ES6语法学习总结


1.let和const

在ES6之前都是用var进行变量定义,但是var定义在程序编写的时候会有很多潜在的问题。

  1. 它可重复定义。var a = 10; var a = 20;
  2. 它不可控,意为可随意修改变量值。不像C和Java可以定义不可变量,甚至可以宏定义。
  3. var变量没有块级作用域。为函数级作用域。

紧接着ES6进行更新了,变量定义的新语法,let和const,二者的出现共同解决了var定义变量的三个大问题。

1. 变量重复声明问题; 2. 变量不可控问题

    let a= 12;
    let a= 15; //重复定义错误
	const data = 10;
	console.log(data);	//10
	//data = 100; 		//执行错误,常量不可重复定义
	但是若用常量去定义一个数组,可操作常量数组中的值,但是无法为常量数组赋值。对象操作类似。
	const list = [1, 2, 3];
	console.log(list);	//[ 1, 2, 3 ]
	list[0] = 10;
	console.log(list);	//[ 10, 2, 3 ]
	list.push(20);
	console.log(list);	//[ 10, 2, 3, 20 ]
	//list = [4,5,6]; //错误 常量不可重复赋值

3.块级作用域问题

	var arr = [];
	for (var i = 0; i < 10; i++) {
	  arr.push(function(){
	    console.log(i);
	  })
	}
	arr.forEach(item=> item())   // 10 10 10 10 10 10 10 10 10 10 

按照for循环的执行机制来说, 应该打印从0到9的数字,但是i的声明方式是var,在全局范围内都有效,所以全局只有一个变量i。每一次循环,变量i的值都会发生改变,而循环内被赋给数组a的函数内部的console.log(i),里面的i指向的就是全局的i。也就是说,所有数组a的成员里面的i,指向的都是同一个i,导致运行时输出的是最后一轮的i的值,也就是 10。
解决办法: 1. 利用闭包概念,将i包在函数身上。2. 利用let进行变量声明

	var arr = [];	
	for (var i = 0; i < 10; i++) {
	    arr.push((function () {
	        console.log(i);
	    })(i))
	}
	arr.forEach(item => item())	// 0 1 2 3 4 5 6 7 8 9
	闭包之后可以实现预期输出,但是程序编写略显麻烦,下面用let进行变量声明
	var arr = [];
	for (let i = 0; i < 10; i++) {
	    arr.push(function () {
	        console.log(i);
	    })
	}
	arr.forEach(item => item()) // 0 1 2 3 4 5 6 7 8 9
	分析:变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以
	最后按顺序输出。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而
	计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在
	上一轮循环的基础上进行计算。
总结一下:var变量可重复声明,可以被修改,函数级作用域;let 不能重复声明,可以被修改,块级作用域;
const 不能重复声明,不可以被修改,块级作用域; 放弃var用let,const使用看情况。

但是let有暂时性死区问题

        var a = 10;
        function name(params) {
            console.log(a);
            let a = 20;
        };
        name();

输出a,浏览器会报错,这就是let的暂时性死区。只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
在这里插入图片描述


2.解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。

  1. 两边的结构必须一样,不能等式一边是数组一边是JSON之类不对等的解构。
  2. 等式右边必须是正确的结构,类似{12, 15}; [ "name":"不良菜", “age”: 18]等 奇奇怪怪的表达式无法进行解构。

数组解构赋值

let arr = [1, 2, 3, 4, 5]
let [a, b, c] = arr;
console.log(a, b, c); // 1 2 3 4 5 
通过剩余运算符
let [x, y, ...other] = arr;
console.log(x, y, other); //1 2 [ 3, 4, 5 ]

对象解构赋值

let json= { name: '不良菜', age: 20 };
let {name, age} = json;
console.log(name, age); 	// 不良菜 20

数值和布尔值的解构赋值
其中原始类型和实例对象的自动转换,大家可以看看包装对象,网道写的非常详细。
解构在内部使用函数ToObject()把元数据结构转换为对象。意味着在对象解构的上下文中,原始值会被当成对象。根据ToObject()函数的定义,null和undefined不能被解构,否则会抛出错误。

