常用的es6语法总结(一)

常用的es6语法总结

摘抄借鉴自阮一峰es6入门:http://es6.ruanyifeng.com/#docs/let

一、let和const

  1. 作用域问题
  2. 变量提升问题
  3. 顶层对象属性
let命令

var作用域为全局作用域
在全局范围内都有效,数组a的成员里面的 i,指向的都是同一个 i导致最后一轮i的值就是10

var a = [];
for (var i = 0;i<10;i++){
  a[i] = function (){
     console.log(i)
  }
}
a[6]();//10

let为块级作用域
当前i只在本轮循环中有效,每次循环的i都是一个新的变量


var a = [];
for (let i = 0; i<10;i++){
   a[i] = function(){
   console.log(i)
  }
}
a[6](); //6

let不存在变量提升

//var存在变量提升
console.log(foo);//输出undefined
var foo = 2;

//let不存在变量提升
console.log(bar);//输出ReferenceError
let bar = 2;

变量foovar声明会发生变量提升,开始运行时变量已经存在,但未赋值输出undefined;变量bar用==let声名时不会发生变量提升,声明之前变量不存在,所以会报错

let存在暂时性死区

var tmp = 123;
if(true){
tmp = 'abc';//ReferenceError 引用错误
let tmp;
}

var声明了一个全局变量tmp,但是块级作用域内let又声明了一个局部变量tmp,因为let在块级作用域内会变量会绑定这个区域,凡是在声明之前使用这些变量就会报错

let 不允许重复声明

//报错
function func(){
   let a = 10;
   var a = 1;
}
//报错
function func(){
   let a = 10;
   let a = 1;
}

function func(arg){
   let arg;
}
func()//报错
function func(arg){
 {
    let arg
 }
}
func()//不报错

不允许在相同作用域内重复声明同一个变量,不能在函数内部重新声明参数

const命令
const实际上保证的并不是变量的值不得改动,而是变量指向的内存地址所保存的数据不得改动。主要针对简单类型的数据(number、string、boolean),值就保存在内存地址中,等同于常量。对于复合类型(对象和数组),变量指向的内存地址只是一个指向实际数据的指针,只能保证指针是固定的,无法控制数据结构是否可变
const foo = {};
//foo指向一个对象,存储的是一个地址可以为它添加属性
foo.prop = 123;
foo.prop //123
//不能将它指向另一个对象,会报错,不能将它指向另一个地址。但对象本质是可变的
foo = {}//TypeError:"foo" is read-only foo是一个只读的
const a = [];
a.push('Hello');//为数组添加数据可以执行
a.length = 0;//设置数据的长度可以执行
a = ['Dave'];//将领一个数组的值赋给a,会报错

