/10
下面介绍的箭头函数没有arguments属性,如果箭头函数内要实现不定参,上述方式就是一个不错的选择了。
2,箭头函数
箭头函数实现了一种更加简洁的书写方式,并且也解决了关键字声明方式的一些麻烦事儿。箭头函数内部没有arguments,也没有prototype属性,所以不能用new关键字调用箭头函数。
箭头函数的书写方式:参数 => 函数体。
1 let add = (a,b) => { 2 return a+b; 3 } 4 let print = () => { 5 console.log('hi'); 6 } 7 let fn = a => a * a; 8 //当只有一个参数时,括号可以省略,函数体只有单行return语句时,大括号也可以省略,强烈建议不要省略它们,是真的难以阅读
当函数需要直接返回对象时,建议用变量保存,然后返回变量名,或用小括号把对象包裹起来。否则将抛出错误。
1 var returnObj = () =>{ 2 var obj = {name:'ren',age:12}; 3 retufn obj; 4 }; 5 //var returnObj = () => ({name:'ren',age:12});
箭头函数和普通函数最大的区别在于其内部this永远指向其父级AO对象的this。
普通函数在预编译环节会在AO对象上添加this属性,保存一个对象(请参照《java script之深入对象(二)》)。每个普通函数在执行时都有一个特定的this对象,而箭头函数执行时不会在自己的this属性上添加一个新对象,而是直接引用父级AO对象上this绑定的对象。普通函数的AO对象只有在函数执行时才产生,换言之,普通函数的this是由函数执行时的环境决定。而箭头函数的特别之处在于,当函数被定义时,就需要引用其父级AO对象的this,即箭头函数的this由定义时的环境决定。
根据箭头函数的特点,不难推测:如果定义对象的方法直接使用箭头函数,那么函数内的this将直接指向window。
1 var age = 123; 2 let obj = { 3 age:456, 4 say:() => { 5 console.log(this.age); 6 } 7 }; 8 obj.say();//123
9 //对象是没有执行期上下文的(AO对象),定义对象的方法实际上是在全局作用域下,即window
如果你一定要在箭头函数中让this指向当前对象,其实也还是有办法的(但是没必要这么麻烦啊,直接使用普通函数不是更好吗?):
1 var age = 123; 2 let obj = { 3 age:456, 4 say:function(){ 5 var fn = () => { 6 console.log(this.age); 7 } 8 return fn(); 9 } 10 }; 11 obj.say();//456
我们来分析一下这是怎么做到的:首先,我们使用obj调用say方法时,say内创建了AO对象,并且该AO对象的this属性指向了obj(这都不明白的请回去往前复习一下我的《java script之深入函数/对象》),然后,say内部又声明了一个箭头函数。我们说箭头函数在声明时就要强行引用父级AO的this属性,那么现在该箭头函数的父级AO是谁呢?当然就是say的AO啦,所以这里箭头函数的this直接就绑定了obj,最后箭头函数在执行时拿到的this,实际上就是say方法的AO.this,即obj本身。
上面是在对象中使用箭头函数,如果那让你难于理解,那么请看下面这种方式:在普通函数中使用箭头函数。
1 var obj = {name:'ren'}; 2 function test(){ 3 var fn = () => { 4 console.log(this); 5 }; 6 fn(); 7 } 8 test();//window
9 test.call(obj);//{name:'ren'}
test函数在全局执行时,其this指向window,这时也产生了箭头函数的定义,于是箭头函数内的this也被指向了window,所以最终打印出window对象。
当我们手动改变test函数执行时this的指向时,箭头函数定义所绑定的this实际上也被我们修改了。所以最终打印出obj。
四 class(类)
class 作为对象的模板被引入ES6,你可以通过 class 关键字定义类。class 的本质依然是一个函数。
1,创建类
1 class Ex {//关键字申明方式
2 constructor(name){ 3 this.name = name; 4 this.say = () => { 5 console.log(this.name); 6 } 7 } 8 methods(){ 9 console.log('hello ' + this.name); 10 } 11 static a = 123; 12 static m = () => { 13 console.log(this.a); 14 }; 15 } 16 //let ex = class{} 字面量方式
17 var example = new Ex('ren'); 18 example.say();//'ren'
19 Ex.m();//123
20 example.methods();//'hello ren'
constructor是创建类必须的方法,当使用new调用类创建实例时,将自动执行该方法,该方法和构造函数类似,默认返回this对象。实例的方法和属性都定义在constructor内部。相当于构造函数的this方式。
类保留了prototype属性,类中的方法不需要使用function关键字,并且方法之间不需要逗号隔开。类中定义的方法实际上还是保存在类的prototype属性上。
使用static关键字定义类的静态属性和方法。类中不能定义共有属性,要想定义实例的共有属性还是需要使用prototype属性:Ex.prototype.属性名 = 属性值。
创建实例依然使用new关键字。
2,类的继承
类的继承通过extends关键字实现。
1 class Person { 2 constructor (name,age){ 3 this.name = name; 4 this.age = age; 5 } 6 say(){ 7 console.log(this.name + ':' + this.age); 8 } 9 } 10 class Student extends Person{ 11 constructor (name,age,sex){ 12 super(name,age); 13 this.sex = sex; 14 } 15 } 16 var student = new Student('ren',12,'male'); 17 student.name;//'ren'
18 student.sex;//'male'
19 student.say();//'ren:12'
子类继承自父类,不会隐式的创建自己的this对象,而是通过super()引用父类的this。这个过程和在子构造函数内使用父构造函数call(this)很像,但他们有本质的区别。另外,ES6规定,super()必须在子类的this之前执行。所以一般我们把super()放在子类constructor方法的第一行,这样准没错!
五 异步机制
ES6新增了两种实现异步的新机制,Promise和Ge