ES6介绍
ES6, 全称 ECMAScript 6.0 ,2015.06 发版。
let 和 const命令
let命令
let 命令,用来声明变量。它的用法类似于var,区别在于var声明的变量全局有效,let 声明的变量只在它所在的代码块内有效。
使用var声明:
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10
使用闭包解决:
) { ((i){ a[i] = () { console.log(i); }; })(i); } a[6](); 6
使用let:
for (let i = 0; i < 10; i++ 6
- let 不存在变量提升,必须先声明后使用,否则报错;var存在变量提升,未声明前使用输出 undefined。
- let 存在暂时性死区,在代码块内,使用let命令声明变量之前,该变量都是不可用的。
- let 不允许重复声明。
const 命令
const 声明一个只读的常量。一旦声明,常量的值就不能改变。不能只声明不赋值。
const a = 10; a = 20; 报错 const b; 报错
const 的作用域与 let 相同。
if(true) { const num = 5; } console.log(num); 报错
const 声明对象,常量对象内存地址,因此对象本身可改,但是给常量重新赋值就会报错。
const obj = {}; obj.a = 'a'; obj = {}; 报错
块级作用域和函数作用域
ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。
第一种场景,内层变量可能会覆盖外层变量。
var tmp = new Date(); f() { console.log(tmp); if (false) { var tmp = 'hello world'; } } f(); undefined
第二种场景,用来计数的循环变量泄露为全局变量。
var s = 'hello'; var i = 0; i < s.length; i++) { console.log(s[i]); } console.log(i); 5
ES6的块级作用域
let实际上为 JavaScript 新增了块级作用域。
f1() { let n = 5; ) { let n = 10; } console.log(n); 5 }
块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。
IIFE 写法 ( () { var tmp = ...; ... }()); 块级作用域写法 { let tmp = ...; ... }
ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。
情况一 ) { f() {} } 情况二 try { f() {} } catch(e) { ... }
上面两种函数声明,根据 ES5 的规定都是非法的。
ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
function f() { console.log('I am outside!'); } ( 重复声明一次函数f function f() { console.log('I am inside!'); } } f(); }());
上面代码在 ES5 中运行,会得到“I am inside!”,因为在if内声明的函数f会被提升到函数头部,实际运行的代码如下。
ES5 环境 ); } ) { } f(); }());
ES6 就完全不一样了,理论上会得到“I am outside!”。因为块级作用域内声明的函数类似于let,对作用域之外没有影响。但是,如果你真的在 ES6 浏览器中运行一下上面的代码,是会报错的,这是为什么呢?
浏览器的 ES6 环境 ); } } f(); }()); Uncaught TypeError: f is not a function
上面的代码在 ES6 浏览器中,都会报错。
原来,如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大影响。为了减轻因此产生的不兼容问题,浏览器的实现可以不遵守上面的规定,有自己的行为方式。
注意,上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。
根据这三条规则,浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量。上面的例子实际运行的代码如下。
); } (var f = undefined; Uncaught TypeError: f is not a function
考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
另外,还有一个需要注意的地方。ES6的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。
第一种写法,报错 true) let x = 1 第二种写法,不报错 ) { let x = 1; }
上面代码中,第一种写法没有大括号,所以不存在块级作用域,而let只能出现在当前作用域的顶层,所以报错。第二种写法有大括号,所以块级作用域成立。
函数声明也是如此,严格模式下,函数只能声明在当前作用域的顶层。
不报错 报错 'use strict'; ) function f() {}
变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
数组的解构赋值
模式匹配赋值,如果解构不成功,变量的值就等于 undefined。
let [a,[[b],c]] = [1,[[2],3]]; console.log(a,b,c); 1,2,3 let [x,y,z] = [1,1)">]; console.log(x); 1 console.log(y); 3 console.log(z); undefined
不完全解构赋值,等号左边的模式,只匹配一部分的等号右边的数组。
let [x,[y],z] = [1,[2,3],4 2 console.log(z); 4
数组结构赋值右边必须是数组,模式不匹配则报错。
let [a] = {}; 报错
解构赋值可以添加默认值,并且可以引用解构赋值的其他变量。
let [a = 1,b = 2] = [,1)">]; console.log(a); 1 console.log(b); 3 let [x = 1,y = x] = []; x = 1; y = 1 let [x = 1,y = x] = [2]; x = 2; y = 2
数组解构赋值可用于交换变量的值。
let [a,b] = [1,2]; console.log(a,b); [a,b]; console.log(a,1)"> 2,1
对象的解构赋值
@H_533_403@变量必须与属性同名let { a,c } = { a: 'aaa',b: 'bbb' }; console.log(a); 'aaa' console.log(b); 'bbb' console.log(c); undefined
变量名与属性名不一致
let { a: x,b: y } = { a: 'aaa',1)"> }; console.log(x); 'aaa' console.log(y); 'bbb'
嵌套赋值,如果子对象所在的父属性不存在,会报错,慎用。
let { a,a: {x},b: y } = { a: {x: 'xxx',y: 'yyy'},b: "bbb" { x: 'xxx',y: 'yyy' } console.log(x); 'xxx' let {c: {d: {e}}} = {c: 'ccc'}; 报错 console.log(e)
字符串解构赋值
字符串解构赋值,将字符串转化成数组对象
const [a,c] = '123456789'; const {length} = '123456789'; console.log(a,c,length); 属性,因此还可以对这个属性解构赋值。let {length : len} = 'hello'; len 5函数参数解构赋值
add([x,y]){ return x + y; } add([1,2]); 3下面是另一个例子:
const arr = [[1,2],[3,4]].map(([a,b]) => a + b); console.log(arr); [ 3,7 ]函数参数的解构也可以使用默认值。
function move({x = 0,y = 0} = {}) { return [x,y]; } move({x: 3,y: 8}); [3,8] move({x: 3}); [0,0] move(); 上面代码中,函数move的参数是一个对象,通过对这个对象进行解构,得到变量x和y的值。如果解构失败,x和y等于默认值。注意,下面的写法会得到不一样的结果。
function move({x,y} = { x: 0,y: 0 }) { [undefined,undefined] move(); 代码是为函数move的参数指定默认值,而不是为变量x和y指定默认值,所以会得到与前一种写法不同的结果。字符串扩展
for...of 遍历字符串
for(let codePoint of 'string'){ console.log(codePoint) } 's' // 't' 'r' 'i' 'n' 'g'includes(),startsWith(),endsWith()
三个方法都接收两个参数,第一个参数为检索的值,第二个参数为检索的起始位置,返回布尔值
let s = 'Hello world!'; const [a,c] = [ s.startsWith('Hello',1)">),s.endsWith('!') ]; console.log(a,1)"> false true truerepeat()
repeat 方法返回一个新字符串,表示将原字符串重复 n 次。
- 参数为[-Infinity,-1]或者 Infinity,会报错;
- 参数为(-1,1)时,相当于参数为 0;
- 参数为小数时向下取整;
- 参数 NaN 等同于 0;
- 参数是字符串,则会先转换成数字。
'str'.repeat('3') 'strstrstr'
padStart(),padEnd()
padStart(),padEnd()有两个参数,第一个参数为字符串补全生效的最大长度,第二个参数为补全的字符串。
第二个参数默认为空格,省略第二个参数时默认用空格补全。
第一个参数小于字符串原长度时,返回原字符串。
如果用来补全的字符串与原字符串,两者的长度之和超过了最大长度,则会截去超出位数的补全字符串。
常见用途:补全指定位数,提示字符串格式。
'123456'.padStart(10,'0') "0000123456" '09-12'.padStart(10,'YYYY-MM-DD') "YYYY-09-12"模版字符串(``)
const str = 'world'; const template = `Hello ${str}`; console.log(template); Hello world数值扩展
二进制、八进制表示法
使用二进制表示法,前缀为 0b,使用八进制表示法,前缀为 0o,ES6 不支持使用 00 前缀表示八进制。
进制转换使用 toString 方法,使用 Number 方法直接转十进制。
0b1100100 === 100; true 0o144 === 100; true (0b1100100).toString(8); 144 (0b1100100).toString(10); 100 Number('0b1100100'); 100Number.isFinite(),Number.isNaN()
Number.isFinite()用来检查一个数值是否为有限的(finite),即不是 Infinity。参数类型不是数值,Number.isFinite 一律返回 false。
Number.isNaN()用来检查一个值是否为 NaN。参数类型不是 NaN,Number.isNaN 一律返回 false。
Number.isFinite(15); true Number.isFinite(-Infinity); false Number.isNaN(15) false Number.isNaN(9/0) // trueNumber.parseInt(),Number.parseFloat()
ES6 将全局方法 parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。
Number.isInteger()
Number.isInteger()用来判断一个数值是否为整数。
Number.isInteger(25) true Number.isInteger(25.0) true Number.isInteger(25.1) false
- Number.EPSILON 极小常量,浮点数误差小于这个值可以认为不存在误差;
- Number.MAX_SAFE_INTEGER 安全整数的最大范围;
- Number.MIN_SAFE_INTEGER 安全整数的最小范围;
- Number.isSafeInteger() 用来判断一个整数是否落在安全整数范围之内。
Number.isSafeInteger(9007199254740993) false Number.isSafeInteger(990) true Number.isSafeInteger(9007199254740993 - 990) trueMath 对象的扩展
Math.trunc() 除去一个数的小数部分,返回整数部分。参数不是数值,内部会先调用 Number()专为数值,对于空值和无法截取整数的值,返回 NaN。(Math 对象的扩展的方法对于非数值的处理方法都一样)
Math.trunc(5.9) 5 Math.trunc(-4.9) -4 Math.trunc(null) 0 Math.trunc('foo'); NaNMath.sign() 判断一个数是正数、负数、还是零。
Math.sign(-5) -1 负数 Math.sign(5) +1 正数 Math.sign(0) +0 零 Math.sign(-0) -0 零 Math.sign(NaN) NaNMath.cbrt() 计算一个数的立方根。
Math.cbrt(2) 1.2599210498948734 Math.sqrt(x) 计算平方根 Math.sqrt(2) 1.4142135623730951 幂运算 Math.pow(x,y) Math.pow(2,3)Math.hypot() 返回所有参数的平方和的平方根。
Math.hypot(3,4); 5 Math.hypot(3,4,5); 7.0710678118654755函数扩展
rest 参数
ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。只能是最后一个参数,函数的 length 属性,不包括 rest 参数。
sum1(x,...args) { let sum = 0; for (let arg of args) { sum += arg; } sum; } console.log(sum1(1,4)) 7 sum2(...args) { return args.reduce((prev,curr) => { return prev + curr },0) } console.log(sum2(1,3)); 6name 属性
函数的 name 属性,返回该函数的函数名。对于匿名函数,ES5 返回' ',ES6 返回变量名; Function 构造函数返回的函数实例,name 属性的值为 anonymous;bind 返回的函数,name 属性值会加上 bound 前缀。
fn() {} fn.name 'fn' foo() {}; foo.bind({}).name 'bound foo' (new Function).name "anonymous" function(){}).bind({}).name 'bound '箭头函数
const fn = v => v; 等同于 const fn = (v) { v; };注意要点
- 函数体内的 this 对象,就是定义时所在的对象,而不是使用时所在的对象;
- 不可以当作构造函数,即不可以使用 new 命令,否则会抛出一个错误;
- 不可以使用 arguments 对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替;
- 不可以使用 yield 命令,因此箭头函数不能用作 Generator 函数。
数组扩展
扩展运算符
扩展运算符(spread)是三个点(...)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。
const arr = [1,1)">]; arr.push(...[4,5,6]);扩展运算符的应用:
- 数组展开
const arr = [1,1)">]; ...arr
复制数组 const a1 = [1,1)">]; 写法一 const a2 = [...a1]; 写法二 const [...a2] = a1; 相当于 const a1 = [1,1)">]; const a2 = a1.concat();
- 解构赋值,字符串转数组
const list = [1,1)">]; [a,...b] = list; console.log(a) 1 console.log(b) [2,3] [...'hello'] ['h','e','l','o']Array.from()
Array.from 方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。
常见的类似数组的对象有 DOM 操作返回的 NodeList 集合,以及函数内部的 arguments 对象。
let arrayLike = { '0': 'a','1': 'b'3 }; ES5的写法 var arr1 = [].slice.call(arrayLike); ['a','b','c'] ES6的写法 let arr2 = Array.from(arrayLike); Array.from('hello'); let namesSet = new Set(['a','b']); Array.from(namesSet); 方法,用来对每个元素进行处理,将处理后的值放入返回的数组。let arrayLike = { '0': 1'2': 3 }; Array.from(arrayLike,x => x * x); [ 1,9 ]Array.of()
Array.of 方法用于将一组值,转换为数组。这个方法的主要目的,是弥补数组构造函数 Array()的不足。因为参数个数的不同,会导致 Array()的行为有差异。
Array.of() [] Array.of(undefined) [undefined] Array.of(1) [1] Array.of(1,2) [1,2]copyWithin()
参数:
- target(必需):必需。复制到指定目标索引位置。
- start(可选):可选。元素复制的起始位置。
- end(可选):可选。停止复制的索引位置(默认为array.length)。如果为负值,表示倒数。
这三个参数都应该是数值,如果不是,会自动转为数值。
var result = [1,5].copyWithin(0,1)">) console.log(result)[4,5]find() 和 findIndex()
数组实例的 find 方法,用于找出第一个符合条件的数组成员,如果没有符合条件的成员,则返回 undefined。
findIndex 方法返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
[1,-5,10].find(n => n < 0); -5 [1,10].findIndex(n => n < 0); 2两个方法都可以接受第二个参数,用来绑定回调函数的 this 对象。
f(v){ return v > this.age; } let person = {name: 'John',age: 20}; [10,12,26,15].find(f,person); 26这两个方法都可以发现 NaN,弥补了数组的 indexOf 方法的不足。
fill() 填充数组
fill 方法使用给定值,填充一个数组。fill 方法可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象,改变数组中的一项,则所有项都改变。
let arr = Array.of(1,1)">).fill({ num: 20 }); console.log(arr); [ { num: 20 },{ num: 20 },{ num: 20 } ] arr[0].num = 10; console.log(arr); [ { num: 10 },{ num: 10 },{ num: 10 } ]entries(),keys() 和 values() 遍历数组
for (let index of ['a',1)">].keys()) { console.log(index); } 0 1 for (let elem of ['a',1)">].values()) { console.log(elem); } 'a' 'b' for (let [index,elem] of ['a',1)">].entries()) { console.log(index,elem); } 0 "a" 1 "b"includes()
includes 方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的 includes 方法类似。该方法的第二个参数表示搜索的起始位置,第二参数是负数,取它的倒数,第二参数大于数组长度,取 0。
[1,3].includes(3,-1); true
flat(),flatMap()
flat()默认只会“拉平”一层,如果想要“拉平”多层的嵌套数组,可以将 flat()方法的参数写成一个整数,表示想要拉平的层数,默认为 1。
flat()的参数为 2,表示要“拉平”两层的嵌套数组。如果不管有多少层嵌套,都要转成一维数组,可以用 Infinity 关键字作为参数。
[1,[3]]].flat(Infinity); 方法类似。[2,4].flatMap(x => [x,x * 2]); 相当于 [2,4].map(x => [x,x * 2]).flat(); 对象扩展属性简洁表示法
const a = 1; const b = 2; const c = {a,b}; 等同于 const c = {a: a,b: b}; const o = { method() { return "Hello!"; } }; 等同于 const o = { method: () { ; } }; f(x,y) { {x,y}; } 等同于 {x: x,y: y}; }对象的扩展运算符
对象扩展符类似数组扩展符,主要用于解构赋值。
let { x,...z } = { x: 1,y: 2,a: 3,b: 4 }; x 1 y 2 z { a: 3,b: 4 } let ab = { ...a,...b }; 等同于 let ab = Object.assign({},a,b);Object.is()
它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
Object.is('str','str'); true Object.is({},{}); false不同之处只有两个:一是+0不等于-0,二是NaN等于自身。
+0 === -0 true NaN === NaN Object.is(+0,-0) false Object.is(NaN,NaN) trueobject.assign()
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
由于undefined和null无法转成对象,所以如果它们作为首参数,就会报错。
const target = { a: 1,b: 1 }; const source1 = { b: 2,c: 2 }; const source2 = { c: 3 }; Object.assign(target,source1,source2); target {a:1,b:2,c:3}常见用途:
Object.keys(),Object.values(),Object.entries()
ES5 引入了Object.keys方法,返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
var obj = { foo: 'bar',baz: 42 }; Object.keys(obj) ["foo","baz"]Object.values方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
const obj = { foo: 'bar',1)"> }; Object.values(obj) ["bar",42]
const obj = { 100: 'a',2: 'b',7: 'c' ["b","c","a"]
上面代码中,属性名为数值的属性,是按照数值大小,从小到大遍历的,因此返回的顺序是b、c、a。
Object.values只返回对象自身的可遍历属性。
const obj = Object.create({},{p: {value: 42}}); Object.values(obj) []上面代码中,Object.create方法的第二个参数添加的对象属性(属性p),如果不显式声明,默认是不可遍历的,因为p的属性描述对象的enumerable默认是false,Object.values不会返回这个属性。只要把enumerable改成true,Object.values就会返回属性p的值。
const obj = Object.create({},{p: { value: 42 } }); Object.values(obj) [42]Object.entries()方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
const obj = { foo: 'bar',1)"> }; Object.entries(obj) [ ["foo","bar"],["baz",42] ]
除了返回值不一样,该方法的行为与Object.values基本一致。
Object.fromEntries()
Object.fromEntries()方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。
Object.fromEntries([ ['foo','bar'],['baz',42] ]) { foo: "bar",baz: 42 }原文链接:/es6/994414.html
猜你在找的ES6相关文章