箭头函数:
更简洁的语法
没有this
不能使用new 构造函数
不绑定arguments,用rest参数...解决
使用call()和apply()调用
捕获其所在上下文的 this 值,作为自己的 this 值
箭头函数没有原型属性
不能简单返回对象字面量
箭头函数不能当做Generator函数,不能使用yield关键字
箭头函数不能换行
箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
普通函数的this指向调用它的那个对象
1.函数体内的this
对象,就是定义时
所在的对象
,而不是使用时所在的对象
普通
的函数里面的this
是指向运行时的作用域
.
箭头函数
中的this
是绑定定义
时所在的作用域
的。
可以使用箭头函数使this指向固定化
,这种特性很有利于封装回调函数
普通函数
function foo() {
setTimeout(function() {
console.log('id:', this.id);
//setTimeout里面的回调函数运行的时候的作用域是window,但是this定义的时候的作用域是函数foo。
}, 100);
}
var id = 21;
foo.call({ id: 42 }); //id: 21
箭头函数
function foo() {
setTimeout(() => {
console.log('id:', this.id);
//箭头函数导致this总是指向函数定义生效时所在的对象
}, 100);
}
var id = 21;
foo.call({ id: 42 }); //id: 42
实际
是箭头函数
根本没有自己的this
,导致内部的this
就是外层代码块的this
// ES6
function foo() {
setTimeout(() => {
console.log('id:', this.id); //其实这里的this就是使用了外层作用域的this
}, 100);
}
// ES5
function foo() {
var _this = this; //将外层作用域的this复制给一个变量
setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}
2.不可以
当作构造函数
,也就是说,不能使用new命令
,否则会抛出一个错误
箭头函数没有自己的this
,所以理所当然箭头函数
也不可以
当作构造函数
。
var fun = (id, name) => {
this.id = id;
this.name = name;
this.showName = () => {
console.log(this.name);
}
};
let obj = new fun(1, "hdl"); //TypeError: fun is not a constructor
//说fun不是一个构造函数,这也反过来印证了第一点,箭头函数没有this。
obj.showName();
3.不可以使用arguments
对象,该对象在函数体内不存在
。如果要用,可以用rest参数
代替。
function func1(a, b) {
console.log(arguments);
//Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]
}
let func2 = (a, b) => {
console.log(arguments); //arguments is not defined
}
改成
let func2 = (...rest) => {
console.log(rest); //[1, 2]
}
func1(1, 2);
func2(1, 2);
4.没有new.target
new.target
是ES6
新引入的属性,普通函数
如果通过new
调用,new.target
会返回该函数的引用
。
function Cat() {
console.log(new.target);
}
let cat = new Cat(); // ƒ Cat() { console.log(new.target); }
用于确定构造函数是否为new调用的。
在箭头函数
里使用new.target
会报错
。
// 普通函数
let a = function() {
console.log(new.target);
}
a(); // undefined
// 箭头函数
let b = () => {
console.log(new.target); // 报错:Uncaught SyntaxError: new.target expression is not allowed here
};
b();
5.没有原型
和super
由于不能通过new
关键字调用,不能作为构造函数
,所以箭头函数
不存在 prototype
这个属性
let func = () => {};
console.log(func.prototype) // undefined
箭头函数没有原型
,也不能通过 super
来访问原型
的属性,所以箭头函数也是没有 super
的。同this、arguments、new.target
一样,这些值由外围最近一层非箭头函数
决定。
6.call/apply/bind
方法无法
改变箭头函数
中this的指向
call()、apply()、bind()
方法的共同特点是可以改变this
的指向,用来动态修改
函数执行时this的指向
。箭头函数的this定义时
就已经确定
了且不会改变
。
var name = 'global name';
var obj = {
name: 'huangdonglu'
}
// 箭头函数定义在全局作用域
let func = () => {
console.log(this.name);
};
func(); // global name
// this的指向不会改变,永远指向Window对象,放到到window下的全局变量
func.call(obj); // global name
func.apply(obj); // global name
func.bind(obj)(); // global name
7.箭头函数的解析顺序相对靠前
虽然箭头函数中的箭头不是运算符
,但箭头函数具有与常规函数不同的特殊运算符优先级解析规则
。
let a = false || function() {}; // ok
let b = false || () => {}; // SyntaxError: Malformed arrow function parameter list
let c = false || (() => {}); // ok
8.箭头函数不支持重名
参数
function foo(a, a) {
console.log(a, arguments); // 2 Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ]
}
var boo = (a, a) => { // 直接报错:Uncaught SyntaxError: Duplicate parameter name not allowed in this context
console.log(a);
};
foo(1, 2);
boo(1, 2);
9.不可以使用yield
命令,因此箭头函数不能用作 Generator
函数。
箭头函数不适用的场景
1.第一个场合是定义对象的方法
,且该方法内部包括this
。
如下:对象不构成
单独的作用域,导致jumps箭头函数
定义时的作用域就是全局作用域
。
对象里面的函数使用箭头函数
const cat = {
lives: 9,
jumps : () => {
this.lives--;
}
};
cat.jumps();
console.log(cat.lives); //9
对象里面的方法使用普通方法
const cat = {
lives: 9,
jumps() {
this.lives--;
}
};
cat.jumps();
console.log(cat.lives); //8
2.需要动态this
时,也不应该使用箭头函数。
var btn = document.getElementById('btn');
btn.addEventListener('click', () => {
console.log(this);//this就是全局对象 不是btn
如果改成普通函数,this就会动态指向被点击的按钮对象。
});
3.具有动态上下文
的回调函数
,也不应使用箭头函数
4.不能应用在构造函数
中
5.避免在 prototype
上使用
6.避免在需要 arguments
上使用
网友评论