3

一、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
后续将不断完善,期待您的批评和指正!


薇薇
298 声望24 粉丝

路漫漫其修远兮,吾将上下而求索


引用和评论

0 条评论