ES5和ES6那些你必须知道的事儿
ES6新增的东西
一、块级作用域:关键字let,常量const
let与var的区别:
a、不会进行变量声明提升
b、变量不允许被重复定义
c、变量不允许被删除
d、在for循环中可以保留i的值
e、循环的变量只能在当前块级作用域中使用
const和var的区别:
a、常用于声明常量时或声明不可被修改的变量的时候
b、const的值不允许被修改
c、不会进行变量声明提升
d、常量不允许被删除
二、对象字面量属性赋值简写
var name = “我是name”; var age = 18; var obj = { name, age } //此处的对象的key值与value值是一样的,所以简写 //不简写的话就是 var obj = { name:name, //即name:“我是name” age:age //即age:18 }
三、解构赋值
let singer = { first: "Bob", last: "Dylan" }; let { first: f, last: l } = singer; // 相当于 f = "Bob", l = "Dylan" let [all, year, month, day] = /^(\d\d\d\d)-(\d\d)-(\d\d)$/.exec("2015-10-25"); let [x, y] = [1, 2, 3]; // x = 1, y = 2
四、展开运算符...
var arr=[1,2,3,4]; console.log(...arr) //打印出来不是一个数组, //而是将数组里的内容分开打印 //1 2 3 4
五、箭头函数
//正常函数的写法: function a(){ //内容 } //如果改成箭头函数 a()=>{ //内容 }
//箭头函数的简写 x => x * x //上面的代码相当于下面的代码 function (x) { return x * x; } //如果参数不是一个,就需要用括号()括起来: // 两个参数: (x, y) => x * x + y * y // 无参数: () => 3.14 // 可变参数: (x, y, ...rest) => { var i, sum = x + y; for (i=0; i<rest.length; i++) { sum += rest[i]; } return sum; } //如果要返回一个对象,就要注意,写成下面这样 x => ({ foo: x })
要注意箭头函数的this
普通函数下的this:
- 在普通函数中的this总是代表它的直接调用者,在默认情况下,this指的是window,
- 在严格模式下,没有直接调用者的函数中的this是 undefined使用
- call,apply,bind(ES5新增)绑定的,this指的是 绑定的对象
箭头函数中的this:
- 箭头函数没有自己的this, 它的this是继承而来; 默认指向在定义它时所处的对象(宿主对象),
- 而不是执行时的对象, 定义它的时候,可能环境是window,也有可能是其他的。
看下面这段代码:
function a() { console.log(this); //window } a();
因为a是一个全局函数,也就是挂载在window对象下的,所以a(),等价于window.a();
var obj = { say: function () { setTimeout(function () { console.log(this); //window }); } } obj.say();
定时器中的函数,由于没有默认的宿主对象,所以this指向window
var obj = { func: function() {}, say: function () { console.log(this);//obj,此时的this是obj对象 setTimeout(function () { console.log(this); //window that.func(); }); } } obj.say();
此时say的宿主环境是obj,所以say里面的this是obj,定时器中的函数, 由于没有默认的宿主对象,所以默认this指向window
箭头函数中的this:
var obj = { say: function () { setTimeout(() => { console.log(this);// obj }); } } obj.say();
此时的 this继承自obj, 指的是定义它的对象obj, 而不是 window!
var obj = { say: function () { var f1 = () => { console.log(this); // obj setTimeout(() => { console.log(this); // obj }) } f1(); } } obj.say()
因为f1定义时所处的函数 中的 this是指的 obj, setTimeout中的箭头函数this继承自f1,所以不管有多层嵌套,都是 obj
var obj = { say: function () { var f1 = function () { console.log(this); // window, f1调用时,没有宿主对象,默认是window setTimeout(() => { console.log(this); // window }) }; f1(); } } obj.say()
结果: 都是 window,因为 箭头函数在定义的时候它所处的环境相当于是window, 所以在箭头函数内部的this函数window
换个理解方式:因为箭头函数没有this,当需要判断当前this是什么的时候,把箭头函数去掉,看剩下的代码此处的this指向哪里即可。
var a=10; var obj={ a:50, getA(){ return this.a }, b:()=>{ return this.a } } console.log(obj.getA())//50 console.log(obj.b())//10 console.log(obj.getA.call())//10
六、字符串模版` `
var name = "Bob", time = "today"; `Hello ${name}, how are you ${time}?` // return "Hello Bob, how are you today?"
七、迭代器
八、生成器
九、class
Class,有constructor、extends、super,但本质上是语法糖(对语言的功能并没有影响,但是更方便程序员使用)。
class Artist { constructor(name) { this.name = name; } perform() { return this.name + " performs "; } } class Singer extends Artist { constructor(name, song) { super.constructor(name); this.song = song; } perform() { return super.perform() + "[" + this.song + "]"; } } let james = new Singer("Etta James", "At last"); james instanceof Artist; // true james instanceof Singer; // true james.perform(); // "Etta James performs [At last]"
十一、Map() 和 Set()
// Sets var s = new Set(); s.add("hello").add("goodbye").add("hello"); s.size === 2; s.has("hello") === true; // Maps var m = new Map(); m.set("hello", 42); m.set(s, 34); m.get(s) == 34;
十二、一些新的API
一些新的API Number.EPSILON Number.isInteger(Infinity) // false Number.isNaN("NaN") // false Math.acosh(3) // 1.762747174039086 Math.hypot(3, 4) // 5 Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2) // 2 "abcde".includes("cd") // true "abc".repeat(3) // "abcabcabc" Array.from(document.querySelectorAll('*')) // Returns a real Array Array.of(1, 2, 3) // Similar to new Array(...), but without special one-arg behavior [0, 0, 0].fill(7, 1) // [0,7,7] [1, 2, 3].find(x => x == 3) // 3 [1, 2, 3].findIndex(x => x == 2) // 1 [1, 2, 3, 4, 5].copyWithin(3, 0) // [1, 2, 3, 1, 2] ["a", "b", "c"].entries() // iterator [0, "a"], [1,"b"], [2,"c"] ["a", "b", "c"].keys() // iterator 0, 1, 2 ["a", "b", "c"].values() // iterator "a", "b", "c" Object.assign(Point, { origin: new Point(0,0) })
十三、proxy
Proxy 让我们能够以简洁易懂的方式控制外部对对象的访问。其功能非常类似于设计模式中的代理模式。
使用 Proxy 的好处是:对象只需关注于核心逻辑,一些非核心的逻辑(如:读取或设置对象的某些属性前记录日志;设置对象的某些属性值前,需要验证;某些属性的访问控制等)可以让 Proxy 来做。从而达到关注点分离,降级对象复杂度的目的。
var p = new Proxy(target, handler);
其中,target 为被代理对象。handler 是一个对象,其声明了代理 target 的一些操作。p 是代理后的对象。
当外界每次对 p 进行操作时,就会执行 handler 对象上的一些方法。handler 能代理的一些常用的方法如下:
- get:读取
- set:修改
- has:判断对象是否有该属性
- construct:构造函数
- ...
var target = { name: 'obj' }; var logHandler = { get: function(target, key) { console.log(`${key} 被读取`); return target[key]; }, set: function(target, key, value) { console.log(`${key} 被设置为 ${value}`); target[key] = value; } } var targetWithLog = new Proxy(target, logHandler); targetWithLog.name; // 控制台输出:name 被读取,执行的get targetWithLog.name = 'others'; // 控制台输出:name 被设置为 others,执行了set console.log(target.name); // 控制台输出: others
- targetWithLog 读取属性的值时,实际上执行的是 logHandler.get :在控制台输出信息,并且读取被代理对象 target 的属性。
- 在 targetWithLog 设置属性值时,实际上执行的是 logHandler.set :在控制台输出信息,并且设置被代理对象 target 的属性的值。
_
开头的变量都认为是私有的。var api = { _secret: 'xxxx', _otherSec: 'bbb', ver: 'v0.0.1' }; api = new Proxy(api, { get: function(target, key) { // 以 _ 下划线开头的都认为是 私有的 if (key.startsWith('_')) { console.log('私有变量不能被访问'); return false; } return target[key]; }, set: function(target, key, value) { if (key.startsWith('_')) { console.log('私有变量不能被修改'); return false; } target[key] = value; }, has: function(target, key) { return key.startsWith('_') ? false : (key in target); } }); api._secret; // 私有变量不能被访问 console.log(api.ver); // v0.0.1 api._otherSec = 3; // 私有变量不能被修改 console.log('_secret' in api); //false console.log('ver' in api); //true
使用代理(Proxy)监听对象的操作,然后可以做一些相应事情。
可监听的操作: get、set、has、deleteProperty、apply、construct、getOwnPropertyDescriptor、defineProperty、getPrototypeOf、setPrototypeOf、enumerate、ownKeys、preventExtensions、isExtensible。
十四、Symbol
Symbol是一种基本类型。Symbol 通过调用symbol函数产生,它接收一个可选的名字参数,该函数返回的symbol是唯一的。
var key = Symbol("key"); var key2 = Symbol("key"); key == key2 //false
十五、promise
Promises是处理异步操作的对象,使用了 Promise 对象之后可以用一种链式调用的方式来组织代码,让代码更加直观
function fakeAjax(url) { return new Promise(function (resolve, reject) { // setTimeouts are for effect, typically we would handle XHR if (!url) { return setTimeout(reject, 1000); } return setTimeout(resolve, 1000); }); } // no url, promise rejected fakeAjax().then(function () { console.log('success'); },function () { console.log('fail'); });
异步操作的同步代码