JavaScript基础功能总结

JavaScript功能总结


文章目录



前言


一、变量

1.1 声明变量

var variable;
let variable;

1.2 变量赋值

1.2.1 常规赋值

variable = value

1.2.2 数组解构赋值

// 1、常规数组解构
[variable_1, variable_2...] = [value_1, value_2...] 

// 2、含有默认值的数组解构
[variable_1 = defaultValue_1, variable_2...] = [value_1, value_2...] 

1.2.3 对象解构赋值

// 1、常规对象解构
{prop: variable} = {prop: value} 

// 2、含有默认值的对象解构
{prop: variable = defaultValue} = {prop: value} 

1.2.4 字符串解构赋值

[variable_1,variable_2...] = '字符串'

1.3 变量初始化

// 1、初始化 = 声明 + 赋值
var variable = value
let variable = value
const constant = value

// 2、同时初始化多个变量 
var variable_1 = value_1, variable_2 = value_2...        
let variable_1 = value_1, variable_2 = value_2...
const constant_1 = value_1, constant_2 = value_2...



二、输入输出语句

2.1 输入语句

2.1.1 prompt('输入框标题') 浏览器弹出输入框, 返回输入内容

2.1.2 confirm('msg') 显示一段内容以及确认按钮和取消按钮的对话框


2.2 输出语句

2.2.1 alert('msg') 浏览器弹出内容警示框

2.2.2 console.log('msg') 浏览器控制台输出内容

2.2.3 document.write('msg') 写入的信息在HTML页面输出,输出的是msg.toString的值




三、流程控制语句

3.1 条件语句

3.1.1 if-else

if (条件表达式1) {
 	// 条件1成立执行的代码语句
}else if(条件表达式2) {
	// 条件2成立执行的代码语句
}...
...
}else {
	// 条件成立执行的代码语句
}

3.1.2 switch

switch(表达式){
	 case value1:
		 // 表达式 等于 value1 时要执行的代码
	 	 break;
	 case value2:
	 case value3:
	 	 // 表达式 等于 value2、value3 时要执行的代码
	 	 break;
	 default:
	 	 // 表达式 不等于任何一个 value 时要执行的代码
}

3.2 循环语句

3.2.1 for

for(初始化控制变量; 判断条件表达式; 操作控制变量表达式) {
	//重复执行下列代码
	...
}

3.2.2 while

while(条件表达式) {
	...
	// 必须要有修改变量的语句
}

3.2.3 do-while

do {
	...
	// 必须要有修改变量的语句
} while (条件表达式)

3.2.4 break

// 1、常规终止循环
let num3 = 0;
outermost:
for(let i =0;i<10 ; i++){
    for(let j = 0;j<10;j++){
        if(i==5 && j==5){
            break;
        }
        num3++;
    }
}
alert(num3); // 95


// 2、终止标签循环
let num2 = 0;
outermost:
for(let i =0;i<10 ; i++){
    for(let j = 0;j<10;j++){
        if(i==5 && j==5){
            break outermost; //	终止outermost指向的循环
        }
        num2++;
    }
}
alert(num2); // 55

3.2.5 continue

// 1、常规终止循环
let num = 0;
for(let i = 0;i<10;i++){
    for(let j = 0;j<10;j++){
        for(let k = 0;k<10;k++){
            if(j==5 && k==5){
                continue;
            }
            num++;
        }
    }
}
alert(num); // 990


// 2、终止标签循环
let num3 = 0;
outermost:
for(let i =0;i<10 ; i++){
    for(let j = 0;j<10;j++){
        if(i==5 && j==5){
            continue outermost; //终止outermost指向的循环
        }
        num3++;
    }
}
alert(num3); //95

3.2.6 for of

for(const key of 可迭代对象){
	执行语句;
}

3.3 修改作用域语句

3.3.1 with

with(obj){
	// 把对象obj当做 with 要执行的代码体的作用域链的最顶端(最直接的最近的 AO)。
	// 每个变量首先会被认为是一个局部变量,如果没有找到该局部变量,则默认是对象的属性
}

var obj = {
    name: 'obj'
}
var name = 'window';
function test() {
    var age = 123;
    var name = 'scope';
    with(obj) {
        console.log(name);  // obj
        console.log(age);   // 123
    }
}
test();



四、Number

4.1 声明数字

var num = ...;
var num = new Number(...);

4.2 数字方法

4.2.1 数字的获取方法

1、num.toFixed(count) 返回包含小数点位数为count的数值字符串
2、num.toExponential(count) 返回以科学记数法表示,小数点位数为count的数值字符串
3、num.toPrecision(count) count小于本身位数则用toExponential,大于本身位数用 toFixed
let number = 10;
console.log(number.toFixed(2));         // 10.00
console.log(number.toFixed(1));         // 10.0
console.log(number.toExponential(1));   // 1.0e+1
console.log(number.toExponential(3));   // 1.000e+1
console.log(number.toExponential(4));   // 1.0000e+1
console.log(number.toPrecision(3));     // 10.0
console.log(number.toPrecision(1));     // 1e+1
4、Number.isFinite(num) 判断是否是无限值,不支持类型转换
5、Number.isInteger(num) 判断是否是整数,不支持类型转换
6、Number.isSafeInteger(num) 判断是否是安全整数,不支持类型转换
// 1、如果数值的精度超过53 个二进制位(15个十进制位),第54位及后面的位就会被丢(第16个十进制位及其后面就被丢弃)
Number.isInteger(3.0000000000000002) // true


// 2、如果一个数值的绝对值小于Number.MIN_VALUE(5E-324),即小于 JavaScript 能够分辨的最小值,会被自动转为 0。
Number.isInteger(5E-324) // false
Number.isInteger(5E-325) // true


// 3、JavaScript 能够准确表示的整数范围在-2^53到2^53之间(不含两个端点)
// 实际使用这个函数时,需要注意。验证运算结果是否落在安全整数的范围内,不要只验证运算结果,而要同时验证参与运算的每个值。
console.log(Number.isSafeInteger('a'));                     // false
console.log(Number.isSafeInteger(null))                     // false
console.log(Number.isSafeInteger(NaN))                      // false
console.log(Number.isSafeInteger(Infinity))                 // false
console.log(Number.isSafeInteger(-Infinity))                // false
console.log(Number.isSafeInteger(3))                        // true
console.log(Number.isSafeInteger(1.2))                      // false
console.log(Number.isSafeInteger(9007199254740990))         // true
console.log(Number.isSafeInteger(9007199254740992))         // false
console.log(Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 1)) // false
console.log(Number.isSafeInteger(Number.MIN_SAFE_INTEGER))  // true
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER))  // true
console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1)) // false

4.2.2 数字的转换方法

1、Number(variable)
// (1)对所有数据类型都有效 
// (2)对于string只有纯数字才能转为数字,其他一律是NaN
2、parseInt(variable [, 进制数])
// 变量只有string、number有效,其他一律返回NaN
// 转换整数数值型 

// 1、从index=0开始遍历如果遇到非数字字符则直接转型遍历到的数字字符串并返回
var demo =123abc”;
var num = parseInt(demo);
console.log(typeof(num) +:+ num);	// 答案显示 number: 123


// 2、如果参数有进制数,则将变量看作是该进制数的表示,函数返回的是用十进制表示变量的数
var demo =10;
var num = parseInt(demo ,16);
console.log(typeof(num) +:+ num);	// 答案显示 number: 16
3、parseFloat(变量)
// 变量只有string、number有效,其他一律返回NaN
// 如果有遍历到小数点则返回浮点数,如果只有整数则返回整数 

// 从index=0开始遍历如果遇到除了第一个点以外的非数字字符则直接转型遍历到的数字字符串并返回
var demo =100abc”;
var num = parseFloat (demo);
console.log(typeof(num) +:+ num);	// 答案显示 number: 100



五、String

5.1 声明字符串

// 1、标准字符串
var str = '...';

// 2、模板字符串
var str = `...${variable_1}...`		

// 3、字符串包装对象
var str = new String(...)

5.2 字符串方法

5.2.1 字符串增加方法

1、str.padStart(num [,str1]) 在str1头部用多个str2补全直至字符串总长度为num并返回结果
2、str.padEnd(num [,str1]) 在str1尾部用str2补全直至字符串总长度为num并返回结果
// 1、常规添加
console.log('x'.padStart(5,'ab'));     // ababx
console.log('x'.padEnd(5,'ab'));       // xabab


// 2、若不能以整数个str2补全则根据长度去截取补全
console.log('x'.padStart(5,'hello'));  // hellx


// 3、若不添加str2参数,则默认是空格
console.log('x'.padStart(5));          //    x
3、str.concat(str1,str2...) 连接字符串并返回
4、str.repeat(num) 将原字符串重复n次组合起来并返回
let str = 'hello world';
console.log(str.repeat(3)); // hello worldhello worldhello world
console.log(str);			// hello world

5.2.2 字符串删除方法

1、str.trim() 删除字符串两端的空字符
2、str.trimStart() 消除字符串头部的空格
3、str.trimEnd() 消除尾部的空格
const s = '  abc  ';
s.trim() 		// "abc"
s.trimStart()   // "abc  "
s.trimEnd() 	// "  abc"

5.2.3 字符串修改方法

1、str.replace(oldStr/pattern,newStr) 替换字符串,只替换第一个匹配的oldStr
2、str.replaceAll(newStr, oldStr) 将str中的oldStr替换为newStr并返回
// 1、选择字符串模式
var str = 'aa';
console.log(str.replace('a', 'b'));     // ba,默认只替换一次


