Open FrankKai opened 5 years ago
this
,arguments
,super
,new.target
。method function指的是对象的方法函数,而non-method则反之,也就是说箭头函数最好用在不是对象的method的场景,因此我们的API层将改为ES6的函数shorhand写法。
(foo, bar, baz) => { statements }
(foo, bar, baz) => { return expression } // (foo, bar, baz) => expression
( foo ) => { statements } // foo => { statements }
() => { statements }
(foo, bar, baz) => ({a: 'a'})
(foo, bar, ...rest) => { statements }
(foo = 'foo', bar = true, bar = {a: 1, b: 2}) => { statements }
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a +b +c;
f(); // 6
关于Arrow functions,mozilla.org上有一篇深度剖析的文章。ES6 In Depth: Arrow functions
var elements = [
'Hydrogen',
'Helium',
'Lithium',
'Beryllium'
];
elements.map(function(element ) {
return element.length;
}); // [8, 6, 7, 9]
elements.map(element => element.length); // [8, 6, 7, 9]
elements.map(({ length }) => length); // [8, 6, 7, 9]
其实最后2步做了这样一个操作:const { length } = element
,由于解构element后参数不再是单个,因此需要用()包裹起来。
js中this,其实是与面向对象编程的思想不符的,箭头函数一定程度上消除了这种困惑。 因为this在不同的情况下,指代的东西不同,在constructor中指代新对象,在'use strict'的函数中this为undefined,对象方法函数中的this又是这个对象。
function Person() {
this.age = 0;
setInterval(function growUp() {
this.age++;
console.log(this); // window
}, 1000);
}
var p = new Person();
function Person() {
var that = this;
that.age = 0;
setInterval(function growUp() {
that.age++;
console.log(this, that); // window, Person实例(创建2个则打印2个)
}, 1000);
}
var p = new Person();
function Person(){
this.age = 0;
setInterval(() => {
this.age++;
console.log(this); // Person实例(创建2个则打印2个)
}, 1000);
}
var p = new Person();
console.log(p);
使用箭头函数后,callback中的this不再由于闭包而指向window,直接指向了当前实例,因此也不需要像es5中的var that = this;显式将实例传入callback中。 使用箭头函数后,this变得不再让人困惑了!
严格模式下,箭头函数中的this也是ok的。
var f = () => { 'use strict'; return this; };
f() === window; // f() -> window
严格模式下,普通函数中的this是undefined。
var f = function() {'use strict'; return this; };
f() === undefined; //f() -> undefined
非严格模式下,this是window。
var f = function() { return this; };
f() === window; //f() -> window
显然箭头函数是strict mode下的更好写法。
由于call()或者apply()只能通过parameters传值,所以在箭头函数上用call(),apply(),this会被忽略。因为箭头函数没有arguments!。
var adder = {
base: 1,
add: function(a) {
var f = v => v + this.base; // {base: 1, add: ƒ, addThruCall: ƒ}
return f(a);
},
addThruCall: function(a) {
var f = v => v + this.base; // {base: 1, add: ƒ, addThruCall: ƒ}
var b = {
base: 2
}
return f.call(b, a);
}
}
console.log(adder.add(1)); // 2
console.log(adder.addThruCall(1)); // 2,因为箭头函数没有arguments,call中的this会被忽略,this依然是当前的对象,因此还是2.
const f = function() { console.log(arguments) };
f();
Arguments [callee: ƒ, Symbol(Symbol.iterator): ƒ]
const f = () => { console.log(arguments); }
f();
Uncaught ReferenceError: arguments is not defined
var arguments = [1, 2, 3];
var arr = () => arguments[0];
arr(); // 1
function foo(n) {
var f = () => arguments[0] + n; // foo's implicit arguments binding. arguments[0] is n
return f();
}
foo(3); // 6
通过rest parameters
可以获取到箭头函数的parameters!
var customArguments = [1, 2, 3];
var arr = () => arguments[0];
arr(); // 1
function foo(n) {
var f = (...args) => args[0] + n;
return f(customArguments[0]);
}
foo(3); // 4
在有this的情况下慎用,最好用function的shorthand。
'use strict';
var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log(this.i, this);
}
}
obj.b(); // prints 0, Window {...}
obj.c(); // prints 10, Object {...}
Object.defineProperty()中也可以说明箭头函数作为method不好。
'use strict';
var obj = {
a: 10
};
Object.defineProperty(obj, 'b', {
get: () => {
console.log(this.a, typeof this.a, this); // undefined 'undefined' Window {...} (or the global object)
return this.a + 10; // represents global object 'Window', therefore 'this.a' returns 'undefined'
}
});
改成get()是OK的。
箭头函数不能被当做constructor使用,否则会抛出一个错误。
var Foo = () => {};
var foo = new Foo(); // Uncaught TypeError: Foo is not a constructor
今天终于明白了Uncaught 仅仅代表error是否被捕获。
var Foo = () => {};
console.log(Foo.prototype);// undefined
function类型的可以。
var Foo= function() {};
console.log(Foo.prototype); // {constructor: ƒ}
没有constructor,没有prototype,这也是不能使用new的原因。
因为直接写一个{ foo: 1},foo: 1会被当作一个statement。
var func = () => { foo: 1 };
var func = () => { foo: function() {} };
foo会被当作label,1和function(){}被当作statement,没有任何return。
var func = () => ({foo: 1});
不可以。
var func = ()
=> 1;
// SyntaxError: expected expression, got '=>'
let callback;
callback = callback || function() {}; // ok
callback = callback || () => {};
// SyntaxError: invalid arrow-function arguments
callback = callback || (() => {}); // ok
let empty = () => {};
(() => 'foobar')();
var simple = a => a > 15 ? 15: a;
let max = (a, b) => a > b ? a : b;
var arr = [5, 6, 13, 0, 1, 18, 23];
var sum = arr.reduce((a, b) => a + b); // 66
var even = arr.filter(v => v % 2 == 0); // [6, 0, 18]
var double = arr.map(v => v * 2); // [10, 12, 26, 0, 2, 36, 46]
promise.then(foo => {
// ...
}).then(bar => {
// ...
});
setTimeout( () => {
console.log('I happen sooner');
setTimeout( () => {
console.log('I happen later');
}, 1);
}, 1);
// main.js
Vue.prototype.$appName = ()=> {
console.log(this); // 绑定的this指向的是main.js
}
Vue.prototype.$appName = function(){
console.log(this); // 这样才能绑定到Vue类,从而切换this到实例
}
vue实例除了watcher以外,几乎所有的地方都是箭头函数,这样才可以获取到单文件组件这个实例。从这里可以看出,其实箭头函数的作用是:隐式绑定this到父作用域。这里的父作用域指的是单文件组件实例。
因为箭头函数中的this指向的是全局对象,不能指向当前vue实例。
与let,const一样,对箭头函数的掌握也一直是模棱两可,因此需要深入学习一下,mdn的Arrow Functions就是很好的学习资料,除了阅读文档,我也会加入一些自己的思考。