let {toString: s} = 123;
s === Number.prototype.toString // true
let {toString: s} = true;
s === Boolean.prototype.toString // true
数值和布尔值的包装对象都有toString属性,因此变量s都能取到值。

const { prop: x } = undefined; // TypeError
const { prop: y } = null; // TypeError
可以使用空对象模型{}来检查一个值是否被强制转换成了一个对象。正如前面提到的规则,
undefinednull将会抛出错误

字符串的解构赋值
其中原始类型和实例对象的自动转换,大家可以看看包装对象,网道写的非常详细。

let { length } = "abc"	// 字符串abc的包装对象提供了多个属性,length只是其中之一
// 相当于现在"abc"变成了{0: "a", 1: "b", 2: "c", length: 3, [[PrimitiveValue]]: "abc"}
// 我们用其中的length,自然输出就为3
console.log(length);    // 3 
console.log({length});  // { length: 3 }
字符串被转换成了一个类似数组的对象。
const [a,b,c,d,e]="hello"
console.log(a,b,c,d,e);		// h e l l o

函数参数的解构赋值
函数参数的解构可以使用默认值也可以利用传递的参数进行解构

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

move({x: 3, y: 8}); // [3, 8]
move(); // [0, 0]  无传参,直接使用默认值

用途
对JSON格式的值提取起来尤为方便,再进行数据传输的时候,假如后台返回一串JSON格式的值,通过遍历之后,再通过解构就能轻松将里面的值取出来。

let jsonData = {
  id: 01,
  name: 'buliangc',
  status: "OK",
  data: [[{},{},{}]
};

let { id, name, status, data: sourceData} = jsonData;

console.log(id, name, status, sourceData); 
// 1 buliangc OK [ {}, {}, {} ]

3.块级作用域

ES5之前js的作用域只有全局作用域和函数作用域,ES6之后,新增了块级作用域,解决了以前诸多不合理的问题。比如:内层变量可能会覆盖外层变量。

var name = '外层变量';
function fn() {
	console.log(name);
	if (false) {
		var name = '内层变量';
	}
}
fn();//undefined

通过var变量提升,内部的name变量提升到函数作用域的最前面,var name;导致外层的变量被覆盖。从而输出undefined。
let 实际上为 JavaScript 新增了块级作用域。

var name = '外层变量';
function fn() {
	console.log(name);
	if (false) {
		let name = '内层变量';
	}
}
fn(); //'外层变量'

4.箭头函数

在ES6中,新增箭头函数,函数的一种简写形式。

  1. 箭头函数不需要使用function关键字,使用括号包裹参数,跟随一个 =>,紧接着是函数体。
  2. 箭头函数内部没有this,而是继承父级作用域的this,任何方法都改变不了,包括显示绑定的call,apply,bind。
  3. 箭头函数内部没有arguments。
  4. 箭头函数不能作为构造函数,不能使用new关键字。

定时器中普通函数的this指向window,除非进行绑定或者用变量保存this,不然指向Person。而用箭头函数就很轻松的解决了这个问题,因为他指向父级,也就是构造函数本身。

function Person() {
    this.age = 0;
    setTimeout(() => {
        this.age++;
        console.log(this.age);
    }, 2000);
}
var person = new Person();

5. for…of vs for…in

for…of:遍历数组的值(value)

let arr = ["a", "b", "c"];
for (let item of arr) {
	console.log(item);	// a b c
}

for…in:遍历对象中的属性,数组的键名(key)

let arr = ["a", "b", "c"];
for (let item in arr) {
    console.log(item);	// 0 1 2
}
let obj = { a: 1, b: 2, c: 3 };
for (let item in obj) {
	console.log(item);	// a b c
	console.log(obj.item)	// 1 2 3
}

6. 类

在这里插入图片描述
子类本身是没有自己的 this ,子类构造器中, this 是由 super () 调用所产生的(即所谓「父类的 this 」)。 在 super () 调用之前,你是不能在子类构造器中使用 this 的,如果访问之,会产报错 ReferenceError :Must call super constructor in derived class before accessing ‘this’ or returning from derived constructor。

super作为函数调用时,代表父类的构造函数,不过this指向的子类实例对象。所以如果你在子类Porsche的constructor中执行super(),就相当于执行A.prototype.constructor.call(this)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值