1.新增API——new.target
众所周知,js中构造函数需使用new来调用,但是即使不使用new关键字,也可以调用构造函数,如【例1-1】,为了解决这一问题,js的解决方式为使用instanceof查看原型上是否有该构造函数,如【例1-2】,到了es6提供了一个特殊的API,可以使用该API在函数内部,判断该函数是否使用new来调用,如【例1-3】
【例1-1】构造函数的两种调用方式
function Person(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
this.fullName = `${firstName}${lastName}`;
//纯碎是为了让p1有返回值
return `${this.firstName} ${this.lastName} ${this.fullName}`
}
const p1 = Person("J", "wh");
const p2 = new Person('T','hs');
console.log(p1);
console.log(p2);
【结果】
![](https://i-blog.csdnimg.cn/blog_migrate/fc0ddc1d38e1b2e4638e25ad60d111ee.png)
【例1-2】之前的解决方式
function Person(firstName, lastName) {
if (!(this instanceof Person)) {
throw new Error('该函数没有使用new来调用')
}
this.firstName = firstName;
this.lastName = lastName;
this.fullName = `${firstName}${lastName}`;
}
const p2 = new Person('T','hs');
console.log(p2);
const p1 = Person("J", "wh");
console.log(p1);
【结果】
![](https://i-blog.csdnimg.cn/blog_migrate/71e49bedc3d0bc638cdde1a525c2ab93.png)
细心的读者可能已经发现了,这种间接的方法可能导致人为改变this指向后,使得原型链上有构造函数,即该判断是可以避开的,存在bug,如下例
const p2 = new Person('T', 'hs');
console.log(p2);
const p3 = Person.call(p2, 'J', 'wh')
console.log(p3)
【结果】
![](https://i-blog.csdnimg.cn/blog_migrate/b3948c28cf273cc1e0647bf4e052f06e.png)
因此,es6提供了新的API —— new.target去直接解决这一问题,该表达式的用法是:当没有使用new调用函数时,返回undefined;若使用了new来调用,则得到new关键字后面的函数本身
【例1-3】
function Person(firstName, lastName) {
if (new.target === undefined) {
throw new Error('该函数没有使用new来调用')
}
this.firstName = firstName;
this.lastName = lastName;
this.fullName = `${firstName}${lastName}`;
}
const p2 = new Person('T', 'hs');
console.log(p2);
const p3 = Person.call(p2, 'J', 'wh')
console.log(p3);
![](https://i-blog.csdnimg.cn/blog_migrate/c8b603db0bf6febfbf6424da4f31db93.png)
2.箭头函数
(1) this指向
- 通过对象调用函数,this指向对象
- 直接调用函数,this指向全局对象
- 如果通过new调用函数,this指向新创建的对象
- 如果apply,call,bind调用函数,this指向指定的数据
- 如果是dom时间函数,this指向事件源
下面给个定时器的例子
【例2-1-1】
const obj = {
count: 0,
start: function () {
setInterval(function () {
this.count++;
console.log(this.count);
}, 1000)
}
}
obj.start();
【结果】本来代码想实现的效果是, 没隔一秒count加1,但是由于定时器的this指向window,因此打印结果为
![](https://i-blog.csdnimg.cn/blog_migrate/9d971f9f6c499f661f94d23228750794.gif)
之前的解决方式是,在start方法中保存this指向,如下,则可以解决该问题
const obj = {
count: 0,
start: function () {
//保存this
const self = this;
setInterval(function () {
self.count++;
console.log(self.count);
}, 1000)
}
}
obj.start();
(2)箭头函数
es6在解决上述问题时引入了箭头函数。箭头函数是一个函数表达式,理论上,任何使用函数表达式的场景都可以使用箭头函数
语法规则
- 完整语法:(参数1, 参数2,...) => {函数体}
- 如果只有一个参数,可以省略小括号:参数=>{函数体}【例2-2-2】
- 如果箭头函数只有一条返回语句,可以省略大括号,和return关键字:参数=>返回值
箭头函数的特点
- 箭头函数中,不存在this,arguments,new.target,如果使用了,则是函数外层的对应的this,arguments,new.target
- 箭头函数没有原型
- 箭头函数不能作用构造函数使用
应用场景
- 临时性使用的函数,并不会且不可以调用它,如:事件处理函数,异步处理函数,其他临时性的函数
- 为了绑定外层this的函数
- 在不影响其他代码的情况下,保持代码的简洁,最常见的,数组方法中的回调函数
【例2-2-1】
const obj = {
count: 0,
start: function () {
setInterval(() =>{
this.count++;
console.log(this.count);
}, 1000)
}
}
obj.start();
【例2-2-2】
const print = num => {
console.log('打印:', num);
}
print(2);
【例2-2-3】
const sum = (a,b)=> ({
a:a,
b:b,
sum:a+b
});
console.log(sum(3,5));
【例2-2-4】
const numbers = [3, 7, 4, 8, 9];
const result = numbers.filter(num => num % 2 !== 0)
.map(num => num * 2).reduce((a, b) => a + b)
console.log(result);