// 2、选择正则表达式模式
var str_2 = 'aabb';
console.log(str_2.replace(/a/, 'b'));   // babb,没有全局匹配,所以只匹配一个结果
console.log(str_2.replace(/a/g, 'b'));  // bbbb,全局匹配,所以匹配项全部替换
console.log(str_2.replaceAll('a', 'b'));// bbbb,replaceAll实现了全局匹配的功能


// 3、replace的核心用法——排序+crud
console.log(str_2.replace(/(\w)\1(\w)\2/, ($,$1,$2) => $2+$2+$1+$1+'b'));   
// bbaab, 替换函数的第一个参数是整个正则表达式匹配到的结果,第二个参数是第一个子表达式的匹配项,以此类推,返回的结果是最终的字符串

5.2.4 字符串获取方法

1、str.length() 获取长度
2、str.charAt(index) 获取指定索引对应的字符
3、str.substr(start,length) 获取字符串指定的区域部分
4、str.substring(start, end) 获取字符串指定的区域部分
5、str.slice(start,end) 获取字符串指定的区域部分
截取方法备注
substr第二个参数是截取字符数,返回截取到的字符串部分
当参数为负时,第一个负参数当成是字符串长度加上该负数,第二个负参数默认为0
substring返回截取索引是[start,end)的内容
当参数为负时,将所有的负参数转换为0,如果start>end,则将end和start交换
slice返回截取索引是[start,end)的内容
当参数为负时,把所有的负参数当成是字符串长度加上该负数
let str = "hello world";

//省略第二个参数默认到字符串末尾
console.log(str.substr(3));        //lo world
console.log(str.substring(3));     //lo world
console.log(str.slice(3));         //lo world
console.log(str.substr(3,7));      //lo worl
console.log(str.substring(3,7));   //lo w
console.log(str.slice(3,7));       //lo w

//当参数是负值时
//slice把所有的负参数当成是字符串长度加上该负数
//substr第一个负参数当成是字符串长度加上该负数,第二个负参数默认为0
//substring将所有的负参数转换为0,如果start>last,则将last和start交换

console.log(str.substr(-3));        //rld
console.log(str.substring(-3));     //hello world
console.log(str.slice(-3));         //rld
console.log(str.substr(3,-7));      //
console.log(str.substring(3,-7));   //hel,相当于(0,3)
console.log(str.slice(3,-7));       //l
6、str.match(pattern)获取匹配到的字符串
var str = 'aabb'
console.log(str.match(/(\w)\1(\w)\2/));     // ["aabb", "a", "b", index: 0, input: "aabb"]
console.log(str.match(/(\w)\1(\w)\2/g));    // ['aabb'],全局匹配只返回匹配到的全局字符串
7、String.raw() 返回一个反斜线都被转义的字符串
console.log(String.raw `Hi\\n`);       //Hi\\n
console.log(String.raw `Hi\n${2+3}`);  //Hi\\5
8、String.fromCodePoint(码值1,码值2...) 获取指定码值对应的字符组成的字符串(能识别四字节字符)
9、str.charCodeAt(index) 获取指定索引对应的字符的码点
10、str.codePointAt(index) 获取四字节的码点,如果下标是第二个双字节,则只读该双字节
console.log(String.fromCodePoint(0x20BB7)); //𠮷

let s = '𠮷a'; //𠮷
console.log(s.charAt(0));       //�,乱码
console.log(s.charAt(1));       //�,乱码
console.log(s.charAt(2));       //a
console.log(s.charCodeAt(0));   //55362,第一个双字节的码点的十进制表示
console.log(s.charCodeAt(1));   //57271
console.log(s.charCodeAt(2));   //97
console.log(s.codePointAt(0));  //134071,完整的四字节码点十进制表示
console.log(s.codePointAt(1));  //57271,第二个双字节的码点的十进制表示
console.log(s.codePointAt(2));  //97,第三个双字节是a
11、str.indexof(str1 [,start])获取指定字符对应的首个索引
12、str.lastindexof(str1 [,start]) 获取指定字符对应的最后一个索引
13、str.search(str1 / pattern) 获取匹配字符串的首个索引
var str = 'aabbcc'
console.log(str.indexOf('a'));          // 0
console.log(str.indexOf('a',1));        // 1
console.log(str.lastIndexOf('a'));      // 1
console.log(str.lastIndexOf('a', 0));   // 0
console.log(str.search(/a/));           // 0
console.log(str.search(/a/g));          // 0, 即使全局匹配也不能违背返回第一个匹配结果的功能
14、str.includes(str1 [,index]) 判断在指定下标开始是否含有指定字符串
15、str.startsWith(str1 [,index]) 判断在指定下标开始是否以指定字符串开头
16、str.endsWith(str1 [,num]) 判断在前num个字符是否以指定字符串结尾
let str = 'hello world';
console.log(str.includes('world',5));   //true
console.log(str.startsWith('hello',0)); //true
console.log(str.endsWith('llo',5));     //true

5.2.5 字符串转换方法

1、str.split('分割符') 分隔字符串成子字符串 ,子字符串放进数组并返回
// 在字符串内根据分割符分割成子字符串 ,子字符串放进数组并返回
// 相邻两个分割符会产生空字符串
let pattern = /[^,]+/;      //[^,]的意思是非','的字符,类似[^xyz]那样
console.log("red,blue,green,yellow".split(pattern));    // ["", ",", ",", ",", ""]
2、str.toString([进制数]) 转为对应进制数的数字字符串
// 1、对数值、布尔值、对象和字符串值有效,null和undefined会报错
var demo = undefined;
var num = demo.toString();
console.log(typeof(num) +:+ num);
// 答案显示报错,undefined 和 null 不能用 toString

// 2、如果有参数则将变量转为对应进制的数值
var demo = 123;
var num = demo.toString(8);
console.log(typeof(num) +:+ num);
// 答案 173,把 123 转成为八进制
3、String(variable) 转为字符串
// 1、对所有类型都有效,隐式转换默认使用String方法转换



六、数组

6.1 创建数组

1、Array()
// 1、一维数组
var arr = new Array() ;				 	   	  // 空数组
var arr = new Array(element_1, element_2...); // 初始化数组
var arr = new Array(length);			   	  // 声明数组长度


// 2、二维数组
var arr = new Array(new Array(), new Array()...) ;				 				//	空数组
var arr = new Array(new Array(element_1,...), new Array(element_1,...)...) 	//	初始化数组
var arr = new Array(new Array(length), new Array(length)...)					//	声明数组长度
2、数组字面量[]
// 1、一维数组
var arr = [] ;				  		   // 空数组
var arr = [element_1, element_2...];   // 初始化数组


// 2、二维数组
var arr = [[],[]...] ;												  // 空数组
var arr = [[element_1, element_2...],[element_1, element_2...]...]    // 初始化数组

6.2 操作数组方法

6.2.1 添加方法

1、arr.push(element_1, element_2...) 尾部添加元素
2、arr.unshirt(element_1, element_2...) 头部添加元素
3、arr.splice(start, 0, element_1, element_2...) 指定区域增加元素
参数备注
start添加位置,使添加的第一个元素的下标是start
0删除元素的个数,这里是增加所以是0

6.2.2 删除方法

1、arr.pop() 尾部删除元素
2、arr.shirt() 头部删除元素
3、arr.splice(start,length) 指定区域删除元素
参数备注
start从索引start开始(包含start)
length删除length个元素

6.2.3 修改方法

1、arr[index] = xxx 修改指定索引值的元素值.如果下标溢出则前面的溢出部分都为undefined,长度为索引值-1
2、arr1.concat(arr2 [, element_1, element_2...]) 拼接两个数组
3、arr.splice(start, length, element_1, element_2...)指定区域修改元素
参数备注
start从索引start开始(包含start)
length删除length个元素,接着添加数据
4、arr.copyWithin(target [,start,end]) 复制并覆盖给定下标范围的数组元素
参数备注
target从下标为target开始覆盖
start / end获取下标为[start, end)的元素
var arr = [1, 2, 3, 4, 5].copyWithin(0, 3, 4);		// [4, 2, 3, 4, 5]
5、arr.fill(element, start, end) 使用给定值在给定下标范围填充一个数组
['a', 'b', 'c'].fill(7, 1, 2)		// ['a', 7, 'c']

// 如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象。
let arr = new Array(3).fill({name: "Mike"});
arr[0].name = "Ben";
arr
// [{name: "Ben"}, {name: "Ben"}, {name: "Ben"}]

6.2.4 获取方法

