javaScript3
事件
1.函数
函数主要用于封装代码块
函数封装的步骤:
1)总结复用代码,用function包装复用代码。
2)发现可变量,抽取为形参。---结合项目观察某些变量值,考量是否更改当前变量就可实现多途径使用。
3)形参尽量不要超过四个。
123
2.作用域
调试工具断点打的其实是:执行环境。--代码运行的时候才会产生执行环境。
执行环境导致作用域存在。所以只有代码(函数)执行的时候才会产生作用域。
一个函数就是一个 独立作用域,和this毫无关系。
this只有在函数或全局代码执行的时候才存在。
AO:activation Object 简称AO ---活动性对象,函数执行的时候才会产生,一但函数执行结束就【被销毁】
一个作用域中的变量,如果没有var,而直接赋值(只有着一种情况!),则层层作用域寻找,直到window,如果window也没有,则var一个
一个作用域中的变量,如果没有var,直接参与运算,则层层作用域寻找,但是如果直到window都没有找到的话,就报错:xxx is not defined
关于函数嵌套:
// 函数嵌套
{
// 通过调试工具可以看到,每一个函数执行的时候在scope(作用域)面板中生成了如下结构:
/*
{
num1: 10, //函数内部定义的变量
this: window // 作用域终点,JS先编译,再执行,
编译后已经知道了当前这个作用域执行后的终点
}
我们将上面的对象称为:Activation Object 简称:AO —— 活动性对象,
仅仅在函数调用的时候产生,一旦函数执行结束就被【销毁】
既然是对象,就有办法保存下来
*/
function a(){
let num1=10;
function b(){
let num2 = 20
num1++;
console.log(num1);
console.log(num2);
function c(){
let num3 = 20;
console.log(num2);
}
c();
}
b();
}
a();
}
箭头函数中的【怪异现象】
/*
通过调试工具可以知道,函数执行的时候发生了:
1. 首先收集全部的变量声明
2. 为变量赋值
*/
function a(){
let num = 10;
const obj = {
name:'张三',
age:20
}
console.log(num)
console.log(obj.age)
}
// 运行a可以看到效果(使用调试工具调试)
// a();
/*
函数调用中的【怪异现象】:
箭头函数在运行过程中,this的指向遵循于当前定义的作用域this终点;
当箭头函数this终点指向window的时候,scope面板显示为undefined
*/
const obj = {
name:'张三',
fn:function(){
let num = 1;
console.log(this.name)
let fn2 = ()=>{
console.log(this)
}
fn2()
},
fn1:()=>{
console.log(this.name)
}
}
obj.fn();
// obj.fn1();
3.关于闭包
// 跨作用于访问
// 什么是闭包?
/*
闭包第一种形态:
常规的跨作用域访问,执行结束后,所有AO都被销毁
*/
function a(){
let num1 = 10;
function b(){
num1++;
console.log(num1)
}
b()
}
a()
function c(){
let num=10;
return function d(){
num++;
console.log(num)
// console.log(this) // script面板中展示的是closureFn,需要考证
}
}
// 此处执行c函数,返回了d函数的代码片段给closure
let closureFn = c();
// 调用closure——使用调试工具观察scope面板
closureFn()
// closureFn()
// closureFn()
// closureFn()
closu = Object
function num(){
return 1
}
闭包使用
/*
狭义的建立闭包:
1. 子级作用域访问了父级作用域变量
2. 子级作用域不随父级作用域销毁(实际父级的AO未被销毁)
执行环境栈顺序:先入后出
*/
// 闭包的方式
function userManager(){
var userList = [];
var admin = '张三';
var password = '12345';
return { //将函数对象抛出去了,外函数外面执行。又访问了外层变量。这就形成了闭包。
//当执行栈中执行环境依次销毁的时候,却找不到里层执行环境,而外层执行环境一直等待里面的销毁。
//这就导致外层作用域下的变量被保存下来。
auth(pwd){
if(pwd === password){
console.log('欢迎回来')
}
},
createUser(userName){
userList.push(userName);
}
}
}
const tools = userManager()
tools.auth('12345');
tools.createUser('李四')
tools.createUser('李四1')
tools.createUser('李四2')
tools.createUser('李四3')
4.面向对象编程
1)函数改写成对象的原则
1.尽量避免函数嵌套
2.如果有函数嵌套,提取后,一定要观察this的指向,及时修改this指向问题。
2)对象的优缺点
1.代码复用,灵活性强
2.数据不安全,任何人都可以访问对象内部方法。
5.组合寄生
// 组合寄生
// 原型链继承和寄生继承
function MyMenu(list){
// call方法——改变this指向
Menu.call(this,list)
}
// 原型链继承
// 1.声明一个空function,用这个function的prototype去接收父类的prototype
(function(){
function A(){};
A.prototype = Menu.prototype;
// 2. prototype中有constrcutor属性,指向了Menu,需要改成MyMenu
A.prototype.constructor = MyMenu;
// 3. 使用MyMenu去接收A的prototype
MyMenu.prototype = A.prototype;
})();
MyMenu.prototype.doClick = function(){
}
const myMenu = new MyMenu('.list1');
6.数组内置方 法
1)concat ---连接两个或更多数组,并返回新数组,不改变原数组
let arr1=[1,2,3]
let arr2=[4,5,6]
arr1.concat(7,8) //[1,2,3,7,8] //直接添加数据
arr1.concat(arr2) //[1,2,3,4,5,6] //连接数组,concat参数可传入多个数组
2)reverse ---反转数组 ,改变原数组
3)push ---向数组末尾添加一个或多个元素,改变原数组
4)unshift ---向数组头部插入一个或多个元素,改变原数组
5)pop ---删除数组最后一个元素,并返回删除的元素,改变原数组
6)shift ---删除数组第一个元素,并返回删除的元素,改变原数组
7)splice() ---增删改查都可以,第一个参数为开始的索引,第二个参数为删除的个数(可选),第三个参数为添加的元素(可选),第三个参数可以有多个。如果只给一个参数,默认删除给定索引以后全部的值。改变原数组
8)sort() --数组在原数组上进行排序,不生成副本。如果不给参数,默认按照数字升序---字母升序进行排列。一个数组中同时存在数字和字母,先数字。如果一个数组同时存在数字,字符串,数组,对象:顺序为数字-数组-对象-字符串)
//数字
***如果不给参数,sort会在每一项上调用String()转型函数,然后比较字符串来决定顺序。***
arr.sort(function(a,b){return b-a}) //数字降序排列 不给值,再反reverse转数组也可以实现
//字母
arr.sort() //字母升序a-z
9)forEach() ---数组每个元素都执行一次回调函数
注意:遍历基本数据类型值的时候,得用索引配合才能改变原数组值。
// 数组改值
let arr = [1,3,5,7,9];
arr.forEach(function(item){
item = 30;
})
console.log(arr); //输出 (5) [1, 3, 5, 7, 9]
// 数组改值
let arr = [1,3,5,7,9];
arr.forEach(function(item,index,arr){
arr[index] = 30;
})
console.log(arr); //输出 (5) [30, 30, 30, 30, 30]
10)map() ---方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。不会检测空数组,不会改变原数组。
11)filter()---创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。参数为函数,不会检测空数组,不会改变原数组。
let ages=[18,19,14,20]
ages.filter(function(age){return age>=18}) //检测数组中大于等于18的
12)every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供) --不会检测空数组,不会改变原数组。
- 如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。
- 如果所有元素都满足条件,则返回 true。
let ages=[18,19,14,20]
ages.every(function(age){return age>=18}) //false
13)some() 方法用于检测数组中的元素是否满足指定条件(函数提供)。只要有一个满足条件就返回true,剩下的不再检测。全部不满足就返回false。--不会检测空数组,不会改变原数组。
let ages=[18,19,14,20]
ages.some(function(age){return age>=18}) //true
14)join() ---将数组拼接为字符串,省略参数时,默认为逗号隔开,不会改变原数组
15)indexOf() ---查找数组元素,和查找字符串一样,第一个参数要查找的元素,第二个为开始索引,找到返回索引,找不到返回-1
16)includes() ---查找是否包含指定元素,返回true或false ,也可以用于字符串。
let arr=[1,"aa",2]
arr.includes("aa") //true
17)flat() 多维数组转一维数组,参数为深度,默认1;
var arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
18)findIndex() 方法返回传入一个测试条件(函数)符合条件的数组第一个元素位置。当有元素满足,后面的不再检测。全不满足返回-1;---和indexOf差不多。 不会改变原始数组。
19)find() 返回传入一个测试条件(函数)符合条件的第一个元素值。全不满足返回undefined。
20)slice(start,end) ---提取一部分并生成新数组,两个参数,开始索引,结束索引(可选)。 只给一个参数,从开始截取到最后。 也可以用于字符串。
如果是负数,则该参数规定的是从字符串的尾部开始算起的位置。也就是说,-1 指字符串的最后一个字符,-2 指倒数第二个字符,以此类推。
例:一维数组按照固定长度拆分二维数组
split_array=(arr,len)=>{
let newArr = [];
for(let i=0;i<arr.length;i+=len){
newArr.push(arr.slice(i,i+len));
}
return newArr;
}
let data = [1,2,3,4,5,6,7];
split_array(data, 3); //[[1,2,3],[4,5,6],[7]]
方式二:
function group(arr, len) {
let index = 0;
let newArray = [];
while(index < arr.length) {
newArray.push(arr.slice(index, index += len));
}
return newArray;
}
21)keys() ---遍历数组并拿到所有的索引生成一个新数组返回出来。用于对象的时候拿到所有的键名生成新数组返回出来。
let arr=[1,2,3,4]
console.log(Object.keys(arr)) // [0,1,2,3]
let obj={name:"张三",age:20}
console.log(Object.keys(obj)) //["name","age"]
https://www.runoob.com/w3cnote/es6-array.html ES6 数组
22)xxx.at(索引) --es2022新增
返回指定索引值
7.字符串内置方法
1)charAt() ---返回指定索引处的字符。如:str.charAt(1)
2)charCodeAt() --- 返回指定索引的字符的Unicode编码。
Unicode编码:Unicode(又称统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
3)concat() ---连接两个或多个字符串,返回新的字符串。和数组使用方法一样。
4)includes() ---查找字符串中是否包含指定的子字符,返回true或false
5)IndexOf() ---查找 某个子字符在字符串中的位置,有返回索引,没有返回-1
6)replace() ---查找并替换符合的字符。第一个参数为正则匹配表达式,第二个参数为替换的字符。
let str="asdfba";
str.replace(/a/g,0) //"0sdfb0"
7)slice() ---拿到开始和结束的索引字符片段,并返回一个新的字符串。和数组用法一样。两个参数,开始和结束索引。
8)split() ---按照指定符分割成数组。
9)substr() --- 截取字符串,两参数,开始索引,截取个数(可选),如果省略第二个参数,默认截取到结尾。
10)substring() ---截取字符串,两参数,开始索引(包括),结束索引(不包括)。
11)toLowerCase() ---将全部字符转换成小写
12)toUpperCase() ---将全部字符转换成大写
13)trim() ---去除字符串两边的空白。jquery方法
$.trim(str)
14) replaceAll() ---替换所有匹配字符
15) match() -- 可在字符串内检索指定值,或找到一个或多个正则表达式的匹配。
16)xxx.at(索引) --es2022新增
17)startsWith() 方法 -- startsWith() 方法用于检测字符串是否以指定的前缀开始。
18)endWith() 方法 --endsWith() 方法用来判断当前字符串是否是以指定的子字符串结尾的(区分大小写)。
8.对象内置方法
1)toLocalString() ---转换时间为字符串可用
例:new Date(time).toLocalString() //将传入的时间转换为YY/MM/DD PM hh:mm:ss的格式
2)Object assign() --浅拷贝
3)Object.entries()
返回索引/值对应的迭代器
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
const obj = { a: 5, b: 7, c: 9 };
for (const [key, value] of Object.entries(obj)) {
console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
}
9.uni限制input只能输入数字
<input type="number" v-model="sum" @input="click" />
export default {
data() {
return {
sum: 0,
}
},
methods: {
click(e){
const v = e.detail.value
this.sum = '1'
const zero = /^(0{2,})|[^0-9]/g
let final = 0
if (!v) {
final = 0
} else {
final = v.toString().replace(zero, (v) => {
return 0
})
if (final.split('')[0] * 1 === 0) {
final = final.slice(1) - 0 || 0
}
}
this.$nextTick(() => {
this.sum = final.toString() || '0'
})
},
}
}
10.处理时间
var date = new Date();
date .getYear(); //获取当前年份(2位)
date .getFullYear(); //获取完整的年份(4位)
date .getMonth(); //获取当前月份(0-11,0代表1月)
date .getDate(); //获取当前日(1-31)
date .getDay(); //获取当前星期X(0-6,0代表星期天)
date .getTime(); //获取当前时间(从1970.1.1开始的毫秒数)
date .getHours(); //获取当前小时数(0-23)
date .getMinutes(); //获取当前分钟数(0-59)
date .getSeconds(); //获取当前秒数(0-59)
date .getMilliseconds(); //获取当前毫秒数(0-999)
date .toLocaleDateString(); //获取当前日期
var mytime=date .toLocaleTimeString(); //获取当前时间
date .toLocaleString( ); //获取日期与时间
//时间戳转日期
new Date(时间戳).toLocaleDateString()
//计算近多少(7)天
new Date(start.getTime() - 3600 * 1000 * 24 * 7).toLocaleDateString(),
11. Array.from()
1)将类数组转换为真正的数组
let arrayLike = {
0: 'tom',
1: '65',
2: '男',
3: ['jane','john','Mary'],
'length': 4
}
let arr = Array.from(arrayLike)
console.log(arr) // ['tom','65','男',['jane','john','Mary']]
要将一个类数组对象转换为一个真正的数组,必须具备以下条件:
1、该类数组对象必须具有length属性,用于指定数组的长度。如果没有length属性,那么转换后的数组是一个空数组。
2、该类数组对象的属性名必须为数值型或字符串型的数字
ps: 该类数组对象的属性名可以加引号,也可以不加引号
2)将Set结构的数据转换为真正的数组
let arr = [12,45,97,9797,564,134,45642]
let set = new Set(arr)
console.log(Array.from(set)) // [ 12, 45, 97, 9797, 564, 134, 45642 ]
Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。如下:
let arr = [12,45,97,9797,564,134,45642]
let set = new Set(arr)
console.log(Array.from(set, item => item + 1)) // [ 13, 46, 98, 9798, 565, 135, 45643 ]
3)将字符串转换为数组:
let str = 'hello world!';
console.log(Array.from(str)) // ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d", "!"]
4)Array.from
第一个参数可以是任何可迭代结构,或者有一个length属性和可索引元素的结构。
console.log(Array.from([12,45,47,56,213,4654,154])) //浅拷贝
12.可选链运算符
可选链 ?. 语法有三种形式:
obj?.prop —— 如果 obj 存在则返回 obj.prop,否则返回 undefined。可以连用。
obj?.prop1?.prop2
obj?.[prop] —— 如果 obj 存在则返回 obj[prop],否则返回 undefined。
obj.method?.() —— 如果 obj.method 存在则调用 obj.method(),否则返回 undefined。
13.字符串转换数字=+
a=+b //b只能为字符串数字才有效
14.对象动态添加key值
例:一个数组对象中的某一个值当key 某一个当值
this.$store.state.course.forEach((item)=>{
Object.assign(this.attrdate,{[item.attrId]:item.attrName})
})
15.正则对象 new RegExp
/\//g
replaceAll("/")
new Reg("/", ''g
//判断跳转来源是否缓存页面
beforeRouteEnter(to, from, next) {
const caches = [
'/order/business/detail',
'/patient/patientTube/detail/roominfo',
'/patient/patientTube/detail/recordInfo',
'/business/order/detail',
'/patient/mine/detail/roominfo',
'/patient/mine/detail/recordInfo',
]
const cache = caches.find(item => {
return new RegExp(item).test(from.path) //查询满足条件的值
})
if (cache) {
next()
} else {
next(vm => {
vm.init()
})
}
},
16.选中与否判断
当点击时,传入的index和当前的请求参数index相同时候表示取消,否则选中
selectDate(index) {
const type = this.queryType === index ? null : index
this.queryType = type
this.fetchDiagList({ type })
//计算近期时间,赋值时间选择器
if (type == null) {
this.date = []
return
}
//顺便匹配时间,根据数组下标或者对象key来匹配,抛弃switch和if...else
const timeArr = [
[this.getNearTime(0), this.getNearTime(0)],
[this.getNearTime(3), this.getNearTime(0)],
[this.getNearTime(7), this.getNearTime(0)],
]
this.date = timeArr[index]
},
17.new Map()与new Array()
Map结构提供了“值—值”的对应,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
const getmap = new Map([['aa',1],['bb',2]]);
getmap.set('aa',2);
console.log(getmap.get('aa')); //2
console.log(getmap.has('aa')); //是否存在aa
const map = Map.from(getmap);//深度拷贝map对象
map.set('aa',1);
console.log(map.get('aa'));//1
console.log(getmap.get('aa'));//2
console.log(getmap.delete('aa'));//删除aa这个元素
map与array转换
const arr = Array.from(getmap);
console.log(arr)//[['bb',2]]
console.log(arr.flat());//['bb',2]
18.将 Object 转化为 Map
new Map() 构造函数接受一个可迭代的 entries 。 借助 Object.entries 方法你可以很容易的将 Object 转换为 Map:
const obj2 = { foo: 'bar', baz: 'abc' };
console.log(Object.entries(obj2)); // [['foo', 'bar'], ['baz', 'abc']]
const map = new Map(Object.entries(obj2));
console.log(map); // Map {'foo' => 'bar', 'baz' => 'abc'}
19.scrollIntoView导致的页面偏移解决
解决方案:放弃使用scrollIntoView 改用scrollTop 来操作滚动条。
el-scrollbar的滚动元素为this.$refs.scrollbar.wrap
//scrollIntoView方式
handleTabClick({ name }) {
const el = this.$refs.tabs.$el.querySelector(`#${name}`)
el && el.scrollIntoView({ behavior: 'smooth' })
this.activeName = name
},
//target目标元素 --锚点跳转
var target = document.getElementById("target");
target.parentNode.scrollTop = target.offsetTop;
offsetTop:元素上外边框距离父元素上内边框的距离(简单来说就是元素相对父元素上边的距离)
//scrollTo方式
const scroll = this.$refs['prescription-item'][index].$el.offsetTop
this.$refs['prescription-content'].scrollTo({
top: scroll,
behavior: 'smooth',
})
20.Infinity
Infinity 属性用于存放表示正无穷大的数值。
21.三目运用
item.medicalType === 'MZ'
? '门诊'
: item.medicalType === 'ZY'
? '住院'
: item.medicalType === 'TJ'
? '体检'
: ''
22.空值合并操作符??符
只有当左侧为null和undefined时,才会返回右侧的数
?? 这个和 || 很像,但是它不会屏蔽掉false和 0 和 ""
null ?? 1 ----1
undefined ?? 1 ----1
false ?? 1 ----false
0 ?? 1 ----0
"" ?? 1 ----""
23.尽量避免条件判断
写 if-else 不外乎两种场景:异常逻辑处理和不同状态处理。异常逻辑处理说明只能一个分支是正常流程,而不同状态处理都所有分支都是正常流程。
原则:
合并条件表达式可以有效地减少if语句数目;
减少嵌套能减少深层次逻辑;
异常条件先退出自然而然主干流程就是正常流程。
针对状态处理型重构方法有两种:
一种是把不同状态的操作封装成函数,简短 if-else 内代码行数;
另一种是利用面向对象多态特性直接干掉了条件判断。
24.Object.defineProperties()
Object.defineProperties() 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。
var obj = {};
Object.defineProperties(obj, {
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
});
25.判断对象内是否包含某个键名
1) xxx in obj
'name' in {name:'jeck'} //true
//缺点:如果属性来自对象的原型,也会返回true
2) Reflect.has(obj,xxx)
Reflect.has({name:'jeck'},'name') // true
//与xxx in obj 类似,缺点同理,Reflect是 ES6 为了操作对象而提供的新 API。所有属性和方法都是内置的。
3)hasOwnProperty()
var obj = {name:'jeck'}
obj.hasOwnProperty('name')
//缺点:不能检索Object.create(null) 创建的对象
4)Object.prototype.hasOwnProperty()
var obj = {name:'jeck'}
Object.prototype.hasOwnProperty.call(obj,'name') //true
//解决了方法3)的缺点 ,直接访问的对象的内置方法,跳过了原型连
5)Object.hasOwn() --es2022新方法(推荐使用)
var obj = {name:'jeck'}
Object.hasOwn(obj,'name') //true


浙公网安备 33010602011771号