一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第26天,点击查看活动详情。
一些ES6特性
嗨嗨害!又来水文啦,小白一枚,水平有限。
ES6建议看看阮一峰老师的那个文档,传送入口
let
let用于变量声明,与var类似。
但又有区别:
1.变量不能重复声明
let star = '蔡徐坤';
let star = '基尼泰美';
var可以重复声明 let不可以
2.块级作用域
在es5里边有3种作用域,全局、函数、eval 其中这个eval是在严格模式下才有的
而ES6里边引入了块级作用域,let声明的变量属于块级作用域
什么意思呢,就是let声明的变量,只在代码块内有效,出了代码块之后就无效了,其他情况包括if else while for中用let声明的话也是块级作用域
{
let girl = '坤坤';
}
console.log(girl); //毫不意外的报错
如果是var girl的话就可以在代码块外面读取到,因为var是没有块级作用域的,所以声明后如果不是函数作用域,就会在window下添加这个属性。
3.不存在变量提升
console.log(taylor); //报错
let taylor = 'love story';
4.不影响作用域链
{
let lol = '英雄联盟';
function fn() {
console.log(lol);
}
fn(); //能正常输出'英雄联盟',说明沿着作用域链去寻找变量了
}
来看看一个案例:
//获取div元素对象
let items = document.getElementsByClassName('item');
for (var i = 0; i < items.length; i++) {
items[i].onclick = function () {
//修改当前元素背景颜色 ,这是通常的写法
this.style.background = 'pink';
}
}
如果把事件处理函数中的执行语句写成了items[i].style.background = 'pink';呢
ES5之前确实不能这么写,因为你触发回调函数的时候,就代表for已经循环完毕了
这时候i一直是最大值3。i是全局作用域下的,当我们点击启动某个元素时,执行这个回调函数
它在全局下找到了i,i是3,但是items[3]超出了范围,越界了,会报错,最多就items[2]嘛
那如果就想要这样子写呢?很简单,只要把var换成let就可以了
for (let i = 0; i < items.length; i++) {
items[i].onclick = function () {
//修改当前元素背景颜色
items[i].style.background = 'pink';
}
}
本来用var的时候,遍历元素绑定事件的代码相当于是这样子的
{
var i = 0;
items[i].onclick = function () {
items[i].style.background = 'pink';
}
}
{
var i = 1;
...
}
{
var i = 2;
...
}
虽然对应顺序的元素绑定上了事件,但是里面执行的代码是items[i].style.background,3次循环后,i自增变成了3,由于i是全局下的,当我i自增完后,你去触发点击事件,执行里面的items[i].style.background = 'pink';
在回调函数中找不到i,就去外层作用域找,找到了,但是i是全局的,被更新过,所以会报一个越界的错误最多到items[2]
如果换成let,就不会有这个问题,let声明的变量的范围是块级作用域,也就是我每一个块的i都是独立的,上面那个遍历绑定事件就相当于是
{
let i = 0;
items[i].onclick = function () {
items[i].style.background = 'pink';
}
}
{
let i = 1;
...
}
{
let i = 2;
...
}
当我点击对应的某个元素时,就回触发回调函数,先在函数自身中找,找不到i,就去外层作用域,此时因为是let声明的i,所以出现了块级作用域,i是属于当前这个块的,这个i是每个块中独立的,即使你在for中i自增了,但是不影响块中的,它声明的时候,i是多少就是多少,不会变。
const声明常量
通常const用于声明常量,格式与var 和 let 是一样的。
比如:
const CSGO = "S1mple";
console.log(CSGO);
注意事项:
-
一定要赋初始值
比如const A;连编译器都自动提示你出错了,你就知道肯定不能这么写啦 -
一般常量用大写(但这不是语法要求,是一个潜规则)
const a = 100; //小写也是可以的 -
常量的值不能修改
// 把刚刚声明的CSGO的值进行修改
CSGO = "k神" // 会报错
- const声明的常量也是块级作用域的
{
const PLAYER = 'uzi';
}
console.log(PLAYER); //PLAYER is not defined
- 对于数组和对象的元素修改,不算做对常量的修改,不会报错
const GROUP = ['A', 'B', 'C', 'D'];
TEAM.push('E');
虽说数组元素发生了改变,但这个常量他所指向的地址没有变,所以不会报错
所以数组和对象的声明可以使用const,是比较稳妥的,避免误操作
解构赋值
1.数组的解构
const TFBOYS = ['王源', '王俊凯', '易烊千玺'];
let [yuan, kai, yi] = TFBOYS;
把这个数组中的元素赋值给某个变量,这时候就能用 解构赋值 来做
用let或者var都可以,用一个中括号[] 把三个变量放进去,然后把TFBOYS赋值给这个玩意儿,这样一来就相当于我声明了3个变量,变量值就是对应数组位置的值。有点像序列解包0 0
console.log(yuan);
console.log(kai);
console.log(yi);
console.log('------------');
2.对象的解构
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
const LOL = {
name: '英雄联盟',
age: '12',
fn: function () {
console.log("全军出击!");
}
};
现在我们也可以用类似的方式,把对象里面的属性值提取出来,但是这时候我们不能用[]了,要使用和这个对象一样的结构
let {name, age, fn} = LOL;
这样就把对象里面的属性分别保存到了里面
相当于我声明了3个变量,并且对这3个变量进行了赋值
console.log(name);
console.log(age);
console.log(fn);
fn();
解构里边属性解构用的比较少,方法解构用的比较多
如果刚刚那个对象的方法没有用解构,每次调用都需要LOL.fn(),多次调用就要重复这个代码
你会发现你多写了很多重复的字符串LOL。所以我们可以给它来一个解构
let {fn} = LOL; 把这个方法单独解构出来(要和对象里边的方法同名)
对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。
对象的解构赋值,允许给赋值的变量重命名
其实在给对象进行解构赋值的时候,有一种需求就是给对象的变量重命名。
let { name: myname } = LOL;
console.log(myname);
左边的name是用来做匹配的,用来去解构对象里面寻找值的
myname才是变量名,myname = "英雄联盟"
补充:
对象的解构赋值是下面形式的简写
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才是变量。真正被赋值的是变量baz,而不是模式foo。