es6笔记

142 阅读5分钟

根据阮一峰es6教程所做的笔记:

  • babel是js的转码器,可以将es6代码转为es5代码
  • babel配置文件,用来设置转码规则和插件
{
"presets": [],
"plugins": []
}
  • babel只转换js的句法(syntax),不转换新的api,如es6数组增加的方法Array.from()就不会转码,要是想使用这个方法,必须给使用环境添加垫片

let/const

let声明的变量只在它所在的代码块中有效(块级作用域)

for循环中设置循环变量的作用域(父作用域)跟循环体内部每次循环的作用域(子作用域)不同

for (let i = 0; i < 5; i++) {
let i = 'a';
console.log(i);
}

上述中循环变量i跟循环体中的变量i不同作用域

let声明的变量不存在变量提升,所以在块级作用域中,使用某变量时,若该变量未声明则报ReferenceError,在代码块中声明变量前的区域就叫暂时性死区(temporal dead zone)

function () {
var i = 10;
if (true) {
i = 100; // ReferenceError
typeof i; // ReferenceError
let i = 1;
}
}

typeof由于暂时性死区也有可能在运行时抛出ReferenceError,而一个变量若没有被声明,使用typeof返回不会报错,返回字符串undefined

function test (x = y, y = 2) {
return [x, y];
}

test()时则会抛出ReferenceError,因为未传参,y未声明,属于死区,test(1)则不会报错

function test (x = 2, y = x) {
return [x, y];
}

test()不报错

在同一个作用域中,不可以使用let重复声明同一个变量,当然也不同在函数体中重复声明函数参数

块级作用域中不建议声明函数,因为不同的环境可能会导致报错,如果需要声明,则使用函数表达式,并且块级作用域使用大括号

if (true) {
function test () {} // 建议不要使用
}
if (true) {
let test = function () {};
}

const定义的是只读的常量,无法修改,声明的时候必须初始化,不可以重复声明,变量不提升,存在暂时性死区,作用域同let一致 const保证的是变量指向的那个内存地址所保存的数据不可修改,简单类型的数据,值就保存在那个内存地址,所以const声明就是常量;而复合类型的变量(主要包括对象、数组),变量指向的内存地址上保存的只是指向实际数据的指针,const保证这个指针是固定的,但指针指向的数据结构可能会发生改变

const obj = {};
obj.name = 'li';
obj = {}; // TypeError

拓展:要是想将一个对象冻结,则应该使用Object.freeze()

const obj = Object.freeze({});
obj.name = 'li'; // 常规模式下不报错,严格模式下报TypeError

拓展:将一个对象彻底冻结,包括它的属性

function constantize (obj) {
	Object.freeze(obj);
	Object.keys(obj).forEach(key => {
		if (typeof obj[key] === 'object') {
			constantize(obj[key])
		}
	})
}

拓展:es6声明变量的方法有6种:var、function、let、const、import、class

var在非函数中声明的变量是全局对象,但也是顶层对象的属性,浏览器中是window的属性,node中是global的属性 let声明的变量若不在某个代码块中,则是全局对象,但不是顶层对象的属性

解构

解构:按照一定模式,从对象或数组中提取值,对变量进行赋值,这就叫解构(destructuring)

let [a, , c, [[d], e], ...z] = [1, 2, 3, [[4, 5, 6], 7, 8, 9], 10, 11, 12, 13];

若解构不成功,即没有在数组中匹配到该位置上的值,则该变量为undefined,z为[]

let [a, b, ...z] = [1];

还有种解构叫不完全解构,只匹配右边数组中部分的元素

let [a, , b] = [1,2,3,4,5];

若右边是不可遍历的结构(不具备Iterator接口),会报错

let [ a, b ] = true;

Set对象可以使用数组解构

const [ a, b ] = new Set([1,2,3,4]);

拓展:Generator函数原生具有Iterator接口,可以采用数组形式结构,这里略

解构默认值

let [ a, b = 10 ] = [1];

当b那个位置上的数组成员严格等于undefined时,默认值才会生效,为null都不生效

默认值可以引用解构赋值的其他变量

let [ x, y = x ] = [1,2,3];

对象解构赋值是按照同名属性匹配赋值的,解构失败依然等于undefined

let { a, b } = {a: 1, b: 2};

对象解构赋值可以方便地将对象的方法取出来

let { log: print } = console; // let { log: log } = console;

其实对象解构的全写形式是上述注释那种,重命名只需修改后者即可,前者是匹配的模式,而不是变量

对象解构取出来的值若为undefined,则不可以再取子属性

let { a: { b: myB } } = { name: 'li' }

对象解构赋值可以取到继承的属性

对象解构赋值指定默认值,默认值生效原则依然是取的属性值严格等于undefined

let { a = 10 } = {};
let { a: myA = true } = {};

将已经声明的变量进行解构赋值,需加()

let a;
({a} = { a: 10})

对数组进行对象属性的解构

let arr = [1,2,3];
let { 0: first, [arr.length - 1]: last } = arr;

字符串解构赋值,将字符串转换成类似数组的对象

let [a, b, c] = 'liqi';
let { length: len } = 'liqi';

对数字和布尔类型的变量解构感觉没啥意思

对null、undefined解构会报错,因为null、undefined无法转为对象

函数参数解构

function ([x, y = 10]) {
	return [x , y];
}

function test({x = 10, y = 101} = {}) {
	return [x, y];
}

test(); // []
test({}); // [10, 101]
test({x: true}); // [true, 101]


function test1({x, y} = {x: 10, y: 10}) {
	return [x, y];
}
test1(); // [10, 10]
test1({}); // [undefined, undefined]
test1({x: true}); // [true, undefined]

交换变量

let x = 10;
let y = 101;
[x, y] = [y, x];

字符串

未完待续