1、arr[index] 获取指定下标的数组元素,下标溢出读,结果undefined
2、arr.slice(start,end) 获取指定区域的元素
3、arr.find(function(item, index, arr){条件语句;}) 获取第一个符合条件的元素
4、arr.filter((item [,index, arr]) => {return 条件语句}) 筛选满足条件的元素组成的新数组
5、arr.map((item [,index, arr]) => {return ...):返回回调函数的返回值组成的数组
6、arr.reduce((total, item [, currentIndex, arr]) => {return ...}, initValue)
// 1、total: 上一次return的值,如果有initValue则作为total的初始值,没有则数组第一项作为total初始值
// 2、reduce返回的是最终的total值
7、arr.indexof(element [,start]) 获取指定元素的首个索引
8、arr.lastIndexof(element [,start]) 获取指定元素的最后一个索引
9、arr.findIndex(function(item, index, arr){条件语句;}) 获取第一个符合条件的元素的下标
[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2
10、arr.some((item [,index, arr]) => {return 条件语句}) 只要有满足条件的元素就返回true
11、arr.every((item [,index, arr]) =>{return 条件语句}) 当所有元素满足条件才返回true
12、arr.includes('value') 判断数组是否有value


6.2.5 排序方法

1、arr.reverse() 元素逆序排列
2、arr.sort([compareFunction]) 元素排序,本质上是冒泡排序
compareFunction的返回值备注
compareFunction(a, b) 小于等于 0a 和 b 的相对位置不变
compareFunction(a, b) 大于 0a和b要交换位置

6.2.6 转换方法

1、arr.join('分隔符') 用分隔符分隔每个元素并组成字符串返回
2、arr.toString() 返回数组元素和逗号分隔的字符串
console.log([1,2,3].toString());    // 1,2,3
3、Array.of(元素1,元素2...) 将一组值转换为数组
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
4、Array.from(可迭代对象 [,function(item,index,arr){}]) 将可迭代对象进行处理并转成数组
// NodeList对象
let ps = document.querySelectorAll('p');
Array.from(ps).filter(p => {
  return p.textContent.length > 100;
});


// arguments对象
function foo() {
  var args = Array.from(arguments);
}


// 迭代器对象
Array.from(numbers()) // [1, 2]
5、arr.flat(Infinity) 数组扁平化
// flat默认只能扁平一层,如果要转为一维数组,则参数使用Infinity
[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]
6、arr.flatMap(function(item){}) 原数组的元素进行处理再对返回值组成的数组执行数组扁平化
// 相当于 [[[2]], [[4]], [[6]], [[8]]].flat()
[1, 2, 3, 4].flatMap(x => [[x * 2]])
// [[2], [4], [6], [8]] 
改变原数组方法备注
push返回新的长度
unshirt返回新的长度
pop返回删除的元素
shirt返回删除的元素
splice返回的是删除的元素组成的数组
reverse改变原数组,返回逆序排列的数组
sort默认按照元素每一个字符逐位比较unicode值排序的,返回排序后的数组
不改变原数组方法备注
slice区间是 [start,end)、生成并返回提取出的元素组成的新数组
concat拼接两个数组加上额外的数据、生成并返回新数组
indexof可选参数是从索引是start开始查找,返回满足条件的第一个索引,没有则返回-1
lastIndexof可选参数是从索引是start开始逆向查找,返回满足条件的第一个索引,没有则返回-1
some根据条件查找元素,有返回true,没有false.
只要找到符合条件就不再遍历
filter返回筛选符合条件的元素组成的新数组
toString返回数组元素和逗号分隔的字符串
find只要找到就终止遍历,返回符合条件的元素; 如果没有符合条件的成员,则返回undefined
findIndex只要找到就终止遍历,返回符合条件的元素的下标; 如果所有成员都不符合条件,则返回-1
includes返回true | false

6.3 遍历数组元素

6.3.1 for

for (var index = 0; index < array.length; index++) {
   ...
}

6.3.2 forEach(return不会终止遍历)

array.forEach(function(item, index, array) {
	...
})

6.3.3 for of调用遍历器接口

for (let i of array) {
  ...
}



七、函数

7.1 声明函数

7.1.1 常规声明

1、声明普通函数
// 1、function关键字声明方式(首选)	
function funcName(formalParameter_1,formalParameter_2...){}

// 2、匿名函数表达式方式,变量存储的是一个函数 
var funcName = function() {}

// 3、构造函数方式
var funcName = new Function('formalParameter_1''formalParameter_2'..., '{funcBody}')
2、声明立即执行函数
// 1、w3c标准写法
(function (formalParameter_1,formalParameter_2...){})(actulParameter_1,actulParameter_2...)


// 2、写法2
(function(formalParameter_1,formalParameter_2...){}(actulParameter_1,actulParameter_2...))
3、声明高阶函数
// 1、接收函数作为参数
function fn(callback){
	callback&&callback();
}
fn(function(){...)}


// 2、将函数作为返回值输出
function fn(){
 return function() {...}
}
fn();
4、声明箭头函数
// 1、标准语法 const 函数名 = (参数1,参数2...) => {函数体};
const sum = (num1, num2) => { return num1 + num2; }


// 2、函数体只有一句代码,且代码的执行结果就是返回值 const 函数名 = (参数1,参数2...) => 返回值;
const sum = (num1, num2) => num1 + num2;


// 3、形参只有一个 const 函数名 = 参数 => {函数体};
const f = v => v;


// 4、如果返回值是一个对象,一定要给该对象加()
let getTempItem = id => { id: id, name: "Temp" };	// 报错
let getTempItem = id => ({ id: id, name: "Temp" }); // 不报错

7.1.2 参数含有默认值的声明

// 1、常规默认值
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') 		  // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') 	  // Hello


// 2、参数默认值与解构赋值默认值结合使用,参数形式是对象形式
// 优先级:实参 > 默认值 > undefined
function foo({x, y = 5}) {
	console.log(x, y);
}
function m1({x = 0, y = 0} = {}) {
    console.log([x, y]);
}
function m2({x, y} = { x: 0, y: 0 }) {
	console.log([x, y]);
}

// 无形参
foo()   // TypeError: Cannot read property 'x' of undefined
m1() 	// [0, 0]
m2() 	// [0, 0]

// x 和 y 都无值的情况
foo({}) 	// undefined 5
m1({}) 		// [0, 0];
m2({}) 		// [undefined, undefined]

// x 有值,y 无值的情况
foo({x: 1}) 	// 1 5
m1({x: 3}) 		// [3, 0]
m2({x: 3}) 		// [3, undefined]

// x 和 y 都有值的情况
foo({x: 1, y: 2})   // 1 2
m1({x: 3, y: 8}) 	// [3, 8]
m2({x: 3, y: 8}) 	// [3, 8]

7.2 函数使用

7.2.1 函数调用

1、标准调用方法
funcName(actulParameter_1,actulParameter_2...);
2、模板字符串调用方法
funcName`modelString`
函数参数列表备注
数组开头和结尾的插值会变为“”,被插值分开的每一块子字符串分别作为数组的元素
其他每个插值表达式的值
var total = 30;
var msg = passthru`The total is ${total} (${total*1.05} with tax)`;
function passthru(literals){
    var result = '';
    var i = 0;
    while(i<literals.length){
        result += literals[i++];  //literals: (3) ["The total is ", " (", " with tax)"]
        if(i < arguments.length){ //arguments: Arguments(3) [Array(3), 30, 31.5]
            result += arguments[i];
        }        
    }
    return result;
}
console.log(msg);   //The total is 30 (31.5 with tax)

7.2.2 操作arguments

1、arguments.length 表示实参个数
// 1、arguments存储了传递的所有实参。实质是类数组
function test(a) {
	console.log(arguments);
	console.log(arguments.length);
}
sum(11, 2, 3)	// 答案[11, 2, 3],3


// 2、有默认值的参数、rest参数就不再算入length中
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
(function(...args) {}).length // 0


// 3、如果前面设置了默认值的参数不是尾参数,那么就不再计入后面的参数了
(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1
2、arguments映射到形参 相同下标的二者都存在才指向同一个值
function sum(a, b){	
	// arguments[0]存在映射到a,arguments[1]不存在则不映射到b
    a = 2;
    b = 2;
    console.log(arguments[0]);
    console.log(arguments[1]);
    console.log(a);
    console.log(b);
}
sum(1);		// 答案 2 undefined 2 2
3、funcName.length 获取形参个数
function sum(a, b, c, d) {
	console.log(sum.length);
}
sum(11,2,,3)	// 答案 4
4、arguments.callee 获取当前函数的引用
5、funcName.caller 获取调用该函数的函数环境的函数引用
function test() {
    console.log(arguments.callee);     // ƒ test()
    function demo() {
        console.log(arguments.callee); // ƒ demo()
        console.log(demo.caller);      // ƒ test()
    }
    demo();
}
test();


八、对象

8.1 创建对象

8.1.1 使用对象字面量创建

// 1、对象默认继承Object.prototype
var prop_3 = ...;
var obj = {
	prop: value,		  			// ES5 标准写法
 	['prop_2']: value_2,    		// ES6 当属性名含有其他变量拼接成字符串时的简洁写法 
	prop_3,			  				// ES6 当属姓名和外部变量名相同时的简洁写法
	funcName: function(...) {} , 	// ES5 标准写法
	[funcName_2]() {}, 		   		// ES6 当属性名含有其他变量拼接成字符串时的简洁写法
	funcName_3() {},			    // ES6 简洁写法
	...	
} 

8.1.2 使用构造函数创建

function constructorName(prop_1,prop_2...) {
	var privateName = ...;	// 私有属性
	this.prop = value;
	this.funcName = function() {}
}
var obj = new constructorName(actualParameter_1,actualParameter_2...);

8.1.3 使用Object()创建

// 1、对象默认继承Object.prototype
var obj = new Object();

8.1.4 使用Object.create()创建

function constructorName(prop_1,prop_2...) {
	var privateName = ...;	// 私有属性
	this.prop = value;
	this.funcName = function() {}
}
var obj = Object.create(constructorName.prototype);
var obj = Object.create(null);	// 对象默认继承Object.prototype

8.2 操作对象的属性和方法

8.2.1 对象添加方法

1、obj.prop = value 添加属性prop
2、obj.funcName = function() {} 添加方法
3、Object.assign(target, source1, source2....) 对象的合并
// (1)将源对象(source)的所有可枚举属性,浅拷贝到目标对象(target)
// (2)同名属性后面的属性值会覆盖前面的值
var target={name:'guxin',age:18}
var source={state:'signle',age:22}
var result=Object.assign(target,source)
console.log(target) // {name: "guxin", age: 22, state: "signle"}
4、constructorName.prototype.funcName = function() {} 原型对象上添加方法
// 把不变的方法和共有的属性直接定义在 prototype对象上,这样所有对象实例可以共享这些方法
// 1、当只有少数方法时才使用第二种方法
// 2、当有多个对象方法,最好给原型对象采取对象形式赋值。
constructorName.prototype = {
 	// 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
 	constructor: constructorName,
	funcName_1: function() {...},
	funcName_2: function() {...}
}
5、Object.defineProperty(obj, prop, {descriptor}) 添加属性prop(默认不可修改 / 枚举 / 删除)
descriptor备注
value设置属性的值
writable值是否可以重写
enumerable目标属性是否可以被枚举
configurable目标属性是否可以被删除或是否可以再次修改特性
// 1、在使用Object.defineProperty添加的数据属性,writable、enumerable和configurable默认值为false。
// 2、使用对象直接量创建的属性,writable、enumerable和configurable特性默认为true
Object.defineProperty(obj, prop, {
	// 必须以键值对形式赋值
	value:...;
	writable: true | false;
	...
})

8.2.2 对象删除方法

1、delete obj.prop 删除对象属性

8.2.3 对象修改方法

1、obj.prop = value 修改对象属性
2、Object.defineProperty(obj, prop, {descriptor}) 修改对象属性
3、Object.setPrototypeOf(object, prototype) 设置一个对象的原型对象并返回该对象
const o = Object.setPrototypeOf({}, null);
4、constructorName.prototype.funcName = function(){...}重写方法
var num = 123;
Number.prototype.toString = function () {
    return this+'';
}
console.log(num.toString()); // 123

8.2.4 对象获取方法

1、obj.prop 获取对象属性
2、Object.getPrototypeOf(obj) 获取一个对象的原型对象
3、Object.getOwnPropertyDescriptor(obj, 'prop') 获取该属性的描述对象
let obj = { foo: 123 };
Object.getOwnPropertyDescriptor(obj, 'foo')
//  {
//    value: 123,
//    writable: true,
//    enumerable: true,
//    configurable: true
//  }
4、Object.fromEntries(arr) 将一个键值对数组转为对象
Object.fromEntries([
  ['foo', 'bar'],
  ['baz', 42]
])
// { foo: "bar", baz: 42 }


// 主要用途: 将键值对的数据结构还原为对象,因此特别适合将 Map 结构转为对象
const entries = new Map([
  ['foo', 'bar'],
  ['baz', 42]
]);
Object.fromEntries(entries) // { foo: "bar", baz: 42 }

8.2.5 调用方法

1、obj.funcName()
2、obj['funcName']()



九、Math

9.1 内置属性

9.1.1 Math.PI 圆周率


9.2 内置方法

9.2.1 最大小值方法

1、Math.Max(num1,num2...) 最大值
2、Math.min(num1,num2...) 最小值

9.2.2 取整方法

1、Math.ceil(num) 向上取整
2、Math.floor(num) 向下取整
3、Math.trunc(num) 取整 ,支持类型转换
4、Math.round(num) 四舍五入
console.log(Math.trunc("123.456"));	// 123
console.log(Math.trunc(123.456));	// 123
console.log(Math.round(-123.4)); 	// -123

9.2.3 随机数方法

1、Math.random() 0-1的随机数

9.2.4 幂方法

1、Math.sqrt(num) 平方根
2、Math.hypoy(num...) 获取多个数平方根,支持类型转换
3、Math.cbrt(num) 获取立方根 ,支持类型转换
4、Math.pow(base,次方数)
console.log(Math.cbrt("8"));	// 2
console.log(Math.cbrt("-1"));	// -1
console.log(Math.cbrt("1"));	// 1
console.log(Math.cbrt(8));		// 2

console.log(Math.hypot(3,4,"5")); // 7.071067811865475
console.log(Math.hypot(-3));      // 3
console.log(Math.hypot());        // 0

9.2.5 底数方法

14、Math.expm1(num) 返回e^num-1
15、Math.log1p(num) 返回ln(1+num),如果小于0则返回NaN
16、Math.log10(num) 返回lg(num),如果小于0则返回NaN
17、Math.log2(num) 返回log2(num),如果小于0则返回NaN
console.log(Math.hypot(3,4,"5")); //7.071067811865475
console.log(Math.hypot(-3));      //3
console.log(Math.hypot());        //0

console.log(Math.expm1(-1));    //-0.6321205588285577
console.log(Math.expm1(0));     //0
console.log(Math.expm1(1));     //1.718281828459045

console.log(Math.log1p(-1));    //-Infinity
console.log(Math.log1p(1));     //0.6931471805599453
console.log(Math.log1p(0));     //0
console.log(Math.log1p(-2));    //NaN

console.log(Math.log10(-1));    //NaN
console.log(Math.log10(1));     //0
console.log(Math.log10(0));     //-Infinity
console.log(Math.log10(-2));    //NaN

console.log(Math.log2(-1));     //NaN
console.log(Math.log2(1));      //0
console.log(Math.log2(0));      //-Infinity
console.log(Math.log2(-2));     //NaN

9.2.6 正负值方法

1、Math.abs(num)绝对值
2、Math.sign(num) 判断是否是正负0
各种情况返回值
正数1
负数-1
00
-0-0
其他值NaN
console.log(Math.sign(3));     //  1
console.log(Math.sign(-3));    // -1
console.log(Math.sign("-3"));  // -1
console.log(Math.sign(0));     //  0
console.log(Math.sign(-0));    // -0
console.log(Math.sign(NaN));   // NaN
console.log(Math.sign("foo")); // NaN
console.log(Math.sign());      // NaN



十、Date

10.1 创建时间对象

// 1、创建基于当前时间的对象, Thu Jan 28 2021 23:48:46 GMT+0800 (中国标准时间)
var date = new Date(); 


// 2、创建基于指定时间的对象,参数必须是毫秒数,但Date在后台调用了Date.parse或Date.UTC方法转换成毫秒数,所以可以直接传入其他参数
// 参数是字符串,缺写的单词则使用默认值
var date = new Date('year-month-day hour:minute:second');
var date = new Date('month/day/year hour:minute:second');
var date = new Date('year/month/day hour:minute:second');


// 3、参数是数字,月份是从0开始的
var date = new Date(year, month, day, hour, minute, second, microsecond);
var date = new Date(microsecond);  //从1970.1.1 00:00:00为开始时间,输出为(date+毫秒数)转换为标准格式

10.2 修改时间方法

10.2.1 修改日期

1、date.setFullYear(year) 修改对象对应的四位数年
2、date.setMonth(month) 修改对象对应的月份-1
3、date.setDate(date) 修改对象对应的日
4、date.setDay(day) 修改对象对应的周几
5、date.setHours(hour) 修改对象对应的时
6、date.setMinutes(minute) 修改对象对应的分
7、date.setSeconds(second) 修改对象对应的秒

10.2.2 修改总毫秒数

1、date.setTime(毫秒数)


10.3 获取时间方法

10.3.1 获取日期

1、date.getFullYear()返回对象对应的四位数年
2、date.getMonth() 返回对象对应的月份-1
3、date.getDate() 返回对象对应的日
4、date.getDay() 返回对象对应的周几
5、date.getHours() 返回对象对应的时
6、date.getMinutes() 返回对象对应的分
7、date.getSeconds() 返回对象对应的秒

10.3.2 获取总毫秒数

1、返回对象对应的时间的总毫秒数
(1)date.valueOf()
(2)date.getTime()
(3)var totalMicroSecond = +对象

2、返回当前时间的总毫秒数
(1)Date.now()

3、返回表示日期的字符串转换为毫秒数
(1)Date.parse(String)
(2)Date.UTC(year,month [,day,hour,minute,second,microsecond])

10.3.3 获取各种时间格式时间的方法

1、date.toDateString() 返回当前date对象对应的时间的星期几、月、日和年
2、date.toTimeString() 返回当前date对象对应的时间的时、分、秒和时区
3、date.toString() 通常返回带时区的信息的日期和时间,24小时制。
4、date.toLocaleDateString 以特定地区格式返回当前date对象对应的时间的星期几、月、日和年
5、date.toLocaleTimeString()以特定地区格式返回当前date对象对应的时间的时、分、秒和时区
6、date.toLocaleString() 与浏览器运行的本地环境一致的时间和日期,通常包含AM,PM。但不包含时区信息
var date4 = new Date(1999,7,22,17,55,55);
alert(date4);                   	// Sun Aug 22 1999 17:55:55 GMT+0800 (中国标准时间)
console.log(date4.toDateString());  // Sun Aug 22 1999
console.log(date4.toTimeString());  // 17:55:55 GMT+0800 (中国标准时间)
// 这两个方法的时间组合起来就是toString的时间

alert(date4.toLocaleString());  	// 1999/8/22 下午5:55:55(我的惠普格式)
console.log(date4.toLocaleDateString());	// 1999/8/22
console.log(date4.toLocaleTimeString());	// 下午5:55:55
// 这两个方法的时间组合起来就是toLocaleString()的时间

alert(date4.toString());  	    	// Sun Aug 22 1999 17:55:55 GMT+0800 (中国标准时间)
// 两个方法只对用于调试,在许多浏览器的返回格式可能不一样


十一、RegExp

11.1 创建正则表达式

// 1、通过字面量创建
var reg = /expression/flag;


// 2、通过调用 RegExp 对象的构造函数创建
var reg = new RegExp('expression',flag);


// 3、用已定义的正则表单式复制
var reg_2 = RegExp(reg_1);		// 同一个正则表达式
var reg_1 = new RegExp(reg);	// 创建一个新的,但是模式是一样的

// 4、通过调用RegExp对象的构造函数创建,后面的标记可以覆盖前面的标记
var reg = new RegExp(/expression/flag, 'other flags');
new RegExp(/abc/ig, 'i').flags   // "i"  i覆盖ig

11.2 元字符

11.2.1锚字符 用来提示字符所处的位置

1、^ 行首匹配,正则表达式必须在字符串开头
2、$ 行尾匹配,正则表达式必须在字符串结尾
3、?=n 正向预查
4、?!n 正向断言
var str = "abaaaaa";
var reg = /a(?=b)/g;                
var reg_2 = /a(?!b)/g
console.log(str.match(reg));    // ["a"], 判断后面是否跟着b,但不把b筛选出来
console.log(str.match(reg_2));  // ["a", "a", "a", "a", "a"],判断后面是否不等于b,但不把b筛选出来

11.2.2 单字符

1、[] 表示一个字符
2、- 方括号内部的范围符
3、^ 方括号内部取反符
4、| 替换字符
符号备注
[ ]表示有一系列字符可供选择,只要匹配其中一个就可以
-表示有一范围的字符可供选择,只要匹配其中一个就可以
^方括号内部加上 ^ 表示取反,只要包含方括号内的字符,都返回 false。界符写到方括号外面
|x|y,匹配x或y

11.2.3 预定义字符 某些常见模式的简写方式

1、. 匹配单个任意字符
2、\d 匹配单个数字字符,等价于[0-9]
3、\D 匹配单个非数字字符,等价于[^\d]
4、\w 匹配单个的数字、字母、下划线字符.相当于[A-Za-z0-9_]
5、\W 匹配单个的非数字、字母、下划线字符相当于[^\w]
6、\s 匹配任意单个的空白字符,空格,制表符、换行符、换页符等.等价于[\t\r\n\v\f]
7、\S 匹配任意单个非空白字符.等价于[^\s]
8、\b 单词边界(就是空格)
9、\B 非单词边界
var reg = /\bcde/g;
var str = "abc cde fgh";
console.log(str.match(reg));    // cde
10、\number 前面子表达式的引用
var reg = /(a)\1/g;
// 这个括号是一个子表达式的意思,这个括号会记录里面匹配的内容,记录完以后利用\加一个数字可以反向引用出来
// \1代表第一个子表达式,\2代表第二个表达式,以此类推
// 这里的意思是匹配a和后面同样的a

11.2.4 量词符 用来设定某个模式出现的次数

1、表达式? 匹配0个或1个
2、表达式+ 匹配至少1个
3、表达式* 匹配任意个
4、表达式{m} 匹配m个
5、表达式{m,n} 匹配m到n个
6、表达式{m,} 匹配至少m个
7、量词后面加个? 非贪婪匹配,能取小就不取大
 var reg = /a{1,3}?/g;   // 能取1就不取2和3
括号备注
大括号量词符. 里面表示重复次数
中括号字符集合。匹配方括号中的任意字符.
小括号子表达式

11.3 标记

1、i 忽略大小写。
2、g 全局匹配。把匹配到的元素放入数组并返回
3、m 换行匹配。查找到末尾时会继续换行查找,针对换行符
4、u unicode模式。用来处理大于\uFFFF的Unicode字符,正确匹配4个字节的字符
5、y 粘连全局匹配。下一次匹配必须从lastIndex开始
6、s 识别任意字符。修复’.'字符的缺陷,不忽略\n,\r,行分隔符,段分隔符
// 1、y标记
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
console.log(s.match(r1));  // ["aaa", "aa", "a"]
console.log(s.match(r2));  // ["aaa", index: 0, input: "aaa_aa_a", groups: undefined], 从下一个位置(即下标3)开始匹配,匹配不到
// 单独一个y修饰符对match方法只能返回第一个匹配,必须与g修饰符连用才能返回所有匹配	
console.log("a1a2a3".match(/a\d/y)); //["a1"]
console.log("a1a2a3".match(/a\d/yg));//["a1","a2","a3"]

// 2、s标记
/foo.bar/.test('foo\nbar')	// false
/foo.bar/s.test('foo\nbar') // true

11.4 正则表达式方法

1、reg.test(str) 测试正则表达式
2、reg.exec(str) 匹配符合正则表达式的子字符串
exec类数组备注
result下标为0,匹配到的子字符串,如果有子匹配项则排在匹配项后面,分组下标则递增
index匹配项在字符串中的下标。若有下一个匹配项,lastIndex是下一次调用方法的起始下标
input要查找的字符串
方法备注
test开发常用,验证用户输入。true | false
exec若能匹配则返回一个类数组,否则返回null,返回null后如果还调用exec则重新开始匹配
let text = "mon and dad and baby";
let partern = /mon( and dad( and baby)?)?/ig;
let array = pattern.exec(text);
console.log(array.index); //起始位置为0
console.log(array.input); //要查找的字符串就是text
console.log(array[0]);    //第一个元素是匹配整个模式的字符串
console.log(array[1]);    //第一个捕获组匹配的子字符串
console.log(array[2]);    //第二个捕获组匹配的子字符串
// 1、有g标记:每次调用exec()都会返回字符串的下一个匹配项,lastIndex每次都会变化
let text = "cat, bat, sat, fat";
let partern = /.at/ig;
let array = pattern.exec(text);
console.log(array.index);       // 0
console.log(array[0]);          // cat
console.log(partern.lastIndex); // 3

array = partern.exec(text);
console.log(array.index);       // 5
console.log(array[0]);          // bat
console.log(pattern.lastIndex); // 8 


// 2、没有g标记,每次调用exec()永远只会返回第一个匹配项
let text = "cat, bat, sat, fat";
let partern = /.at/;
let array = pattern.exec(text);
console.log(array.index);       // 0
console.log(array[0]);          // cat
console.log(partern.lastIndex); // 0,因为永远只返回第一个匹配项,所以上一次匹配的结束位置永远是0

array = pattern.exec(text);
console.log(array.index);       // 0
console.log(array[0]);          // cat
console.log(pattern.lastIndex); // 0 



十二、数据结构的扩展

12.1 Set

12.1.1 概述

1、类似于数组,但键和值相同
2、成员的值唯一
3、Set集合使用size属性表示元素个数
// 1、判断是否相等的算法是类似于精确相等运算符(===)
// 主要的区别是向 Set 加入值时认为NaN等于自身,而精确相等运算符认为NaN不等于自身。
const s = new Set([2, 3, 5, 4, 5, 2, 2, NaN, NaN]);
console.log(s); // 2 3 5 4 NaN

// 2、对象的地址不同,所以两个对象不同
let set = new Set();
set.add({});
set.size 	// 1
set.add({});
set.size 	// 2

在这里插入图片描述

12.1.2 声明set结构

// 1、使用Set构造函数(空参数)
const s = new Set();


// 2、使用具有iterator接口的其他数据结构作为参数的构造函数
// 原理: 调用了iterator接口遍历
const set = new Set([1, 2, 3, 4, 4]);

12.1.3 遍历set结构

let set = new Set(['red', 'green', 'blue']);

// 1、Set.prototype.keys():返回键名的遍历器
for (let item of set.keys()) {
  console.log(item);  // red green blue
}


// 2、Set.prototype.values():返回键值的遍历器
for (let item of set.values()) {
  console.log(item); // red green blue
}


// 3、Set.prototype.entries():返回键值对的遍历器
for (let item of set.entries()) {
  console.log(item); // ["red", "red"] ["green", "green"] ["blue", "blue"]
} 


// 4、Set.prototype.forEach():使用回调函数遍历每个成员
let set = new Set([1, 4, 9]);
set.forEach((value, key) => console.log(key + ' : ' + value))
// 1 : 1    4 : 4    9 : 9


// 5、for of遍历
var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (var e of engines) {
  console.log(e);	// Gecko Trident Webkit
}	

12.1.4 Set方法

1、增加方法
(1)s.add(value) 添加value

2、 删除方法
(1)s.delete(value) 删除value
(2)s.clear() 删除所有值

3、查找方法
(1)s.has(value) 判断是否有某个值


12.2 WeakSet

12.2.1 概述

1、结构与 Set 类似、元素唯一
2、WeakSet 的成员只能是对象,而不能是其他类型的值
3、受到垃圾回收机制的影响,WeakSet 不可遍历
1、WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用
2、也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中
3、由于上面这个特点,WeakSet的成员是不适合引用的,因为它会随时消失。
4、由于WeakSet内部有多少个成员,取决于垃圾回收机制有没有运行,因为垃圾回收机制何时运行是不可预测,所以运行前后很可能成员个数是不一样的,

12.2.2 声明WeakSet集合

// 1、使用WeakSet构造函数(空参数)
const ws = new WeakSet();

// 2、使用任何具有 Iterable 接口的对象的构造函数, 原理: 调用了iterator接口遍历
const a = [[1, 2], [3, 4]];
const ws = new WeakSet(a);  // WeakSet {[1, 2], [3, 4]}

12.2.3 WeakSet方法

1、增加方法
(1)ws.add(value) 向 WeakSet 实例添加一个新成员
2、删除方法
(1)ws.delete(value)清除 WeakSet 实例的指定成员。
3、查找方法
(1)ws.has(value) 返回一个布尔值,表示某个值是否在 WeakSet 实例之中


12.3 Map

12.3.1 概述

1、类似于对象, 提供了“值—值”的对应

在这里插入图片描述

2、键的范围不限于字符串,所有类型的值都可以当作键
3、Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键
4、Map集合使用size属性表示元素个数

12.3.2 声明Map结构

// 1、使用Map构造函数(空参数)
const map = new Map();


// 2、使用任何具有 Iterable 接口的对象的构造函数
// 原理: 调用了iterator接口遍历
const map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);

12.3.3 遍历

// 1、Map.prototype.keys():返回键名的遍历器。
const map = new Map([
  ['F', 'no'],
  ['T',  'yes'],
]);
for (let key of map.keys()) {
  console.log(key);
}
// "F"  "T"



// 2、Map.prototype.values():返回键值的遍历器
for (let value of map.values()) {
  console.log(value);
}
// "no"  "yes"



// 3、Map.prototype.entries():返回所有成员的遍历器
for (let [key, value] of map.entries()) {
  console.log(key, value);
}
// "F" "no"   "T" "yes"



// 4、Map.prototype.forEach():遍历 Map 的所有成员
map.forEach(function(value, key, map) {
  console.log(key, value);
});
// "F" "no"    "T" "yes"

12.3.4 Map方法

1、增加方法
(1)m.set(key, value) 设置键名key对应的键值为value
2、删除方法
(1)m.delete(key) 删除key键
(2)m.clear() 删除所有键值
3、获取方法
(1)m.get(key) 获取key对应的值
(2)m.has(key) 判断key键是否在当前map对象中


12.4 WeakMap

12.4.1 概述

(1)只接受对象作为键名
(2)WeakMap的键名所指向的对象,不计入垃圾回收机制

12.4.2 声明WeakMap集合

// 1、使用WeakMap构造函数(空参数)
const wm = new WeakMap();

// 2、使用任何具有 Iterable 接口的对象的构造函数
// 原理: 调用了iterator接口遍历
const k1 = [1, 2, 3];
const k2 = [4, 5, 6];
const wm2 = new WeakMap([[k1, 'foo'], [k2, 'bar']]);

12.4.3 WeakMap方法

1、增加方法
(1)wm.set(key, value) 设置键名key对应的键值为value
2、删除方法
(1)wm.delete(key) 删除key键
3、获取方法
(1)wm.get(key) 获取key对应的值
(2)wm.has(key) 判断key键是否在当前map对象中


十三、BOM

13.1 Window

13.1.1 定时器

1、setTimeout(callback [,time]) 设置倒计时定时器
2、setInterval(callback [,time]) 设置周期定时器
3、clearTimeout(timer) 清除倒计时定时器
4、clearInterval(timer) 清除周期定时器
// 1、setTimeout返回的唯一标识和 setInterval返回的唯一标识是不会重叠的,值是数字,他们两个是依次的
time = 2000;
var timer = setTimeout(()=> {
}, time);
var timer_2 = setInterval(() => {
}, time);
console.log(timer, timer_2);    // 1  2
定时器种类备注
setTimeout时间省略默认是0
setInterval时间省略默认是0

13.1.2 修改滚动条的位置

1、scroll(x,y) / scrollTo(x,y) 滚动条坐标为(x,y)
2、scrollBy(x,y)向右滚动x距离,向下滚动y距离
scroll(10,1000)         // 滚动条坐标(10,1000)
scroll(10,1000)         // 滚动条坐标(10,1000)
scrollBy(10,1000)       // 滚动条向右移动10px, 向下移动1000px
scrollBy(-10, -1000)    // 滚动条向左移动10px, 向上移动1000px


13.2 location

13.2.1 location修改方法

1、location.replace('url') 加载新的文档替换当前的文档
2、location.href = 'url' 设置当前完整的url

13.2.2 location获取方法

1、location.href 获取当前完整的url
2、location.protocol 返回当前url的协议
3、location.host 返回当前url的主机名和端口
4、location.hostname返回当前url的主机名
5、location.port返回当前URL服务器使用的端口号,默认隐藏不可见
6、location.pathname返回当前URL路径
7、location.search 返回当前URL的参数
8、location.hash 返回当前URL的锚
9、location.reload([true]) 重新加载当前文档 / 有true则不经过浏览器缓存直接从服务器获取数据重载
10、location.assign('url') 在当前页面跳转到指定url
方法备注
location.reload()如果有浏览器缓存则直接使用缓存数据
location.reload(true)不经过浏览器缓存直接从服务器获取数据,解决了因为缓存原因而更新不了数据的问题
location.assign(‘url’)和href一样
location.replace(‘url’)不会在 History 对象中生成一个新的记录,即不能后退到上一个网页


13.3 navigator

13.3.1 使用

// 判断使用什么设备
if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
	window.location.href = ""; //手机
} else {
	window.location.href = ""; //电脑
}

