注:由于是直接从Typora文件复制粘贴过来的,因此有些格式可能会错位,见谅 须要这个文件的同窗能够直接发邮件给我 408579331@qq.comnode
var tem = 123;
if(true){
console.log(tem); // 报错
let tem = 0;
}
let a = a ; // 报错
let b = 0;
let b = 1; // 报错
复制代码
【注】ES5 中 不容许块级做用域中声明函数,但为了兼容老代码,因此ES6的规定中浏览器能够不遵照此规定,有本身的行为方式,因此通常函数的声明会像 var同样会进行函数名的提高,可是只做用于当前的块级做用域es6
【注】ES6 中 块级做用域中函数的声明必须包含在 { } 中,如 if(true) f(){}; 会报错,正确写法if(true) { f(){} };ajax
<1> 用于声明一个常量的值,一旦声明,常量的值就不能改变,若改变则会报错正则表达式
<2> 声明时必须赋值,若只声明不赋值,就会报错算法
<3> 做用域与 let 相同,只存在于当前做用域中json
<4> 没有预解析数组
<5> 存在暂时性死区的特性promise
<6> 同一个变量不能屡次声明浏览器
本质:const实际上保证的是变量指向的那个内存地址所保存的值是不能改变的,因此:服务器
const PI = 3.141592654;
console.log(PI);
PI = 3 ; // 报错
const a ; //报错
const b = [];
b.push('hello'); // 可执行
b.length = 10; // 可执行
b = ['aaa'] // 报错
// 若是想将对象冻结,需使用 Object.freeze() 方法 freeze:冻结
var c = Object.freeze({});
// 常规模式下,下面这行代码不起做用
// 严格模式下会报错
c.prop = 123;
复制代码
在 ES5 中 浏览器的顶层对象就是 window ,顶层对象的属性与全局变量时等价的 Node 里面,是 global 在 ES6 中 ,var 和 function声明的变量依旧是顶层对象的属性,但 let const class 声明的全局变量不属于顶层对象的属性
解构:ES6中容许按照必定模式,从数组和对象中提取值,对变量进行赋值,这称之为解构 数组的解构赋值是按照元素的顺序依次赋值
let [a,b,c] = [1,2,3]
// a:1 b:2 c:3
let [,,a] = [1,2,3]
// a:3
let [a,b] = [1,2,3]
// a:1 b:2
let [a,...b] = [1,2,3,4]
// a:1 b:[2,3,4]
// ... 扩展运算符,将一个数组变成参数序列
let [a,b,...c] = [1]
// a:1 b:undefined c:[]
let [a] = [];
// a:undefined
let [a] = 1;
// 报错
// 默认值
//**注意:当一个数组成员严格等于( === )undefined时,默认值才会生效**
let [x=1] = [undefined];
// x:1
let [x=1] = ['undefined'];
// x:'undefined'
let [x=1] = [null];
// x:null;
let [x=1] = [2];
// x:2
复制代码
变量与对象的解构赋值是变量与属性同名,再进行赋值 例:let {a} = {a:1} 对象与对象的解构赋值是先找到同名的属性,再赋值给对应的变量 例:let {a:b} = {a:1} b=>1
let {x,y}={x:1,y:2};
// x:1 y:2;
// 当变量名与属性名不一致时
let a = {x:1,y:2};
let {x:a,y:b}=a;
// a:1 b:2
let {a:b} = {a:2};
// b:2
// a:报错,not undefined
// 对象与对象的解构赋值的内部机制,是先找到同名属性,而后再赋给对应的变量。真正被赋值的是后者,而不是前者
// 例:
const node = {loc: {start: {line: 1,column: 5}}};
let { loc, loc: { start }, loc: { start: { line }} } = node;
console.log(loc); {start:{line:1,column:5}}
console.log(start); {line:1,column:5}
console.log(line); 1
let { loc, loc: { start }, loc: { start: { line }} } =
{loc: {start: {line: 1,column: 5}}};
// 例2
let obj = {p: ['Hello',{ y: 'World' }]};
let { p, p: [x, { y }] } = obj;
console.log(p); ['Hello',{ y: 'World' }]
console.log(x); 'Hello'
console.log(y); 'World'
// 例3
let obj = {};
let arr = [];
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
console.log(obj); {prop:123}
console.log(arr); [true]
不加一对小括号时,js在行首遇到{}会解析成代码块,从而引起语法错误
// 有默认值时
//**注意:当一个数组成员严格等于( === )undefined时,默认值才会生效**
let {a,b=1}={a:1};
// a:1 b:1
let {x: y = 3} = {};
// y:3 x:报错,not undefined
let {x,y = 3} = {};
// y:3 x:undefined
let {foo: {bar}} = {baz: 'baz'};
// 报错,由于foo是undefined,因此它的子对象就会报错
// 数组的解构赋值
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
// 因为数组的本质是一个特殊的对象,因此 arr=>{0:1,1:2,2:3} ?
console.log(first);
console.log(last);
复制代码
const [a,b,c,d,e] = 'hello';
// a:'h'
// b:'e'
// c:'l'
// d:'l'
// e:'o'
let {length:len} = 'hello'
// len:5
// 字符串是一个类数组,因此具备 length 属性
复制代码
解构赋值的规则:只要等号右边的值不是对象或者数组,就先将其转换成对象,在进行赋值
let {toString:s} = 123;
s === Number.prototype.toString // true
let {toString:s} = true
s === Boolean.prototype.toString // true
// 由于 数值和布尔 的包装对象都具备 toString 属性,因此 变量s 都会被赋值
let {toString:x} = undefined ; // 报错:TypeError
let {toString:x} = null ; // 报错:TypeError
复制代码
function xy([a,b]){
return a+b;
}
xy([1,2]) ===> 3
let arr = [[1,2],[3,4]].map(([a,b])=>a+b);
// .map()方法:数组中的每个元素执行map方法中的函数或者方法,返回一个新的数组
// arr ===> [3,7]
// 函数参数也可使用默认值
// 变量默认值
function xy({x=0,y=0}={}){
return x+y;
}
xy({x:1,y:2}) ===> 3
xy({x:1,a:2}) ===> 1
xy({}) ===> 0
xy() ===> 0
// 参数默认值
function move({x,y}={x:0,y:0}){
return x+y;
}
move({x:1,y:2}) ===> 3
move({x:1}) ===> NaN 由于 y的值是undefined,因此最终结果为NaN
move({}) ===> NaN
// 注意:上述是为参数指定默认值,而不是变量
复制代码
// (1). 交换变量的值
let x = 1;
let y = 2;
[x,y] = [y,x];
// (2). 函数返回多个值
function xy(){
return [1,2,3,4];
}
let [a,b,c,d] = xy();
// a:1 b:2 c:3 d:4
// (3). 函数参数的定义
function xy([x,y,z]){ ... }
xy([1,2,3])
function xy({x,y,z}){ ... }
xy({z:1 , y:2 , x:3})
// (4). 提取 JSON 数据
let jsonData = {
id:1,
status:'OK',
data:[111,222]
}
let {id,status,data:arr} = jsonData;
// id:1 status:'OK arr:[111,222]
// (5). 函数参数的默认值
let ajax = function(url,{ async = true, // async 异步 beforeSend = function(){},
cache = true, // 隐藏
complete = function(){}, // complete 完整的,完成
crossDomain = false, // cross 交叉 domain 领域
global = true, // 全球的,整体的
} = {} ){ ... }
// (6). 遍历map解构
const map = new Map([
[{a:1},1]; // 键是对象
['a',1] // 键是字符串
]);
/* Map()构造函数,是一个键值对的集合,其中键能够时任意类型 集合是一个数组,其中数组中的每个数组项都是Map实例的键和值*/
map.set('first','hello'); // 添加一组键值对
map.get('first') // 获取指定的属性值
map.has('first') // 判断是否存在某个属性,返回bool
map.delete('first') // 删除指定的属性,返回bool
map.size; // 获取数组的长度
map.clear() // 清除全部
// map 的遍历方法--返回一个迭代器,相似一个对象?
.keys() // 返回键名的遍历器
.values() // 返回键值的遍历器
.entries()// 返回全部成员(键值对)的遍历器
.forEach()// 遍历Map的全部成员
// 例:
for(let val of map.kes()){
console.lof(val);
}
for(let [key,value] of map.entries()){
console.lof(key+"==="+value);
}
// 只想得到键名
for(let [key] of map){
console.log(key);
}
// 只想得到值
for(let [,val] of map){
console.log(value);
}
// Set() 构造函数
复制代码
// 能够以 \uxxxx 表示一个字符,其中 xxxx 时 Unicode码点
'\u{7A}' === 'z'
复制代码
// 对于字节超出 Unicode 码点的字符,charAt()方法没法读取
// 因此提供了 codePointAt()方法来读取码点
复制代码
// 经过码点获取字符,能够识别编号大于 0xFFFF 的字符编码
String.fromCodePoint(0x20BB7);
复制代码
// 使用 for of 遍历字符串,能够识别大于 0xFFFF 码点的字符
for(let code of 'foo'){
console.log(code); // 'f' 'o' 'o';
}
复制代码
/* 用于他国语言的语调符号和重音符号 Ǒ(\u01D1)和 O(\u004F)和ˇ(\u030C)合成Ǒ(\u004F\u030C) 两种合成符的判断,js中直接判断为false ,加上 .noemalize()方法后为true */
复制代码
let s = "Hello World";
s.startsWith("Hello") // true 判断参数是否在字符串的开头
s.endWith("World") // true 判断参数是否在字符串的结尾
s.includes('o') // true 判断是否存在该字符串
s.startWith("World",6) // true 从第6个位置到结束是不是以"World"开头
s.includes("Hello",6) // false 从第6个位置到结束中是否包含指定字符串
// 注意--------------
s.endWith("Hello",5) // 前5个字符中是否包含指定字符串
复制代码
// 返回一个新字符串,表示将指定字符串复制n次
let str = "a".repeat(2); // "aa";
let str = "xy".repeat(2); // "xyxy";
// 参数为小数则会取整,负数则报错,0则是一个空字符串
let str = "xy".repeat(2.9); //"xyxy"
let str = "xy".repeat(-1); // 报错
let str = "xy".repeat(0); // 空字符串
// 若是参数是 0~-1之间的小数,则会先取整,也就是按 0 计算
// 若是参数是 NaN 则会按 0 进行计算
// 若是参数是字符串,则先会用 Number() 进行转换再进行计算
复制代码
// 字符串填充
.padStart() // 头部补全
.padEnd() // 尾部补全
'xy'.padStart(3,'0'); // "0xy"
'xy'.padEnd(4,'0'); // "xy00"
'xy'.padStart(5,'ab'); // "abaxy"
'xy'.padEnd(5,'ab'); // "xyaba"
// 第二个参数省略,默认用空格补全
'xy'.padEnd(5); // "xy "
复制代码
// 返回一个正则表达式在当前字符串的全部匹配
复制代码
let str = `<div>${a+1}</div>`;
let str = `<div>${fn()}</div>`;
复制代码
// 返回指定索引对应的字符
let str = "123456"
at(0) // 1
复制代码
// 判断一个数值是否为整数
Number.isInteger(25); // true
Number.isInteger(25.5); // false
复制代码
/* 可以接受的偏差范围 Number.EPAILON 是一个常量,表示1与大于1的最小浮点数之差,即 1 与 1.000...0001(51个零) 等同于 Math.pow(2,-52) 经常使用于浮点数计算后的偏差判断,若是小于这个值,则表示偏差没有意义,即:不存在偏差*/
function withinErrorMargin (left, right) {
return Math.abs(left - right) < Number.EPSILON * Math.pow(2, 2);
}
复制代码
// 判断整数是否是在 -2^53 到 2^53 之间,由于在js内超过这个数值,判断就会出错
Number.isSafeInteger(num) // 返回一个布尔值,注意,只判断数字,其他都为 false
复制代码
// 1. Math.trunc()
// 用于去除一个数的小数部分,返回整数部分
Math.trunc(1.222) // 1
Math.trunc(-0.111) // 0
// 对于非数字,会先用 Number() 进行内部转换
Math.trunc(true) // 1
Math.trunc(false) // 0
// 转换失败则返回 NaN
Math.trunc(NaN) // NaN
Math.trunc('foo') // NaN
Math.trunc() // NaN
Math.trunc(undefined) // NaN
// 2. Math.sign()
// 判断一个数是 正数 负数 零 ,若是是非数值,则会先进行 Number() 转换
// 返回 1:正数 -1:负数 0:零 -0:(输入-0的时候) NaN:转换失败 报错:参数语法错误时
Math.sign(55) // 1
Math.sign(-1546) // -1
Math.sign(0) // 0
Math.sign(-0) // -0
Math.sign('ss') // NaN
Math.sign(2aa) // 报错
// 3. Math.cbrt()
// 用于计算一个数的立方根 , 若是是非数值,则会先进行 Number() 转换
// 返回: 计算后的值 NaN
Math.cbrt(8) // 2
Math.cbrt('8') // 2
Math.cbrt('ss') // NaN
// 4. Math.hypot()
// 返回全部参数的平方和的平方根
// 若是参数不是数值,则会先用 Number() 进行转换,只要有一个为NaN,则返回 NaN
// 能够写多个参数
Math.hypot(3,4) // 5
Math.hypot() // 0
Math.hypot(NaN) // NaN
Math.hypot(3,4,'a') // NaN
复制代码
2 ** 2 // 4
2 ** 3 // 8
2 ** 4 // 16
// 计算方式是右结合,即从右往左计算
2 ** 3 ** 2 ==> 2 ** (3 ** 2) // 512
// 能够与 = 结合
let a = 2;
a **= 3 // 8
复制代码
function abc(a=1, b=2){
ruturn a+b;
}
// 注意:使用参数默认值时,函数不能有同名的形参
// 参数也能够是一个表达式
let i = 100;
function abs(y = i + 1){
console.log(y);
}
abs(); // 101
// 与解构赋值一块儿使用
function foo({x,y = 5} = {}){
console.log(x,y);
}
foo({x:1, y:2}); // 1,2
foo(); // undefined 5
// 注意,若是不设置默认值是 foo()调用会出错,由于只有foo的参数是一个对象时,x,y才会经过结构赋值生成,若果不生成就会报错
// 当知道了默认值后,函数length属性的计算将去掉该参数
// 函数.length : 该函数预约义传入参数的个数
(function(a, b = 1){}).length // 1
// 做用域
// 当设置的参数的默认值时,函数声明初始化时会造成一个单独的 参数 做用域,当初始化结束,该做用域消失
// 若是没有设置默认值,则不存在该做用域
function abc(x, y = x){ return y;}
// 当abs进行初始化时,参数会造成一个单独的做用域,此时 y 的默认值 x 指向 第一个参数 x
// 因此 abc(90) 会返回 90
let x = 1;
function foo(y = x){
let x = 2;
console.log(y);
}
// 当foo进行初始化时,参数会造成一个单独的做用域,因为做用域链的问题,因此 x 会像上查找,
// 查找不到则会报错,即:此时初始化结束后就至关于 y = 1 ;
复制代码
ES6中引入了rest参数(形式为 ...变量名),用于获取函数的多余参数,获取后的格式为一个数组
function foo(x, ...values){
let sum = 0 + x;
for(let val of values){
sum += val;
}
return sum;
}
foo(1,2,3,4,5,6) 21
// 函数的 length 属性不包括 rest 参数
复制代码
// 返回该函数的函数名
function foo(){};
foo.name; // 'foo'
var a = function(){};
a.name; // ES5总为 '' ES6中为 'a'
复制代码
注意:使用了箭头函数后,这个函数里面就没有本身的this,里面所出现的this是外部函数的this,而不是指向的this,这种状况也称为this指向的固定化
// 只有一个参数
let f = v => v;
// 等同于
let f = function (v) {
return v;
}
// 无参数
let f = () => 5;
// 等同于
let f = function () {
return 5;
}
// 多个参数
let sum = (num1,num2) => num1 + num2;
// 等同于
let sum = function(num1, num2){
return num1 + num2;
}
// 返回一个对象
// 因为代码块是用 {} 包含起来的,因此返回一个对象时需用 () 包含起来,不然对象的 {} 会被解析成函数体
let a = id => ({id:id,num:1})
// 与解构赋值一块儿使用
let a = ({first,last}) => first + '' + last;
// 与 rest 参数一块儿使用
let a = (...arr) => arr;
复制代码
改变this指向,即:双冒号左边的对象是右边函数中的this
// 1. obj::foo
等同于 foo.bind(obj)
复制代码
尾调用:指某个函数的最后一步调用了一个函数,即:return y(x); 的严格格式 尾调用优化:每一次函数调用都会在内存中造成一个"调用记录",又称“调用帧”,保存调用位置和内部变量等信息,全部的调用帧称之为 调用栈 ,若是内部函数用到外部函数的变量,就不会进行尾调用优化
尾递归:函数调用自身,称之为递归,尾调用自身,称之为尾递归
// ... ,将一个数组转为用逗号分割的参数列表,内部使用for...of循环
console.log(...[1,2,3]) // 1 2 3
// 通常用于函数调用
let arr = [1,2,3,4,5,6];
foo(...arr)
// 数组最大值判断
let arr = [1,2,3,4,5,6];
Math.max(...arr);
// 数组中的每一项添加到另外一个数组中
let arr = [1,2,3,4];
let brr = [5,6,7,8];
arr.push(...brr);
// 数组复制--浅拷贝
let arr = [1,2,3];
let brr = [];
brr = [...arr];
// 数组合并--浅拷贝
let arr = [1,2,3,4];
let brr = [5,6,7,8];
let crr = [...arr , ...brr];
// 数组与结构赋值一块儿使用
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
// 字符串转数组
let arr = [...'hello']
// ['h','e','l','l','o']
// 类数组转换成规定的数组
let liArr = document.querySelectorAll('li');
let arr = [...liArr];
/* query.selectorAll 方法返回的是一个NodeList对象。不是一个数组,而是一个相似数组的对象, 之因此能够用数组的方法,是由于nodeList对象实现了Iterator(迭代)接口*/
复制代码
将两类对象转换成规定的数组:相似数组的对象(具备length属性),可遍历迭代对象 若是参数是一个规定的数组,该方法会返回一个如出一辙的新数组------即:复制
let arrayLike = {
'0':'a',
'1':'b',
'2':'c',
length:3
}
let arr = Array.from(arrayLike);
// ['a','b','c','d']
Array.from()方法还有第二个参数,做用相似于map()方法,将数组中的被一个元素进行处理并返回
Array.from(arr,x=>x*x)
// 等同于
Array.from(arr).map(x=>x*x);
// 例:取出每一个节点的内容,并造成一个数组
let liObj = document.querySelectorAll('li');
let arr = Array.from(li,v=>v.innerHTML);
// 例:将布尔值为false的数组项转换成0
let arr = [1,2,,3,,5,,0,];
let brr = Array.from(arr,v=>v||0);
// [1, 2, 0, 3, 0, 5, 0, 0]
复制代码
用于将一组值转换成数组
Array.of(1,2,3);
// [1,2,3]
复制代码
var arr = ['a','b','c', 1,2,3]
arr.keys(); // 返回一个对键名的遍历器---- 一个对象
arr.values(); // 返回一个对键值的遍历器---- 一个对象
arr.entries(); // 返回一个对键值队的遍历器---- 一个对象
// 遍历器中有一个next()方法,里面存放着一条数据,可循环调用来一次输出结果
arr.keys().next(); === {value: 0, done: false}
arr.values().next(); === {value: "a", done: false}
arr.entries().next(); === {value: Array(2), done: false}
arr.entries().next().value; === [ 0,'a']
// 例:用 for of 来循环遍历
for(var [key,value] of arr.entries()){
console.log(key+"="+value);
}
// 0='a' 1='b' 2='c' 3=1 4=2 5=3
复制代码
// 将多维数组“拉平”
[1,[2]].flat();
// [1,1]
[1,[2,[3]]].flat();
// [1,2,[3]] 默认拉平一层,从外向内拉平
// flat(number);
number:设置拉平的层数
Infinity 关键字,表示无限
// 若是数组有空位,flat()方法会跳过空位
[1,2,3,,4].flat();
// [1,2,3,4]
复制代码
// 对原数组的每个成员执行一个函数(至关于执行了map()方法),返回一个新数组
// 执行完后再执行flat()方法
[1,2,3,4,5,6].flatMap(x=>x*x); //[1,4,9,16,25,36]
[1,2,3,4].flatMao(x=>[x,x*x]); //[1,1,2,4,3,9,4,16]
复制代码
/* ES6中 Array.from(),(...),entries(),keys(),values(),find(),findIndex() 等会将空位处理成 undefined */
[...[,1]] // [undefined,1]
复制代码
// ES6 容许直接在对象中直接写入变量,此时,变量名为属性名,变量值为属性值
let aaa = 1;
let obj = {aaa}; // {'aaa':1}
复制代码
let aaa = 'a'
let obj = {
['a'+'bc']:1,
[aaa]:2
}
obj.abc // 1
obj.a // 2
obj.aaa // undefined
obj[aaa]// 2
复制代码
// 对象中的每一个属性的都有一个描述对象(Descriptor),用来控制该属性的行为
Object.getOwnPropertyDescriptor() 方法能够获取该属性的描述对象
let obj = {foo:123};
Object.getOwnPropertyDescriptor(obj,'foo'); // 返回一个对象
// {
// value: 123,
// writable: true,
// enumerable: true, //可枚举性
// configurable: true
// }
// 由于for in 遍历会返回继承的属性,因此能够经过设置 enumerable 属性值为 false 来让其忽略该属性
Object.getOwnPropertyDescriptor(Object.prototype, 'toString')
// ES7 引入了Object.getOwnPropertyDescriptors方法,
// 返回指定对象全部自身属性(非继承属性)的描述对象
复制代码
(1) for...in
循环遍历对象自身的和继承的可枚举属性(不包含Symbol属性)
(2) Object.keys(obj)
返回一个数组,包含对象自身的全部属性的(不含继承)全部可枚举属性(不含Symbol属性)的键名
(3) Object.getOwnPropertyNames(obj)
返回一个数组,包含对象自身的全部属性(不含Symbol属性,可是包括不可枚举属性)的键名
(4) Object.getOwnPropertySymbols(obj)
返回一个数组,包含对象自身的全部键名,无论键名时Symbol 或字符串,也无论是否可枚举
(5) Reflect.ownKeys(obj)
返回一个数组,包含对象自身的全部键名,无论键名时Symbol或者字符串,也无论是否可枚举
// 以上 5 种遍历对象的键名都遵照一样的属性遍历的次序规则
- 首先遍历全部的数值键,按照数值升序排序
- 其次遍历全部的字符串键,按照加入时间升序排列
- 最后遍历全部订单 Symbol 键,按加入时间升序排序
// 例:
Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 })
// ['2','10','b','a',Symbol()]
复制代码
表示指向当前对象的原型对象
let obj = {
foo:123,
foo(){
return super.name;
}
};
Object.prototype.name="ybm";
console.log(obj.foo());
// 注意,此关键词只能用于对象的方法中,在其余地方使用会报错
let obj = {
foo:super.name
}
// 报错,该关键词用于对象的属性中
let obj = {
foo:()=>super.name
}
let obj = {
foo:function (){
return super.name;
}
}
// 报错,由于在JS引擎的解析中,此时的super用在一个函数中,而后赋值给foo属性。
// 因此,目前只有对象方法的简写形式可让js引擎确认定义的是对象的方法
/* 在JS引擎的内部,super.foo等同于 Object.getPrototypeOf(this).foo 属性 或 Object.getPrototypeOf(this).foo.call(this) 方法 */
复制代码
// 比较两个值是否相等 可比较特殊的字符
Object.is(NaN,NaN) // true
Object.is(+0,-0) // false
Object.is({},{}) // false
Object.is(+0,0) // true
Object.is(-0,0) // false
复制代码
// 用于的对象的合并,将源对象的全部可枚举的属性复制到目标对象中,不拷贝继承迭代属性
// 若属性名相同,则后面对象的属性值会覆盖前面的属性值
Object.assign(目标对象,源对象)
const target = {a:1};
const target1 = {b:2};
const target2 = {c:3};
const target3 = {a:4};
Object.assign(target,target1,target2,target3)
// target {a:4,b:2,c:3};
// 第二个参数能够为一个字符串,若是是字符串,就会以数组的形式拷贝进目标的对象
// 数值和布尔类型则不会起做用
let str = "abc";
let obj = {a:1};
Object.assign(obj,str);
// obj {'0':'a', '1':'b', '2':'c', a:1}
// 1. 为对象添加方法
Object.assign(SomeClass.prototype,{
someMethod(a,b){
},
anotherMethod(){
}
})
// 等同于下面的写法
SomeClass.prototype.someMethod = function(a,b){};
someClass.prototype.anotherMethod = function(){};
// 2. 拷贝对象
function clone(obj){
return Object.assign({},obj);
// 此方法只能拷贝自身的值,不能拷贝继承的值
}
// 3. 合并多个对象
const merge = (target,...sources) => Object.assign(target,...sources);
复制代码
// 返回指定对象全部自身属性(非继承属性)的描述对象
const obj = {
foo:123,
get bar(){return 'abc'}
};
Object.getOwnPropertyDescriptors(obj);
// { foo:
// { value: 123,
// writable: true,
// enumerable: true,
// configurable: true },
// bar:
// { get: [Function: get bar],
// set: undefined,
// enumerable: true,
// configurable: true } }
复制代码
// 建立一个新对象,并指定新对象的 __proto__ 指向
// 语法 Object.create(proto); 第一个参数为新对象的原型指向
let obj1 = {a:1};
let obj2 = Object.create(obj);
obj2.a; // 1
复制代码
// 设置指定对象的原型对象,并返回当前对象
// 语法:Object.setPrototypeOf(object,prototype);
let obj1 = {a:1};
let obj2 = {b:2};
Object.setPrototypeOf(obj1, obj2);
obj1.b; // 2
复制代码
// 返回指定对象的原型对象
let obj = Object,getPrototypeOf(obj1);
obj {b:2};
复制代码
// Object.keys(obj)
// 返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历属性的键名
var obj = {foo:'bar',baz:44};
var arr = Object.kes(obj);
arr ['foo','baz'];
// Object.values()
// 返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历属性的属性值
var obj = {a:1,b:2};
var arr = Object.values(obj);
arr [1,2];
// Object.entries() 不支持IE
// 返回一个二维数组,每个数组项是参数对象自身的(不含继承的)全部可遍历属性
// 的键值对造成的数组,忽略 Symbol
var obj = {a:1,b:2};
var arr = Object.entries(obj);
arr [['a',1],['b',2]]
复制代码
// Object.fromEntries() 方法是 Object.entries() 的逆操做,
// 用于将一个键值对数组转换成一个键值对形式的对象
// 注:只兼容火狐浏览器
Object.fromEntries([
['foo', 'bar'],
['baz', 42]
])
// { foo: "bar", baz: 42 }
复制代码
/* 1. Symbol 值经过 Symbol()函数生成 2. Symbol 函数能够接受一个字符串做为参数,表示对Symbol实例的描述 3. Symbol 能够显式转换成字符串,布尔值,但不能转换成数字 */
let si = Symbol('foo')
console.log(si)// Symbol(foo)
/*用法?*/
let abc = Symbol('abc');
let obj = {
[abc]:'456',
'abc':'457',
}
复制代码
new Set() 生成的是Set的数据结构,其结构内不会有重复的值,是一个类数组对象
内部判断两个值是否相同使用的算法叫作“Same-value-zero equality”,相似于 === 比较,可是该算法中 NaN与NaN相等
let arr = [1,1,2,2,3,3]
const a = new Set();
arr.forEach(x=>a.add(x));
for(let i of a){
console.log(i)
}//1 2 3 4
//1. Set函数能够接受一个数组或具备iterable接口的其余数据结构做为参数
例一:数组为参数
const set = new Set([1,2,3,4,5,6]);
[...set] // [1,2,3,4,5,6]
例二:具备iterable接口的伪数组做为参数
const set = new Set(document.querySelectorAll('div'));
set.size; // 110
//2. 数组去重
var arr = [1,2,3,1,1,2,3,4];
[...new Set(arr)]; // [1,2,3,4]
//3. 字符串去重
var str = '123132451234561321';
[...new Set(str)].join(''); // "123456"
//4. NaN
var [a,b] = [NaN,NaN];
let set = new Set();
set.add(a);set.add(b);
[...set]; // [NaN]
//5. 并集,交集,差集
let a = new Set([1,2,3]);
let b = new Set([2,3,4]);
// 并集
[...new Set(...a,...b)]; //[1,2,3,4]
// 交集
[...new Set([...a].filter(x=>b.has(x)))]; //[2,3]
// 差集
[...new Set([...a].filter(x=>!b.has(x)))]; //[1]
// Set 结构的实例属性
Set.prototype.constructor :构造函数,默认就是Set函数
Set.prototype.size :返回 Set 实例的成员总数
// Set 结构的实例方法
// 1> 操做方法
.add(value) :添加某个值,返回Set结构自己
.delete(value) :删除某个值,返回一个布尔值,表示删除是否成功
.has(value) :判断是否存在这个值,返回一个布尔值
.clear() :清除全部的成员,无返回值
// 2> 遍历方法、
.keys() :返回键名的遍历器
.value() :返回键值的遍历器
.entries() :返回键值对的遍历器
.forEach() ;使用回调函数遍历每一个成员
// 因为 Set 结构没有键名(或者说键名和键值是同样的),因此keys() 和 values() 方法获得的结果同样
var arr = [1,2,3];
let set = new Set();
for (let item of set.entries()) {
console.log(item); // [1,1] [2,2] [3,3]
}
// Set 结构的实例默认是可遍历的,默认遍历器生成函数就是它的values方法
// 因此能够直接省略values方法,直接用 for...of遍历
for (let item of set) {
console.log(item); // 1 2 3
}
复制代码
1. 与Set相似,也是不重复的值的集合,可是WeakSet的成员只能是对象 2. WeakSet为弱引用,即:垃圾回收机制不计算WeakSet对该对象的引用次数。因此,WeakSet适合存储一些临时数组,当该数组在外部引用此时为0时,他在WeakSet中的引用就会自动消失 3. 因为成员是弱引用,随时会消失,因此ES6规定WeakSet不可遍历 4. 该构造函数能够接受一个数组,或者一个类数组(具备 Iterable 接口)对象,该数组的成员会自动转换成WeakSet实例对象的成员
// WeakSet结构的三个方法
-WeakSet.prototype.add(value);
-WeakSet.prototype.delete(value);
-WeakSet.prototype.has(value);
let arr = [[1,2],[2,3]];
var weak = new WeakSet(arr);
// {[1,2],[2,3]}
复制代码
1. js对象本质上是键值对的集合,可是传统上只能用字符串做为键,因此限制性大,所以ES6提供了一种新的数据结构,相似对象,也是一个键值对的集合,但键名能够是任意类型
// 实例的属性和操做方法
.size //放回Map结构的成员总数
.set(key,value) //添加或者更新一组键值对,返回整个Map数据结构
.get(key) //返回指定键的值,若不存在,则返回undefined
.has(key) //判断是否存在指定键,返回布尔值
.delete(key) //删除指定键
.clear(key) //删除全部的键,无返回值
// 遍历方法---遍历顺序就是插入顺序
keys():返回键名的遍历器。
values():返回键值的遍历器。
entries():返回全部成员的遍历器。
forEach():遍历 Map 的全部成员。
// 默认的遍历器接口为entries()
// 1. 基本使用方法
let map = new Map();
let m = {a:'1'};
map.set(m, 'content');
map.get(m); // content;
map.has(m); // true;
map.delete(m); // true;
map.has(m); // false
// 2. 能够接受一个双成员的二维数组,或者具备Iterable接口,且每一个成员都是一个双元素的类数组对象做为参数
let map2 = new Map([['a',1],['b',10]]);
map2.get('a'); // 1
map2.get('b'); // 10
// 使用Set 和 Map 实例做为参数
const set = new Set([
['foo', 1],
['bar', 2]
]);
const m1 = new Map(set);
m1.get('foo') // 1
const m2 = new Map([['baz', 3]]);
const m3 = new Map(m2);
m3.get('baz') // 3
// 3. 读取一个未知键,则返回undefined
new Map().get('a'); // undefined
// 4. 在Map中 NaN与NaN相等
let mp = new Map();
mp.set(NaN,'1');
mp.set(NaN,'2');
mp.get(NaN); // 2
复制代码
WeakMap结构与Map结构相同,也是用于生成键值对的集合 1. 只接受键名做为键名,2. 键名所对应的值不计入垃圾回收机制
// 通常用于对象在未来会消失,这样这个对象所对应的键值也会被回收,不须要手动回收
let myElement = document.getElementById('logo');
let myWeakmap = new WeakMap();
myWeakmap.set(myElement, {timesClicked: 0});
myElement.addEventListener('click', function() {
let logoData = myWeakmap.get(myElement);
logoData.timesClicked++;
}, false);
// 当DOM元素被删除时,WeakMap中该对象所对应的键值对也会自动删除
// 操做方法
.set()
.get()
.has()
.delete()
复制代码
一种异步解决的方案,一个容器,保存着将来某个时间段某个异步操做的结果
特色: 1. promise对象的状态不受外界所改变,它表明着一种异步操做,有三种状态:pending(进行中),fulfilled(成功),rejected(失败),只有结果才能获取是哪种状态 2. 状态一旦改变一次,就不可再次更改,状态改变只有两种:pending--fulfilled,pending--rejected。只要这两种情况发生,状态就定型了,这是就称为resolved(已定型)
缺点 1. 没法取消,一旦新建就会当即执行,没法中途取消 2. 若是不设置回调函数,promise内部出现的错误不会反应到外部 3. 当处于pending状态时,不知道目标是处于那一阶段(刚开始or已完成)
// 基本使用:
const promise = new Promise(function(resolve, reject){
// 异步代码...
if('异步成功时'){
resolve();//成功的回调函数调用
}else{
reject();//失败的回调函数调用
}
})
promise.then(callback1,callback2);
//.then()方法用于绑定该对象结果的两个阶段所对应的回调函数
//.then()方法会在当前脚本全部同步任务执行完后才会执行
//若是第一个.then()方法中返回的是一个promise对象,
// 那么第二个.then()方法会等待第一个的状态改变时再来判断是否执行
promise.then().catch(callback)
//.catch()方法:当异步操做抛出错误或者回调函数运行出错时会被被该方法捕获
//若是promise的状态已经为成功状态,那么再抛出异常就会无效
复制代码
// 用于指定无论promise对象最后的状态如何,都会执行的操做
promise.then(result => {...})
.catch(error => {...})
.finally(()=>{...})
// 本质是then()方法的特例,等同于
.then(result => {},error => {}) //成功或者失败的方法各写一遍
// 例:请求完后关闭服务器
promise.then().finally(server.stop);
复制代码
// 用于将多个Promise实例,包装成一个新的Promise实例,并返回
const p = Promise.all([p1, p2, p3]);
/* 接受一个数组做为参数,数组中的每个成员都是一个Promise实例 p的状态由 p1,p2,p3决定, 当3个都为fulfilled时,p的状态才为fulfilled,此时p1,p2,p3的返回值会组成一个数组传递给p的回调函数 当其中一个为reject时,p的状态为rejected,此时第一个rejected状态的实例的返回值会传递给p的回调函数 注意:若做为参数的promise实例本身定义了catch方法,那么就不会触发Promise.all()所定义的catch() */
复制代码
// 用于将多个Promise实例,包装成一个新的Promise实例
const p = Promise.race([p1, p2, p3]);
/* 接受一个数组做为参数,数组中的每个成员都是一个Promise实例 当参数中某个Promise实例的状态率先发生改变时,p的状态也会发生改变,率先改变的返回值会传递给p的回调函数 */
// 指定时间内没有得到结构就返回rejected
var p = Promise.race([p1,
new Promise((res,error)=>{
setTimeout(()=>{error();},5000);
})]);
p.then().catch(); // 第一个参数5秒内没有执行成功就抛出失败
复制代码
将现有对象转换成一个Promise对象
const ps = Promise.resolve(对象)
// 当参数是一个thenable对象,即:具备then()方法的对象时,转换完后会当即执行该方法
// 当参数不是具备then()方法的对象,或根本不是一个对象时,该方法会自动生成一个新的Promise对象,状态为
// 成功状态,并把参数传递给相对应的对调函数
// 当无参数时,该方法会自动建立一个新的Promise对象,状态为成功状态
复制代码
返回一个新Promise实例,状态为rejected,并当即执行回调函数
//注:与resolve()不一样的是reject()方法会把建立时的参数原封不动的传递给回调函数
复制代码
为了方便无论是同步仍是异步都用promise管理代码
是一种接口,为不一样的数据结构提供一种统一的访问机制,任何数据只要部署了Iterator接口均可以完成遍历操做
遍历过程:
ES6 规定,默认的 Iterator 接口部署在数据结构的Symbol.iterator
属性,这个属性是一个函数表达式,执行它就会返回一个遍历器 for...of循环会调用Symbol.iterator属性,返回返回对象中的value值
// 模拟next()方法
function makeIterator(obj){
let nextIndex = 0;
return {
next:()=>{
return nextIndex < obj.length ?
{value:obj[nextIndex++], done:false}:
{value:undefined, done:true}
}
}
}
var arr = [1,2,3];
var obj = makeIterator(arr);
obj.next(); //{value:1}
obj.next(); //{value:2}
obj.next(); //{value:3}
obj.next(); //{done:true}
复制代码
Array
Map
Set
String
TypedArray
函数的 arguments 对象
NodeList 对象(相似数组的对象)
// 例:调用数组的 Symbol.iterator属性
var arr = [1,2]
var iter = arr[Symbol.iterator]()
// Symnol值要用[]括起来
iter.next(); // {value:1, done:false}
iter.next(); // {value:1, done:false}
iter.next(); // {value:undefined, done:false}
复制代码
1. 解构赋值
var arr = new Set().add(1).add(2).add(3)
var [x,y] = arr // x:1 y:2
var [first,...rest] = arr //first:1 rest:[2,3]
2. 扩展运算符
var arr = "hello"
[...arr] // ['h','l','l','o']
3. 特殊的类数组对象:
例:querySelectorAll()
例:
var arrayLike1 = {
0: 'a',
1: 'b',
length: 2,
[Symbol.iterator]: Array.prototype[Symbol.iterator]
// 须要具备Symbol.iterator属性
};
// 报错
for (let x of arrayLike1) {
console.log(x);
}
复制代码
-for...of
-Array.from()
-Map(),Set(),WeakMap(),WeakSet()
-Promise.all()
-Promise.race()
复制代码
/* 遍历器除了具备next()方法,还具备return()方法和throw()方法 当for...of循环提早退出(出错时 或 break语句),就会调用 return 方法 注意:return方法必须返回一个对象,这是Generator规格规定 */
function readLinesSync(file) {
return {
[Symbol.iterator]() {
return {
next() {
return { done: false };
},
return() {
file.close();
return { done: true };
}
};
},
};
}
// 状况一
for (let line of readLinesSync(fileName)) {
console.log(line);
break;
}
/* 当执行break方法后就会执行遍历器的return()方法 */
// 状况二
for (let line of readLinesSync(fileName)) {
console.log(line);
throw new Error();
}
/* 状况二在执行return方法关闭文件以后,再抛出错误 */
复制代码
// 1. function关键字与函数名的中间用 * 号链接
// 2. 函数体内部用 yield 表达式来表示不一样的状态
// 3. 调用Generator函数后返回一个遍历器对象,即:指针对象,注:此时Generator函数内部代码尚未执行
// 4. 遍历器对象使用.next()方法进行执行函数体代码,直到遇到 yield 表达式 或 return 语句中止
// 5. 遇到yield表达式时next()方法返回一个对象,{value:当前yield表达式的值, done:布尔值(当前遍历的状态)}
// 6. yield 关键字至关于一个暂停符,.next()方法就为恢复执行
// 7. 返回的遍历器对象不是this对象
// 8. 遍历器对象能够调用函数原型上的方法
function* hello(){
console.log(1)
field 'a'
console.log(2)
field 'b'
console.log(3)
return 'c'+'d'
console.log(4)
}
var hl = hello()
hl.next() // 1 {value:a, done:false}
hl.next() // 2 {value:b, done:false}
hl.next() // 3 {value:cd, done:true} 遇到return时 done的值就为 true
hl.next() // {value:undefined, done:true} // 由于上一句已经return了,因此4不会被输出
复制代码
// 1. yield 表达式自己是没有返回值的,或者说老是undefined
// 2. next()方法能够带一个参数,该参数就会被看成上一个yield表达式的返回值
// 3. 所以第一个调用.next()方法里面传参是无效的,V8引擎会直接忽略第一次调用的参数
// 4. 调用函数后需调用一次next()方法来启动Generator函数的内部代码
function* f() {
for(var i = 0; true; i++) {
var reset = yield i;
if(reset) { i = -1; }
}
}
var g = f();
g.next() // { value: 0, done: false }
g.next() // { value: 1, done: false }
g.next() // { value: 2, done: false }
g.next(true) // { value: 0, done: false }
// 前三次执行时,reset为undefined,第四次执行时,next()方法传了一个参数true,
// 因此yield表达式的,返回值就为true,i=1,i++就为0
// 此特性能够在特定阶段从函数外部向内部传入值
function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }
复制代码
// for ... of 循环能够自动遍历Generator函数时所生成的iterator对象
// ----------------------------------------------------------
for in // 遍历的是数组的索引--即键名
---遍历时会包括数组的原型属性和方法,因此通常用来遍历对象而不是数组
---用 arr.hasOwnPropery(属性) 方法可判断该属性是否是该对象的实例属性
---数组的键名是数字时,for..in循环会转换成字符串获取
---某些状况下,遍历顺序是任意的
for of // 遍历的是数组的元素值
---遍历时不包括数组的原型属性和方法
---遍历数组时只返回具备数字属性的值
// 例:实现斐波那锲数列
function* fbnq(){
let [a,b] = [0,1]
for(;;){
yield b
[a,b] = [b,a+b]
}
}
for(var n of fbnq()){
if(n>1000) break
console.log(n)
}
复制代码
// 调用遍历器对象的return()方法后返回对象中的value值就是return()方法的参数,而且done的值为true
// 此时,Generator函数的遍历就会中止,若是无参数,则value值为undefined
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next() // { value: 1, done: false }
g.return('foo') // { value: "foo", done: true }
g.next() // { value: undefined, done: true }
复制代码
// 用于在一个Generator函数中调用另一个Generator函数
// yield* 表示返回的是一个遍历器对象,若不加js不会自动识别,会输出这个对象
// 无 return 语句时
function* foo(){
yield 'a'
yield 'b'
}
function* bar(){
yield 'x'
yield* foo()
yield 'y'
}
for(let n of bar()){
console.log(n) // 'x' 'a' 'b' 'y'
}
// 有 return 语句时,能够用一个变量来接收 field* foo 表达式的返回值
function* foo(){
yield 'a'
yield 'b'
return 'c'
}
function* bar(){
yield 'x'
let a = field* foo()
console.log(a)
yield 'y'
}
for(let n of bar()){
console.log(n) // 'x' 'a' 'b' 'c'y'
}
// 例:利用yield* 命令遍历取出二维数组
function* iterTree(tree) {
if (Array.isArray(tree)) {
for(let i=0; i < tree.length; i++) {
yield* iterTree(tree[i]);
}
} else {
yield tree;
}
}
const tree = [ 'a', ['b', 'c'], ['d', 'e'] ];
for(let x of iterTree(tree)) {
console.log(x);
}
or [...iterTree(tree)]
复制代码
let obj = {
* myGeneratorMethod(){} // myGeneratorMethod: function* (){}
}
复制代码
var clock = function* () {
while (true) {
console.log('Tick!');
yield;
console.log('Tock!');
yield;
}
};
复制代码
// 传值调用:参数为表达式时,表达式在进入函数体以前就已经计算完成
// 传名调用:参数为表达式时,表达式只有在函数体中使用到时才进行计算
Thunk 函数的定义:将一个参数放到一个临时函数内,再把临时函数当参数传入函数体中,
这个临时函数就是Thunk函数
复制代码
// 1. 语法与 Generator 函数类似
var asyncRead = async function(){
const f1 = await f1()
}
// 1. 返回一个promise对象
// 2. 有两个关键字 async await 分别对应 * yield
// 3. async 函数内置执行器,即:不须要像Generator函数须要.next()方法执行
// 4. await命令后面能够是promise对象和原始数据类型(可是这时会当即自动转换成resolved 的 promise对象)
// 5. async函数内部return 语句返回的值会成为then方法回调函数的参数
// 6. async函数内部抛出错误会直接返回的Promise对象的变成reject状态,而后被catch捕获
// 7. 当遇到第一个await时,后面的代码都会被放入队列中执行
// 8. 只有当await后面的promise对象执行完后,他的状态才会改变
// 9. 只用当async函数内部的全部异步操做执行完后才会执行then方法
// 10 若将异步操做放到try...catch里面,则该异步操做不管是否成功,后面的异步操做都会继续执行
复制代码
// 1. 顺序触发
async function myFunction() {
await getFoo()
await getBar()
} // 只用getFoo()执行完后 getBar()才会执行
// 2. 同时触发
async function myFunction() {
var fooPromise = getFoo()
var barPromise = getBar()
await fooPromise
await barPromise
// 此时就至关于两个异步函数的执行结果被await拦截了
}
async function myFunction() {
var [foo,bar] = await Promise.all([getFoo(),getBar()])
}
复制代码
// Class 类的基本使用
class Point{
constructor() {
// 实例属性
this.name = 2
}
// 原型对象上的实例方法
toString() {}
// 静态属性
static a = '41'
// 静态方法
static show(){ }
}
var p = new Point()
p.toString()
// 1. 使用方法与构造函数相同
// 2. 方法之间不须要用逗号分隔
// 3. 类中的全部方法其实是定义在 类名的prototype上
即等同于:Point.prototype = {
constructor(){},
toString(){}
}
因此类的实例调用方法其实就是调用原型上的方法
// 4. 类中的全部的方法都是不可枚举的
Object.keys(Point.prototype) //[]
// 5. 类没有变量提高
// 类名表达式
var cls = class Me{}
var cls = class {}
var cls = new class {} // 这样就能够直接调用class里面的方法了
复制代码
// 1. 每一个类在建立的时候必须有一个constructor()方法
// 2. 若是没有显示建立,则系统会默认建立一个
// 3. 该方法会在 new 命令后自动调用,默认返回实例对象,即:this,也能够改写此属性,返回另外一个对象
class Point {
z = 0;
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ','this.z+')';
}
}
var p = new Point(1,2)
p.toString() // (1,2)
复制代码
// 在类的内部经过 set get 关键字来拦截某个属性的存取值的操做
// 调用时不能加括号,当表达式调用
class MyClass{
set prop(val){
this.val = val
console.log(this.val+'a')
}
get prop(){
console.log(this.val)
}
}
var myclass = new MyClass()
myclass.prop = 1 // 注意,此时没有加小括号 '1a'
myclass.prop 1
复制代码
// 继承
class Bar{}
class aaa extends Bar {
constructor(){
super(); // 该关键词的做用是调用父类的constructor方法,子类中必须写,
// 不然建立实例时报错---重写constructor()时
// 做为对象时表明指向父类的原型对象,在静态方法中,指向父类
// 由于指向的是原型对象,因此父类上实例的属性和方法,super访问不到
// 经过super调用父类上方法中的this表明的是当前子类的实例
}
}
// super()当函数时使用
class A {
constructor(name,age){
this.name = name
this.age = age
}
say(){
console.log(this.name,this.age)
}
}
class B extends A{
constructor(...args){
super(...args) // 分配内存空间,指向this,同时将父类的属性挂载到this上
// super时父类构造器的一个引用,调用super就是调用父类的构造函数
// super前不能使用this
}
}
const b = new B('xy', 18)
// super当对象时使用
class A {
p() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.p()); // 2
}
}
let b = new B();
复制代码
// name属性
class Bar{}
Bar.name // 'Bar'
// this
class 中的 this 是指向当前实例 // static // 当一个方法名前加了static关键词时,该方法就不会被实例所继承,但能够被他的 子类 继承 class Bar{
static add(){this}
// 注意:其中的this是指类,而不是指实例
}
// 静态属性的定义
class Bar{
}
Bar.a = 1 //注意,写在外面
复制代码
// 该方法能够从子类上获取父类
Object.getPrototypeOf(子类名) === 父类名
// 能够用该方法来判断一个类是否继承了另外一个类
复制代码