将对象冻结,会导致无法添加新属性,还可以将对象的属性冻结(Object.frerze

const foo = Object.freeze({});
foo.prop = 123;
//常规模式下,不起作用
//严格模式下,会报错
//还可以将对象本身冻结,对象的属性也应该冻结
var constantize = (obj) =>{
   Object.freeze(obj);
   Object.keys(obj).forEach((key,i) =>{
      if(typeof obj[key] === 'object'){
        constantize(obj[key]);
   }
 })
}

const声明一个只读的常量,一旦声明常量的值就不能改变

const PI = 3.1415926;
PI //3.1415926 使用const声明一个值之后,就不能发生改变否则会报错
PI = 3;//TypeError: Assignment to constant variable 常数变量分配

const只声明不赋值,会报错

const foo;//SyntaxEoor: Missing initializer in const declaration 常量声明中缺少初始值设定项
//const声明的变量不得改变值,const一旦声明变量,就必须立即初始化,不能留到以后赋值,否则会报错 

const作用域与let命令相同,只在声明的块级作用域内有效

if(true){
   const MAX = 5;
}
MAX //Uncaught ReferenceError:MAX is not defined MAX未定义

不提升,同样存在暂时性死区,只能在声明的位置后面使用

if (true){
  console.log(MAX);//RefernceError 引用错误
  const MAX = 5;//声明之前就调用,会报错
}

const声明的常量和let一样不可以重复声明

var message = "Hello!";
let age = 25;
const message = "Goodbye!";//报错 重复声明
const age = 30;//报错  重复声明
顶层对象属性

es5中顶层对象属性与全局变量挂钩

window.a = 1;
a;//1
a = 2;
window.a //2

es6中:var命令和function命令声明的全局变量,依旧是顶层属性;let,const,class命令声明的全局变量,不属于顶层对象的属性,全局变量将逐步与顶层对象的属性脱钩

var a = 1;
window.a;//1 由var声明,是顶层对象属性
let b = 1;
window.b //undefined 由let声明,不是顶层属性所以返回undefined
二、变量的解构赋值
基本用法

在es6中按照一定模式从数组和对象中提取值,对变量进行赋值被称为解构

let [a,b,c] = [1,2,3];
a //1
b //2
c //3
let [foo,[[bar],baz]] = [1,[[2],3]];
foo //1
bar //2
vaz //3
let [ , ,third] = ["foo","bar","baz"];
third //"baz"
let [x, , y] = [1,2,3];
x // 1
y // 3
let [head,...tail] = [1,2,3,4];
head //1
tail //[2,3,4]
let [x,y,...z] = ['a']
x //"a"
y //undefined
z // []
//这种写法属于模式匹配,只要等号两边的模式相同,左边的变量就会被赋予对应的值
let [foo] = [];//undefined
let [bar, foo] = [1];//undefined
//解构不成功时值会等于undefined
let [x,y] = [1,2,3];
x //1
y //2
let [a,[b],d] = [1,[2,3],4];
a //1
b //2
d //4
//不完全解构,等号左边的模式,只匹配一部分等号右边的数组,这种情况下依然解构成功
  • 如果等号右边不是数组,转为对象以后不具备Iterator接口,或本身不具备Iterator接口1
//报错
let [foo] = 1; //转为对象后不具备iterator接口
let [foo] = false; //转为对象后不具备iterator接口
let [foo] = NaN; //转为对象后不具备iterator接口
let [foo] = undefined; //转为对象后不具备iterator接口
let [foo] = null; //转为对象后不具备iterator接口
let [foo] = {}; //本身不具备iterator接口
//Set结构也可以使用数组的解构赋值
let [x,y,z] = new Set(['a','b','c']);
x // "a"
//只要某种数据结构具有iterator接口,都可以采用数组形式的解构赋值
function*fibs(){
  let a = 0;
  let b = 1;
  while (true){
   yield a;
   [a,b]= [b,a + b];
 }
}
let [first,second,third,fourth,fifth,sixth] = fibs();
sixth //5
//fibs是一个generator函数,原生具有iterator接口。解构赋值会依次从这个接口获取值
解构赋值允许指定默认值
let [foo = true] = [];
foo // true
let [x,y = 'b'] = ['a'];//x='a',y='b'
let [x,y = 'b'] = ['a',undefined];//x='a',y='b'
  • 注意: es6内部使用严格相等运算符(===),判断一个位置是否有值。只有当一个数组成员严格等于_undefined_,默认值才会生效
let [x = 1] = [undefined];
x // 1
let [x = 1] = [null];
x // null 因为null不严格等于undefined

如果默认值是一个表达式,表达式时惰性求值的,只有在用到的时候才会求值

function f(){
  console.log('aaa');
}
let [x = f()] = [1];//x可以取到值。函数f根本不会执行
//等价于⬇⬇⬇⬇⬇⬇
let x;
if([1][0] === undefined){
  x = f();
}else{
  x = [1][0];
}//默认值可以引用解构赋值的其他变量,但变量必须已经声明
let [x = 1,y = x] = [];// x=1;y=1
let [x = 1,y = x] = [2];//x=2;y=2
let [x = 1,y = x] = [1,2];//x=1;y=2
let [x = y,y = 1] = [];//ReferenceError : y is not defined y未声明
对象的解构赋值
  • 对象解构与数组的不同:数组按次序排列,变量的取值由位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值
let {foo,bar} = {foo:'aaa',bar:'bbb'};
foo // "aaa"
bar // "bbb"
let {baz} = {foo:'aaa',bar:'bbb'};
baz // undefined 没有对应的属性名取不到值,等于undefined
let {foo:baz} = {foo:'aaa',bar:'bbb'};
baz // "aaa"
let obj = {first:'hello',last:'world'};
let {first:f,last:l} = obj;
f // 'hello'
l // 'world'
//变量名和属性名不一致的情况下,可以⬆⬆⬆⬆⬆⬆⬆

对象的解构赋值内部机制,先找到同名属性,然后再赋给对应的变量,真正被赋值的时后者不是前者,真正的解构赋值的形式是⬇⬇⬇⬇⬇⬇

let {foo:foo,bar:bar} = {foo:'aaa',bar:'bbb'};
let {foo:baz} = {foo:'aaa',bar:'bbb'};
baz // "aaa" 
foo // error:foo is not defined
//foo是匹配的模式,baz才是变量,真正被赋值的变量

对象解构也可以用于嵌套结构的对象

let obj = {
 p:[
   'Hello',
   {y:'World'}
 ]
};
let {p, p:[x,{y}]} = obj;
x // "Hello"
y // "World"
p // ["Hello",{y:"World"}]
const node = {
  loc:{
   start:{
     line:1,
     column:5
   }
 }
};
let {loc,loc:{start},loc:{start:{line}}} = node;
line //1
loc // Object {start:Object}
start //Object {line:1,column:5}
//分别对loc、start、line三个属性的解构赋值,最后一次的解构赋值中,只有line是变量,loc和start都是模式,不是变量

嵌套赋值

let obj = {};
let arr = [];
({foo:obj.prop,bar:arr[0]} = {foo:123,bar:true});
obj // {prop:123}
arr // [true]

let {foo:{bar}} = {baz:'baz'}//报错
//对象foo属性对应一个子对象,这时解构时foo等于undefined,所以其子对象属性就会报错
const obj1 = {};
const obj2 = {foo:'bar'};
Object.setPrototypeOf(obj1,obj2);
const {foo} = obj1;
foo //"bar"
//对象的解构赋值可以取到继承的属性
对象的解构赋值也可以指定默认值
var {x = 3} = {};
x // 3
var {x,y = 5} = {x:1};
x // 1
y // 5
var {x:y = 3} = {};
y // 3
var {x:y = 3} = {x:5};
y //5
var {message:msg = 'Something went wrong'} = {};
msg // "Somthing went wrong"

var {x = 3} = {x:undefimed};
x // 3
var {x = 3} = {x:null};
x // null
//默认值生效的条件时对象的属性值严格等于undefined
  • 注意:1.将一个已经声明的变量用于解构赋值时,可以将整个解构赋值语句放在一个圆括号里
//例:
let x;
{x} = {x:1};//SyntaxError:syntax error

let x;
({x} = {x:1});
  • 解构赋值允许等号左边的模式,不放置任何变量名
({} = [true,false]);
({} = 'abc');
({} = []);
//语法合理可以执行
  • 数组属于特殊的对象,可以对数组进行对象属性的解构
let arr = [1,2,3];
let {0:first,[arr.length-1]:last} = arr
first //1
last //3
字符串的解构赋值
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
//解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
let {prop:x} = undefined;//TypeError
let {prop:y} = null;//TypeError
//undefined和null无法转为对象,所以对他们进行解构赋值会报错
函数参数的解构赋值
function add([x,y]){
  return x + y;
}
add([1,2]);//3
//函数add的参数表面上是数组,但传入参数后就解构成了变量x,y
[[1,2],[3,4]].map((a,b) =>a+b );
//[3,7]
function move({x = 0,y = 0} = {}){
  return [x,y];
}
move({x:3,y:8});//[3,8]
move({x:3});//[3,0]
move({});//[0,0]
move();//[0,0]
//函数move的参数是一个对象,通过对这个对象进行解构,得到变量x和y的值。如果解构失败,x和y等于默认值
function move({x,y} = {x:0,y:0}){
 return [x,y];
}
move({x:3,y:8});//[3,8]
move({x:3})//[3,undefined]
move({});//[undefined,undefined]
move();//[0,0]
//为函数move的参数指定默认值,不是为了变量x和y指定默认值
[1,underfined,3].map((x='yes')=> x);//[1,'yes',3]
//undefined会触发函数参数的默认值

  1. (简单来说就是实现了Iterator接口的对象能被foreach遍历,内部的vaild.current,key方法会一次被调用,返回值时key和value,终止条件根据vaild方法的返回而定,一次循环结束之后将调用next进行下一次循环)* ↩︎

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值