13.4 history

13.4.1 history的获取方法

1、history.length 获取当前窗口历史记录的条数
2、history.back() 页面跳转到上一条历史记录
3、history.forward() 页面跳转到下一条历史记录
4、history.go(number) 页面前进后退到指定条数历史记录
number的值备注
0刷新当前页面
正整数页面前进number条记录
负整数页面后退number条记录



十四、DOM

13.1 添加节点

13.1.1 插入节点

1、node.parentNode.appendChild(sonNode) sonNode插入到parentNode的子节点的末尾
2、node.parentNode.insertBefore(sonNode,broNode) sonNode插入到parentNode子元素broNode前面
方法备注
appendChild如果子节点已经在页面存在了,就把原来的子节点删除,重新插入到指定处

13.1.2 创造节点

1、document.createElement('tagName') 创建元素节点
2、document.createAttribute('propName') 创建属性节点
3、document.createTextNode('text') 创建文本节点
4、document.createComment('comment') 创建注释
创建节点方式效率
document.write()直接将内容写入页面的内容流,会导致页面全部重绘
innerHTML页面创建元素很多时使用,采取数组形式拼接效率极高,采取拼接字符串效率低
creatElement果页面创建元素较少时使用

13.1.3 克隆节点

1、node.cloneNode([false]) 复制节点本身
2、node.cloneNode(true) 复制节点本身及其子节点


