ES6复习(一)
ES6 及以上最新规范
let 和 const
在 ES6 之前,声明变量的关键字只有var
,并且没有块级作用域,只有函数作用域和全局作用域。
let
、const
和var
的区别
- 不允许声明提升
- 不允许重复声明
- 不覆盖全局变量
- let
console.log(outer);
console.log(inner);
// Uncaught ReferenceError: inner is not defined
{
console.log(outer);
//
console.log(inner);
// Uncaught ReferenceError: Cannot access 'inner' before initialization
var outer = true;
let inner = true;
console.log(outer);
// true
console.log(inner);
// true
}
console.log(outer);
// true
console.log(inner);
// Uncaught ReferenceError: inner is not defined
临时死区(Temporal Dead Zone, TDZ),也叫暂时性死区。用
let
或const
声明的变量,在声明前都会放到 TDZ 中,而声明前访问这些变量就会触发运行时错误。其次,let 不允许重复声明同一个变量。这里有个限制:必须是在同一个作用域时,才不允许同一个变量重复声明。
最后是
let
在全局作用域中的特性。当用 var
在全局作用域中声明变量的时候,该变量不但会成为全局变量,而且会成为全局对象(如浏览器中 window 对象)的一个属性。ES6 规定用 let 可将全局变量和全局对象断开联系。下面用两组代码分别演示断开联系(第一组)和覆盖已有属性(第二组),注意,在第二组代码中为了方便对比,忽略了重复声明的错误。// group 1
var global = true;
console.log(window.global);
// truelet whole = true;
console.log(window.whole);
// undefined// group 2
var Math = true;
console.log(window.Math);
//truelet Math = true;
console.log(window.Math);
- const
const
与let
不同,声明时必须初始化(即赋值)。并且这设定后其值无法更改。注意,const 限制的是变量与内存地址之间的绑定。也就是说
const
让变量无法更改内存地址。如果是基本类型(如布尔值、数字等)的变量,那么对应的内存地址中保存的就是值;如果是引用类型(如对象)的变量,那么对应的内存地址中保存的是指向实际数据的一个指针。由此可知,当用 const 声明的变量,其初始化的值是对象时,可以修改对象中的属性或方法。- 循环中的
let
和const
for (let i = 0;
i < 3;
i++) {
setTimeout(function () {
console.log(i);
}, 0);
}
在控制台输出的结果依次为 0、1、2,没有出现循环中的异步回调问题。这是因为在每次循环的时候,都会重新创建一个叫作 i 的同名变量,并将其初始化为计算后的值,而循环体内调用的 i 变量不会受其他同名变量的影响,所以能够在定时器的回调函数中正确显示该变量的值。在 ES5 及之前的版本中,如果要解决异步回调问题,可以借助立即执行函数表达式(IIFE)才能得到预期的效果
for (var i = 0;
i < 3;
i++) {
(function (n) {
setTimeout(function () {
console.log(n);
}, 0);
})(i);
}
Symbol Symbol,可以像字符串那样作为对象的属性,且具有唯一性的特点,(重要)可以避免属性冲突。
1.创建
【ES6复习(一)】
Symbol
没有字面量形式,只能通过Symbol()
函数创建。该函数有一个可选参数,只是用来描述当前符号,除了便于阅读,没有其他用途。即使 2 个Symbol
的描述相同,它们也不相等。Symbol()
不是构造函数,不能组合new
运算符使用。var sym1 = Symbol();
var sym2 = Symbol("name");
var sym3 = Symbol("name");
var sym4 = new Symbol();
// 抛出异常错误
cosole.log(sym2 === sym3);
// true
typeof
识别Symbol
typeof Symbol() === "symbol";
// true
- 类型转换
var sym = Symbol("age");
Number(sym);
parseInt(sym);
1 + sym;
"" + sym;
但可以显性转成字符串或布尔值。
Boolean(sym);
// true
!sym;
// false
sym.toString();
// "Symbol(age)"
String(sym);
// "Symbol(age)"
- 全局共享
var sym1 = Symbol.for("name");
var sym2 = Symbol.for("name");
console.log(sym1 === sym2);
// true
- 属性名
- 内置符号
属性名称 | 值类型 | 描述 |
---|---|---|
hasInstance | 方法 | 当使用 instanceof 运算符,该方法会被调用 |
isConcatSpreadable | 布尔值 | 当对象作为 Array.protorype.concat()方法的参数时,控制改对象是否被展开 |
iterator | 方法 | 返回一个迭代器用于定义一个可迭代对象 |
match | 方法 | 当对象作为 String.prototype.match() 方法的参数时,该方法会被调用 |
replace | 方法 | 当对象作为 String.prototype.replace() 方法的参数时,该方法会被调用 |
search | 方法 | 当对象作为 String.prototype.search() 方法的参数时,该方法会被调用 |
split | 方法 | 当对象作为 String.prototype.split() 方法的参数时,该方法会被调用 |
species | 方法 | 创建派生类的构造函数 |
toPrimitive | 方法 | 当对象需要转换成原始值(即执行 toPrimitive 抽象操作)时,该方法会被调用 |
toStringTag | 字符串 | 指定对象的类型,可在调用 Object.prototype.toString()方法的时候返回 |
unscopables | 对象 | 保存在这个对象中的属性将不能被 width 语句引用 |
hasInstance
、isConcatSpreadable
、match
和toStringTag
:- 实现一个可迭代的对象
var people = {
name: "test",
sex: "male",
hobbies: ["ball", "paint", "sing"],
[Symbol.iterator]() {
const _this = this;
const keys = Reflect.ownKeys(_this);
// 获取到对象的key值列表
let index = 0;
return {
next() {
if (index < keys.length - 1) {
return {
value: _this[keys[index++]], // 想返回什么 就返回什么 keys[index++]
done: false,
};
}
return {
value: keys[index++],
done: true, // 迭代结束
};
},
};
},
};
for (let h of people) {
console.log(h);
}
推荐阅读
- 一个人的旅行,三亚
- 一个小故事,我的思考。
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- 开学第一天(下)
- 一个人的碎碎念
- 2018年11月19日|2018年11月19日 星期一 亲子日记第144篇
- 遇到一哭二闹三打滚的孩子,怎么办┃山伯教育
- 第326天
- Y房东的后半生14
- 奔向你的城市