一、let
ES6 新增了let命令,用来声明变量。
特点:
1.块级作用域
它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
2.不存在变量提升
let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错
3.暂时性死区
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”。
4.不允许重复生明
let不允许在相同作用域内,重复声明同一个变量。
二、const
同样用于声明变量。
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。
理论来说const声明的变量的值不得改动,意思其实是变量指向的那个内存地址所保存的数据不得改动,上面代码中,常量zs储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把zs指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性,最后将 zs 指向另一个对象,就会报错TypeError: Assignment to constant variable.
如果想让定义的对象或数组的内部数据也不能够修改和改变,可以使用object.freeze(names)进行冻结,这样为对象添加新属性就不起作用。
三、变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
let [a, b, c] = [1, 2, 3];
四、原始数据类型Symbol
ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。
使用场景:
1.作为属性名
let sy = Symbol("key1");
// 写法1
let syObject = {};
syObject[sy] = "kk";
console.log(syObject); // {Symbol(key1): "kk"}
// 写法2
let syObject = {
[sy]: "kk"
};
console.log(syObject); // {Symbol(key1): "kk"}
// 写法3
let syObject = {};
Object.defineProperty(syObject, sy, {value: "kk"});
console.log(syObject); // {Symbol(key1): "kk"}
2.定义常量
const COLOR_RED = "red";
const COLOR_YELLOW = "yellow";
const COLOR_BLUE = "blue";
const MY_BLUE = "blue";
五、Map
Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
Maps 和 Objects 的区别
- 一个 Object 的键只能是字符串或者 Symbols,但一个 Map 的键可以是任意值。
- Map 中的键值是有序的(FIFO 原则),而添加到对象中的键则不是。
- Map 的键值对个数可以从 size 属性获取,而 Object 的键值对个数只能手动计算。
- Object 都有自己的原型,原型链上的键名有可能和你自己在对象上的设置的键名产生冲突。
六、Set
Set 对象允许存储任何类型的唯一值,无论是原始值或者是对象引用。
使用场景:
1.数组去重
var mySet = new Set([1, 2, 3, 4, 4]);
[...mySet]; // [1, 2, 3, 4]
2.并集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var union = new Set([...a, ...b]); // {1, 2, 3, 4}
3.交集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var intersect = new Set([...a].filter(x => b.has(x))); // {2, 3}
4.差集
var a = new Set([1, 2, 3]);
var b = new Set([4, 3, 2]);
var difference = new Set([...a].filter(x => !b.has(x))); // {1}
七、Reflect 与 Proxy
Proxy 与 Reflect 是 ES6 为了操作对象引入的 API 。
Proxy 可以对目标对象的读取、函数调用等操作进行拦截,然后进行操作处理。它不直接操作对象,而是像代理模式,通过对象的代理对象进行操作,在进行这些操作时,可以添加一些需要的额外操作。
Reflect 可以用于获取目标对象的行为,它与 Object 类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与 Proxy 是对应的。
let target = {
name: 'Tom',
age: 24
}
let handler = {
get: function(target, key) {
console.log('getting '+key);
return target[key]; // 不是target.key
},
set: function(target, key, value) {
console.log('setting '+key);
target[key] = value;
}
}
let proxy = new Proxy(target, handler)
proxy.name // 实际执行 handler.get
proxy.age = 25 // 实际执行 handler.set
// getting name
// setting age
// 25
八、字符串的扩展
ES6 加强了对 Unicode 的支持,并且扩展了字符串对象。
字符的 Unicode 表示法
如果直接在\u
后面跟上超过0xFFFF
的数值(比如\u20BB7
),JavaScript会理解成\u20BB+7
。由于\u20BB
是一个不可打印字符,所以只会显示一个空格,后面跟着一个7
。
ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。
"\u{20BB7}"
// ""
"\u{41}\u{42}\u{43}"
// "ABC"
let hello = 123;
hell\u{6F} // 123
'\u{1F680}' === '\uD83D\uDE80'
// true
有了这种表示法之后,JavaScript 共有6种方法可以表示一个字符。
'\z' === 'z' // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true
codePointAt()
ES6提供了codePointAt方法,能够正确处理4个字节储存的字符,返回一个字符的码点。
String.fromCodePoint()
ES6提供了String.fromCodePoint方法,可以识别0xFFFF的字符,弥补了String.fromCharCode方法的不足
字符串的遍历器接口
ES6为字符串添加了遍历器接口,使得字符串可以被for...of循环遍历。
for (let codePoint of 'foo') {
console.log(codePoint)
}
// "f"
// "o"
// "o"
includes(), startsWith(), endsWith()
传统上,JavaScript只有indexOf
方法,可以用来确定一个字符串是否包含在另一个字符串中。ES6又提供了三种新方法。
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在源字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部。
let string = "apple,banana,orange";
string.includes("banana"); // true
string.startsWith("apple"); // true
string.endsWith("apple"); // false
string.startsWith("banana",6) // true,第二个参数为搜索起始位置索引
注意:
1.这三个方法只返回布尔值,如果需要知道子串的位置,还是得用 indexOf 和 lastIndexOf 。
2.这三个方法如果传入了正则表达式而不是字符串,会抛出错误。而 indexOf 和 lastIndexOf 这两个方法,它们会将正则表达式转换为字符串并搜索它。
repeat()
repeat方法返回一个新字符串,表示将原字符串重复n次。
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
padStart(),padEnd()
补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
模板字符串
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
$('#result').append(`
There are <b>${basket.count}</b> items
in your basket, <em>${basket.onSale}</em>
are on sale!
`);
九、ES6数值
数值的表示
二进制表示法新写法: 前缀 0b 或 0B 。
console.log(0b11 === 3); // true
console.log(0B11 === 3); // true
八进制表示法新写法: 前缀 0o 或 0O 。
console.log(0o11 === 9); // true
console.log(0O11 === 9); // true
Number.EPSILON
Number.EPSILON 属性表示 1 与大于 1 的最小浮点数之间的差。
它的值接近于 2.2204460492503130808472633361816E-16,或者 2-52。
测试数值是否在误差范围内:
0.1 + 0.2 === 0.3; // false
// 在误差范围内即视为相等
equal = (Math.abs(0.1 - 0.3 + 0.2) < Number.EPSILON); // true
还增加了些Number对象,Math对象的新方法,详细参考文档:
https://www.runoob.com/w3cnote/es6-number.html
十、ES6对象
对象的拓展运算符
拓展运算符(...)用于取出参数对象所有可遍历属性然后拷贝(浅拷贝)到当前对象。
let person = {name: "Amy", age: 15};
let someone = { ...person };
someone; //{name: "Amy", age: 15}
可用于合并两个对象
let age = {age: 15};
let name = {name: "Amy"};
let person = {...age, ...name};
person; //{age: 15, name: "Amy"}
Object.assign(target, source_1, ···)
用于将源对象的所有可枚举属性复制到目标对象中(浅拷贝)。
let target = {a: 1};
let object2 = {b: 2};
let object3 = {c: 3};
Object.assign(target,object2,object3);
// 第一个参数是目标对象,后面的参数是源对象
target; // {a: 1, b: 2, c: 3}
Object.is(value1, value2)
用来比较两个值是否严格相等,与(===)基本类似。
Object.is("q","q"); // true
Object.is(1,1); // true
Object.is([1],[1]); // false
Object.is({q:1},{q:1}); // false
与(===)的区别
//一是+0不等于-0
Object.is(+0,-0); //false
+0 === -0 //true
//二是NaN等于本身
Object.is(NaN,NaN); //true
NaN === NaN //false
十一、数组
数组创建
Array.of()
将参数中所有值作为元素形成数组。
console.log(Array.of(1, 2, 3, 4));
// [1, 2, 3, 4]
// 参数值可为不同类型
console.log(Array.of(1, '2', true));
// [1, '2', true] // 参数为空时返回空数组
console.log(Array.of());
// []
Array.from()
将类数组对象或可迭代对象转化为数组。
// 参数为数组,返回与原数组一样的数组
console.log(Array.from(\[1, 2\])); // \[1, 2\]
// 参数含空位
console.log(Array.from(\[1, , 3\])); // \[1, undefined, 3\]
扩展运算符
let arr = [1, 2], arr1 = [...arr];
console.log(arr1); // [1, 2]
// 数组含空位
let arr2 = [1, , 3], arr3 = [...arr2];
console.log(arr3); //[1, undefined, 3]
//合并数组
console.log([...[1, 2],...[3, 4\]]); // [1, 2, 3, 4]
十二、函数
箭头函数
箭头函数提供了一种更加简洁的函数书写方式。基本语法是:
参数 => 函数体
基本用法
var f = v => v; //等价于
var f = function(a){ return a; } f(1); //1
当箭头函数没有参数或者有多个参数,要用()括起来。
var f = (a,b) => a+b;
f(6,2); //8
当箭头函数函数体有多行语句,用{}包裹起来,表示代码块,当只有一行语句,并且需要返回结果时,可以省略{}, 结果会自动返回。
var f = (a,b) => {
let result = a+b;
return result;
}
f(6,2); // 8
当箭头函数要返回对象的时候,为了区分于代码块,要用()将对象包裹起来
// 报错
var f = (id,name) => {id: id, name: name}; f(6,2);
// SyntaxError: Unexpected token :
// 不报错
var f = (id,name) => ({id: id, name: name}); f(6,2);
// {id: 6, name: 2}
注意点:没有 this、super、arguments 和 new.target 绑定。
var func = () => {
// 箭头函数里面没有 this 对象,
// 此时的 this 是外层的 this 对象,即 Window
console.log(this)
}
func(55)
// Window
var func = () => {
console.log(arguments)
}
func(55); // ReferenceError: arguments is not defined
箭头函数体中的 this 对象,是定义函数时的对象,而不是使用函数时的对象。
function fn(){
setTimeout(()=>{
// 定义时,this 绑定的是 fn 中的 this 对象
console.log(this.a);
},0)
} var a = 20;
// fn 的 this 对象为 {a: 19} fn.call({a: 18}); // 18
不可以作为构造函数,也就是不能使用 new 命令,否则会报错
适合使用的场景
ES6 之前,JavaScript 的 this 对象一直很令人头大,回调函数,经常看到 var self = this 这样的代码,为了将外部 this 传递到回调函数中,那么有了箭头函数,就不需要这样做了,直接使用 this 就行。
// 回调函数
var Person = {
'age': 18,
'sayHello': function () {
setTimeout(function () {
console.log(this.age);
});
}
};
var age = 20;
Person.sayHello(); // 20
var Person1 = {
'age': 18, 'sayHello': function () {
setTimeout(()=>{
console.log(this.age);
}); }
};
var age = 20;
Person1.sayHello(); // 18
所以,当我们需要维护一个 this 上下文的时候,就可以使用箭头函数。
不适合使用的场景
定义函数的方法,且该方法中包含 this
var Person = {
'age': 18,
'sayHello': ()=>{
console.log(this.age);
}
};
var age = 20;
Person.sayHello(); // 20
// 此时 this 指向的是全局对象
var Person1 = {
'age': 18,
'sayHello': function () {
console.log(this.age);
}
};
var age = 20;
Person1.sayHello(); // 18
// 此时的 this 指向 Person1 对象
需要动态 this 的时候
var button = document.getElementById('userClick');
button.addEventListener('click', () => {
this.classList.toggle('on');
});
button 的监听函数是箭头函数,所以监听函数里面的 this 指向的是定义的时候外层的 this 对象,即 Window,导致无法操作到被点击的按钮对象。
详细请参考:https://www.runoob.com/w3cnote/es6-tutorial.html
后续将不断完善,期待您的批评和指正!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。