13.2 删除节点

13.2.1 删除元素节点

1、node.parentNode.removeChild(sonNode) 删除指定的子节点并返回
2、childNode.remove() 删除自身

13.2.2 删除节点属性

1、element.removeAttribute('propName') 删除H5自定义的属性


13.3 修改节点

13.3.1 替换节点

1、node.parentNode.replaceChild(newChild, oldChild) 新节点替换旧节点

13.3.2 修改元素节点属性

1、element.setAttribute('propName','value') 修改内置和H5自定义的属性值
2、element.propName = value 修改内置属性的属性值

13.3.3 修改元素节点内容

1、element.innerHTML 修改标签内容
2、element.innerText 修改标签内容
3、element.outerHTML 修改标签和标签内容
属性备注
innerHTML修改标签内的内容。把标签、文本、空格和换行合成一个字符串
innerText修改标签内的内容。把标签、空格和换行去除,只保留文本
outerHTML修改包括标签自身和标签的内容

13.3.4 修改元素节点样式

1、element.className = 'value' 通过class属性值修改元素节点样式
2、element.style.propName = 'value' 通过style属性修改元素节点样式(只修改行间样式)


13.4 获取节点

13.4.1 遍历节点树

1、node.parentNode 获取父节点
2、node.childNodes[index] 获取首代指定下标的子节点
3、node.firstChild 获取首代第一个子节点
4、node.lastChild 获取首代最后一个子节点
5、node.previousSibling 获取上一个兄弟节点
6、node.nextSibling 获取下一个兄弟节点

13.4.2 遍历元素节点树

1、node.parentElement 获取父元素节点
2、node.children[index] 获取首代指定下标的子元素节点
3、node.firstElementChild 获取首代第一个子元素节点
4、node.lastElementChild 获取首代最后一个子元素节点
5、node.previousElementSibling 获取上一个兄弟元素节点
6、node.nextElementSibling 获取下一个兄弟元素节点
属性兼容性
除children外的属性ie9及以下不支持

13.4.3 获取元素节点

1、document.documentElement 获取<html>节点
2、doucumnet.body 获取<body>节点
3、doucumnet.head 获取<head>节点
属性原型
documentElementDocument.prototype
bodyHTMLDocument.prototype
headHTMLDocument.prototype
4、document.getElementById('idValue') 通过id值获取元素节点
5、document.getElementsByTagName('tagName') 通过标签名获取元素节点
6、document.getElementsByClassName('className') 通过class值获取元素节点
7、document.getElementsByName('nameValue') 通过name值获取元素节点
8、document.querySelector('selector') 通过指定选择器获取元素节点
9、document.querySelectorAll('selector') 通过指定选择器获取所有元素节点
方法备注兼容性原型
getElementById返回id值唯一的元素节点对象兼容所有Document.prototype
getElementsByTagName返回伪数组兼容所有Document.prototype、Element.prototype
getElementsByClassName返回伪数组不支持IE8及IE8以下Document.prototype、Element.prototype
getElementsByName返回伪数组不支持 IEHTMLdDocument.prototype
querySelector只返回第一个符合条件的元素节点,取不到伪类不支持ie7及ie7以下Document.prototype、Element.prototype
querySelectorAll返回伪数组不支持ie7及ie7以下Document.prototype、Element.prototype
<div></div>
<div class="demo"></div>
<div></div>
// querySelector()和.querySelectorAll()选出来的元素不是实时的,是静态的,是副本
var divNode = document.getElementsByTagName('div');
var divNode_2 = document.querySelectorAll('div');
var newNode = document.createElement('div');
document.body.appendChild(newNode);
console.log(divNode);   // [div, div.demo, div, div]
console.log(divNode_2); // [div, div.demo, div],并没有实时更新

13.4.5 获取节点属性

1、element.getAttribute('propName') 获取内置和H5自定义属性的属性值
2、element.dataset.propName 获取H5自定义属性的属性值
// 自定义属性目的:是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。
// 但是有些自定义属性很容易引起歧义,不容易判断是元素的内置属性还是自定义属性。所以就有H5规定自定义属性data-开头做为属性名并且赋值
// 若h5自定义属性是 data-index="2" data-list-name="andy"
// 获取h5自定义属性值应该要去掉data-并添加dataset

console.log(div.dataset.index);
console.log(div.dataset['index']);
console.log(div.dataset.listName);
console.log(div.dataset['listName']);

13.4.6 获取节点内容

1、element.innerHTML 获取标签内容
2、element.innerText 获取标签内容
3、element.outerHTML 获取标签和标签内容
属性备注
innerHTML获取标签内的内容。把标签、文本、空格和换行合成一个字符串
innerText获取标签内的内容。把标签、空格和换行去除,只保留文本
outerHTML获取包括标签自身和标签的内容

13.4.7 获取文档相对于浏览器窗口因为滚动条移动的距离

1、window.pageYOffset / window.pageXOffset
2、document.body.scrollLeft / document.body.scrollTop
3、document.documentElement.scrollLeft / document.documentElement.scrollTop
// 开发中使用的兼容方法
function getScrollOffset() {
    if(window.pageXOffset) {
        // IE8 及 IE8 以下不兼容
        return {
            x: window.pageXOffset,
            y: window.pageYOffset
        }
    }else {
        // IE8 及 IE8 以下的使用方法
        // 这两个方法兼容性比较混乱,但规律是其中一个有值,另外一个的值一定是 0。兼容的方法是取两个值相加
        return {
            x: document.documentElement.scrollLeft + document.body.scrollLeft,
            y: document.documentElement.scrollTop + document.body.scrollTop
        }
    }
}

5.7.6 获取可视区窗口的尺寸

1、window.innerWidth / window.innerHeight
2、document.body.clientWidth / document.body.clientHeight
3、document.documentElement.clientWidth / document.documentElement.clientHeight
// 可视区窗口: 不含菜单栏、地址栏、控制台,若控制台占据部分空间则这部分空间不算入可视区
function getViewportOffset() {
	if(window.innerWidth) {
	    // 兼容ie9以上
	    return {
	        w: window.innerWidth,
	        h: window.innerHeight
	    }
	}else {
	    // 兼容IE8 及 IE8 以下
	    if(document.compatMode === 'BackCompat') {
	        // 渲染模式是怪异/混杂模式
	        return {
	            w: document.body.clientWidth,
	            h: document.body.clientHeight
	        }
	    }else {
	        // 渲染模式是标准模式
	        return {
	            w: document.documentElement.clientWidth,
	            h: document.documentElement.clientHeight
	        }
	    }
	}
}

5.7.7 获取元素节点样式

1、window.getComputedStyle(element,null).propName 获取计算样式(权重最高的样式)
<style>
    div {
        width: 300px !important;
        height: 10rem;
        background-color: pink;
    }

    div::after {
        content: '';
        display: block;
        width: 100px;
        height: 100px;
        background-color: green;
    }

    .demo::after {
        content: '';
        display: block;
        width: 200px;
        height: 200px;
        background-color: red;
    }
</style>
<body>
    <div style="width: 150px"></div>
    <script>
        var divNode = document.getElementsByTagName('div');        
        // 获取伪元素的样式
        console.log(window.getComputedStyle(divNode[0],"after").width); 	// 结果: 300px 160px 150px 100px      
        // 修改伪元素样式,使用className转换
        var flag = true;
        divNode[0].onclick = function () {
            if(flag) {
               this.className = 'demo'; 
            }else {
                this.className = '';
            }
            flag = !flag;
        }
    </script>
</body>
2、element.offsetWidth / element.offsetHeight 获取元素可实宽高(Width/Height+border+padding)
3、element.offsetTop / element.offsetLeft 获取元素相对于父元素上偏移和左偏移

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4、element.clientTop / element.clientLeft 获取上/左边框大小
5、element.clientWidth / element.clientHeight 获取元素width/height+padding的宽度

在这里插入图片描述

6、 element.scrollTop / element.scrollLeft 获取被卷去的高/宽
7、element.scrollWidth / element.scrollHeight 获取元素实际的宽/高

在这里插入图片描述

8、element.offsetParent 获取最近的有定位的父级,如无,返回 body
属性备注(返回的不带单位的数值)
offsetTop、offsetLeft它以带有定位的父亲为准 如果没有父亲或者父亲没有定位 则以 body(有8px的外边距) 为准
offsetWidth、offsetHeight包含contentWidth/contentHeight+border+padding
offsetParent如果父级没有定位则返回body
clientTop、clientLeft\
clientWidth、clientHeight不包含边框的可见宽高
scrollTop、scrollLeft返回滚动条卷去部分内容的高宽
scrollWidth、scrollHeight如果内容高宽高于容器高宽,则返回实际内容不包含边框的高宽

在这里插入图片描述





十四、事件

14.1 绑定事件

14.1.1 element.onEventType = callback

14.1.2 element.addEventListener('eventType', callback, flag)

14.1.3 element.attachEvent(onEventType, callback)

// 1、addEventListener的flag:true(事件捕获)/ false(事件冒泡,默认)
// 2、attachEvent:因为其this默认指向window,所以要想修改this指向,则需要分别写处理函数和回调函数

在这里插入图片描述

方法备注兼容性this
onEventType一个对象只能绑定一个回调函数,若重复绑定则最后注册的处理函数将会覆盖前面注册的处理函数兼容所有绑定的对象
addEventlistener可以绑定多个回调函数,若回调函数使用方法名形式并且重复绑定,则只执行一次ie9以上绑定的对象
attachEvent可以绑定多个回调函数,同一个元素同一个事件可以注册多个监听器按注册顺序依次执行ie8及ie8以下window
/**
 * 给dom添加事件处理函数兼容方法
 * @param {object} element  dom对象
 * @param {string} type     事件类型
 * @param {function} handle 回调函数
 * @param {boolean} flag    addEventListener冒泡/捕获
 */

function addEvent(element, type, handle, flag) {
    if(element.addEventListener) {
        element.addEventListener(type, handle, flag);
    }else if(element.attachEvent) {
        element.attachEvent('on' + type, handle);
    }else {
        element['on' + type] = handle;
    }
}

14.2 解绑事件

14.2.1 element.onEventType = null

14.2.2 element.removeEventListener('eventType', callback)

14.2.3 element.detachEvent(onEventType, callback)

/**
 * 给dom解绑事件处理函数兼容方法
 *
 * @param {object} element  dom对象
 * @param {string} type     事件类型
 * @param {function} handle 回调函数
 * @param {boolean} flag    addEventListener冒泡/捕获
 */

function removeEvent(element, type, handle, flag){
    if(element.addEventListener){
        element.removeEventListener(type, handle, flag);
    }else if(element.attachEvent){
        element.detachEvent('on' + type, handle);
    }else{
        element["on" + type] = null;
    }
}

14.3 阻止事件冒泡

1、event.stopPropagation() ie9以上
2、event.cancelBubble = true ie8及ie8以下
/**
 * 阻止冒泡兼容写法
 *
 * @param {object} event 事件对象
 */

function stopBubble(event) {
    if(event.stopPropagation) {
        event.stopPropagation();
    }else {
        event.cancelBubble = true;
    }
}

14.4 阻止默认事件行为

1、e.preventDefault() ie9以上
2、e.returnValue = false ie8及ie8以下
3、return false 句柄事件绑定方式
/**
 * 阻止默认行为兼容写法
 *
 * @param {object} event 事件对象
 */
 
function stopDefault(event) {
    if(event.preventDefault) {
        event.preventDefault();
    }else {
        event.returnValue = false;
    }
}

14.5 事件对象

14.5.1 获取事件对象

1、window.event ie8以及ie8以下
2、 e ie9以上
/**
 * 获取事件对象
 *
 * @param {object} e 事件对象
 * @return {object}  兼容的事件对象
 */
 
function getEvent(e) {
    return e || window.event;
}

14.5.2 获取事件对象属性

1、e.target 获取事件源对象
/**
 * 获取事件源对象
 *
 * @param {object} e 事件对象
 * @return {object}  兼容的事件源对象
 */

function getEventTarget(e) {
    return e.target || e.srcElement;
}

2、e.clientX、e.clientY 获取相对于可视化页面鼠标的坐标
3、e.pageX、e.pagrY 获取相对于完整页面的鼠标的坐标
4、e.screenX、e.screenY获取相对于电脑屏幕的鼠标的坐标
5、e.keyCode 获取按键的ASCII值
属性备注
e.target触发事件的元素,标准
e.srcElement触发事件的元素,非标准、ie6~8使用
e.type不带on
e.clientX、e.clientY返回可视化页面(浏览器窗口)的鼠标x,y坐标,原点是当前可视化页面的左上角,不带单位
e.pageX、e.pagrY返回完整文档页面(包括滚动条的页面)的鼠标x,y坐标,原点是完整页面的左上角,不带单位
e.screenX、e.screenY返回电脑屏幕的鼠标x,y坐标,原点是屏幕的左上角,不带单位
e.keyCodeonkeydown 和 onkeyup 不区分字母大小写,onkeypress 区分字母大小写。
e.persisted如果返回的是true 就是说如果这个页面是从缓存取过来的页面


14.6 事件类型

14.6.1 鼠标事件

1、click 单击事件
2、dblclick双击事件
3、mouseover / mouseenter 鼠标移入
4、mouseout / mouseleave鼠标移出
5、mousedown / mouseup鼠标按键被按下 / 松开
6、mousemove 鼠标被移动
7、contextmenu 右键打开菜单
鼠标事件备注
onmouseover鼠标移入,经过子节点会重复触发,有冒泡现象
onmouseout鼠标移出,经过子节点会重复触发,有冒泡现象
onmouseenter鼠标移入,经过子节点不会重复触发
onmouseleave鼠标移出,经过子节点不会重复触发
oncontextmenu主要用于程序员取消默认的上下文菜单
onselectstart主要用于禁止外人复制内容

14.6.2 键盘事件

1、document.onkeydown 键盘按键被按下
2、document.onkeypress 键盘字符键按键被按下
3、document.onkeyup 键盘按键被松开
document.onkeydown = function () {
    console.log('keydown');
}

document.onkeypress = function () {
    console.log('keyPress');
}

document.onkeyup = function () {
    console.log('keyup');
}

// 先后顺序是keydown - keyPress - keyup
// 你想监控字符类按键,并想区分大小写,就用keypress.charCode,如果是操作类按键就用keydown.keyCode

14.5.3 窗口事件

1、window.onload 页面完全加载完毕
2、window.onDOMContentLoaded页面html加载完毕
3、window.onresize 窗口大小变化
4、window.onscroll 当滚动条一滚动,scroll 事件就触发了

事件备注
window.onload当文档内容完全加载完成会触发该事件。如图像、脚本文件、CSS文件等
而且传统注册方式只能写一个,监听器方式可以写多个
window.onDOMContentLoaded纯HTML加载完成会触发该事件。不包括样式表,图片,flash等等
页面的图片很多,从用户访问到onload触发可能需要较长的时间时使用
Ie9以上才支持
window.onresize只要窗口大小发生像素变化,就会触发这个事件。
经常利用这个事件配合window.innerWidth(屏幕宽度) 完成响应式布局

14.5.4 表单事件

1、element.oninput 表单所有变化(增删改)都会触发 input 事件
2、element.onchange 聚焦与失去焦点状态转换之间表单内容有修改则触发
3、element.onblur 失去焦点
4、element.onfocus 获取焦点
        下列事件必须添加在form元素上
             submit:			当我们点击type = submit上的按钮才能触发
             reset:			当我们点击type= reset上的按钮才能触发

14.5.5 移动端触屏事件

1、ontouchstart 触摸到DOM元素
2、ontouchmove 在DOM元素上滑动
3、ontouchend 从DOM元素上移开



十五、web存储技术

15.1 添加方法

1、sessionStorage.setItem(key, value) 存储数据
2、localStorage.setItem(key, value) 存储数据

15.2 删除方法

1、sessionStorage.removeItem(key) 删除数据
2、sessionStorage.clear() 删除所有数据
3、localStorage.removeItem(key) 删除数据
4、localStorage.clear() 删除所有数据

15.3 修改方法

1、sessionStorage.setItem(key, value) = value 存储数据
2、localStorage.setItem(key, value) = value 存储数据

15.4 获取方法

1、 sessionStorage.getItem(key) 获取数据
2、localStorage.getItem(key) 获取数据


十六、Ajax

16.1 使用xhr发起get请求

var xhr = new XMLHttpRequest();			// 1、创建 xhr 对象
xhr.timeout = microSecondsCount;		// 2、设置HTTP请求时限(毫秒数)
xhr.open('GET','url', [,'flag']);       // 3、flag是否异步(默认false)
xhr.send();								// 4、发送请求
xhr.onreadystatechange = function () {	// 5、监听 onreadystatechange 事件, 状态改变触发回调函数
  if (xhr.readyState === 4 && xhr.status === 200) {
	// 获取成功
	...
  }
}
onreadystatechange中可使用的变量备注
readyState状态值(整数),可以确定请求/响应过程的当前活动阶段
responseText服务器返回的数据资源
status状态码(整数),如:200、404…
statusText状态文本(字符串),如:OK、NotFound…
readyState值动作状态
0未初始化 UNSENT未调用open()方法
1启动 OPENED已经调用open()方法,未调用send()方法
2发送 HEADERS_RECIEVED已经调用send()方法,未接收到响应
3接收 LOADING已经接收到部分数据
4完成 DONE已经接收到全部数据,可以在客户端使用

16.2 使用xhr发起post请求

var xhr = new XMLHttpRequest();		// 1、创建 xhr 对象
xhr.timeout = microSecondsCount;	// 2、设置HTTP请求时限(毫秒数)
xhr.open('POST', 'url'[,'flag']);	// 3、flag是否异步(默认false)	
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');	// 4. 设置 Content-Type 属性
xhr.send('不带问号的查询字符串');		// 5、发送请求
xhr.onreadystatechange = function () {	// 6、监听 onreadystatechange 事件, 状态改变触发回调函数
  if (xhr.readyState === 4 && xhr.status === 200) {
   	...
  }
}

16.3 原生JS封装Ajax函数

function ajax(options) {
  var xhr = new XMLHttpRequest();
  var qs = queryString(options.data);	 // 把外界传递过来的参数对象,转换为 查询字符串
  if (options.method.toUpperCase() === 'GET') {
    // 发起GET请求
    if(qs == '') {
      xhr.open(options.method, options.url);
    }else {
      xhr.open(options.method, options.url + '?' + qs);
    }
    xhr.send();
  } else if (options.method.toUpperCase() === 'POST') {
    // 发起POST请求
    xhr.open(options.method, options.url);
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    xhr.send(qs);
  }
  xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
      var result = JSON.parse(xhr.responseText);
      options.success(result);
    }
  }
}

// 将数据转为查询字符串格式
function queryString(data){
  var arr = [];
  for (var k in data) {
    var str = k + '=' + data[k];
    arr.push(str);
  }
  return arr.join('&');
}

16.4 数据处理JSON和JS对象的互转

1、JSON.parse(jsonStr) JSON 字符串转换为 JS 对象,叫做反序列化
2、JSON.stringify(Obj) JS 对象转换为 JSON 字符串,叫做序列化
var obj = JSON.parse('{"a": "Hello", "b": "World"}')		// obj =  {a: 'Hello', b: 'World'}
var json = JSON.stringify({a: 'Hello', b: 'World'})			// json = '{"a": "Hello", "b": "World"}'



十六、Proxy

15.1 Proxy声明

var proxy = new Proxy(target, handler);
参数备注
target所要拦截的目标对象
handler定制拦截行为的处理对象


15.2 handler的拦截器分类

1、删除拦截器
(1)deleteProperty(target, key) 拦截delete操作。如果抛出错误或返回false,属性就无法被delete删除
var handler = {
  deleteProperty (target, key) {
    invariant(key, 'delete');
    delete target[key];
    return true;
  }
};
function invariant (key, action) {
  if (key[0] === '_') {
    throw new Error(`Invalid attempt to ${action} private "${key}" property`);
  }
}
var target = { _prop: 'foo' };
var proxy = new Proxy(target, handler);
delete proxy._prop		// Error: Invalid attempt to delete private "_prop" property
2、修改拦截器
(1)set(target, propKey, value [, receiver]) 拦截对象属性的设置
let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
    }
    // 对于满足条件的 age 属性以及其他属性,直接保存
    obj[prop] = value;
    return true;
  }
};
let person = new Proxy({}, validator);
person.age = 100;
person.age // 100
person.age = 'young' // 报错
person.age = 300 // 报错
3、获取拦截器
(1)get(target, propKey [, receiver]) 拦截对象属性的读取
// 1、receiver指向proxy
var person = {
  name: "张三"
};
var proxy = new Proxy(person, {
  get: function(target, propKey) {
    if (propKey in target) {
      return target[propKey];
    } else {
      throw new ReferenceError("Prop name \"" + propKey + "\" does not exist.");
    }
  }
});
proxy.name // "张三"
proxy.age // 抛出一个错误
(2)has(target, propKey) 拦截propKey in proxy的操作,返回一个布尔值
// 1、has()方法拦截的是HasProperty操作,即has()方法不判断一个属性是对象自身的属性还是继承的属性
// 2、has()拦截只对in运算符生效,对for...in循环不生效,导致不符合要求的属性没有被for...in循环所排除
var handler = {
  has (target, key) {
    if (key[0] === '_') {
      return false;
    }
    return key in target;
  }
};
var target = { _prop: 'foo', prop: 'foo' };
Object.setPrototypeOf(target, {_prop_2: '123', prop_2: '456'});
var proxy = new Proxy(target, handler);
console.log('prop' in proxy);     // true
console.log('prop_2' in proxy);   // true
console.log('_prop' in proxy);    // false
console.log('_prop_2' in proxy);  // true
(3)construct(target, args [, newTarget]) 拦截new命令
// 1、target必须是函数
// 2、args是构造函数的参数数组
// 3、newTarget指的是创造实例对象时,new命令作用的构造函数(下面的p)
// 4、construct必须返回一个对象
const p = new Proxy(function () {}, {
  construct: function(target, args) {
    console.log('called: ' + args.join(', '));
    return { value: args[0] * 10 };
  }
});
(new p(1)).value		// "called: 1"  10
(4)apply(target, object, args) 拦截 Proxy 实例作为函数调用的操作
// 1、比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)
var twice = {
  apply (target, ctx, args) {
    return Reflect.apply(...arguments) * 2;
  }
};
function sum (left, right) {
  return left + right;
};
var proxy = new Proxy(sum, twice);
proxy(1, 2) // 6
proxy.call(null, 5, 6) // 22
proxy.apply(null, [7, 8]) // 30

15.3 取消Proxy代理器

// 1、Proxy.revocable()方法返回一个对象,该对象的proxy属性是Proxy实例,revoke属性是一个函数,可以取消Proxy实例
// 2、当执行revoke函数之后,再访问Proxy实例,就会抛出一个错误
let target = {};
let handler = {};
let {proxy, revoke} = Proxy.revocable(target, handler);
proxy.foo = 123;
proxy.foo // 123
revoke();
proxy.foo // TypeError: Revoked

总结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值