箭頭函數(shù)與傳統(tǒng)JavaScript的不同
先來談?wù)凟S5中的this
在ES5中,每個函數(shù)在被調(diào)用時(shí)都會自動取得this這個特殊的對象冤留。因此浆熔,每個內(nèi)部函數(shù)不能訪問到外部函數(shù)的this對象蛉幸。(跟變量訪問一樣张抄,如果局部環(huán)境存在某個變量,就不會去搜索全局環(huán)境的同名變量)碑定。
** this對象是在運(yùn)行時(shí)基于函數(shù)的執(zhí)行環(huán)境決定的流码。**
執(zhí)行環(huán)境:
a.全局環(huán)境
運(yùn)行在全局上下文(在任何函數(shù)體外部),this指向全局對象延刘,并且漫试,無論是否是在嚴(yán)格模式下,this都指代全局對象访娶。在瀏覽器中商虐,this指向window對象。
console.log(this === window); // true;
b.函數(shù)環(huán)境
在函數(shù)內(nèi)部崖疤,this的值取決于函數(shù)是如何調(diào)用的。
-
直接調(diào)用典勇,非嚴(yán)格模式下劫哼,this默認(rèn)指向全局對象。不管調(diào)用的函數(shù)是在全局函數(shù)還是局部環(huán)境割笙。
function app() { console.log(this === window); // true } app(); // 全局調(diào)用 function foo() { function bar() { console.log(this === window); // true } bar(); // 局部調(diào)用 } foo();
-
直接調(diào)用权烧,嚴(yán)格模式下,this默認(rèn)指向undefined伤溉。不管調(diào)用的函數(shù)是在全局函數(shù)還是局部環(huán)境般码。
'use strict' function app() { console.log(this === undefined); // true } app(); function foo() { function bar() { console.log(this === undefined); // true } bar(); } foo();
-
作為對象調(diào)用
當(dāng)函數(shù)以對象的方法被調(diào)用時(shí),它的this是調(diào)用該函數(shù)的對象乱顾,并且是距離最近的對象板祝。var o = { sayName: function() { console.log(this === o); // true } } o.sayName();
-
作為構(gòu)造函數(shù)調(diào)用
當(dāng)函數(shù)被當(dāng)做構(gòu)造函數(shù)調(diào)用時(shí),this指向剛要被創(chuàng)建的新對象走净。
function Person() { this.name = 'noshower'; } var person = new Person(); console.log(person.name); //'noshower'
-
使用call和apply調(diào)用券时,改變函數(shù)內(nèi)部this的綁定值孤里。
function foo() { console.log(this.name); //'noshower' } var obj = { name: 'noshower' } foo.call(obj);
// 函數(shù)foo內(nèi)部的this對象被綁定到了obj對象上。
-
使用bind方法橘洞,會永久把this與一個對象綁定捌袜。無論這個函數(shù)如何被調(diào)用,都改變不了this炸枣。
function foo() { console.log(this.name); // 'noshower' } var obj1 = { name: 'noshower' } var obj2 = { name: 'DaLin' } var a = foo.bind(obj1); //用bind方法虏等,將this進(jìn)行永久綁定。 a.call(obj2); // 此時(shí)使用call方法將改變不了this的指向适肠。
下面我們開始講ES6箭頭函數(shù)中的this對象
箭頭函數(shù)被調(diào)用的時(shí)候霍衫,不會自動綁定一個this對象。換句話說迂猴,箭頭函數(shù)根本就沒有自己的this慕淡。它的this都是捕獲自其所在上下文的this值。
-
作為匿名函數(shù)被調(diào)用沸毁。
function foo() { console.log(this); //{name:'noshower'} setTimeout(() => { console.log('name:', this.name); //noshower }, 100); } var name = 'DaLin'; foo.call({ name: 'noshower' });
上面代碼中峰髓,我們用call()方法,將函數(shù)foo的this對象綁定到了對象{name:'noshower'}上息尺。由于携兵,箭頭函數(shù)沒有this變量,所以搂誉,箭頭函數(shù)能夠訪問到外部環(huán)境的this變量徐紧。此時(shí),箭頭函數(shù)內(nèi)部炭懊,訪問到的是foo函數(shù)的this對象并级。因此,this.name的值是'noshower'侮腹。
-
作為方法被調(diào)用
var obj = { name: 'noshower', sayName: () => this.name } var name = 'bar'; console.log(obj.sayName());
上面代碼中嘲碧,箭頭函數(shù)是作為對象的方法。因?yàn)楦缸瑁^函數(shù)本身是不綁定this對象的愈涩。因此,它只能從外部搬運(yùn)this對象加矛。上面代碼中履婉,只有全局環(huán)境存在this對象,因此返回的是window.name斟览,即'bar'毁腿。
-
在方法內(nèi)部被調(diào)用
var obj = { name: 'noshower', sayName: function() { var a = () => this.name; console.log(a()); // noshower } } var name = 'bar'; obj.sayName();
上面代碼中,箭頭函數(shù)是在sayName方法中運(yùn)行的。此時(shí)狸棍,箭頭函數(shù)的this對象身害,搬運(yùn)的是sayName方法的this對象。當(dāng)sayName函數(shù)作為方法調(diào)用時(shí)草戈,它的this對象指向obj對象塌鸯。因此,箭頭函數(shù)的this.name就是obj.name,即'noshower';
-
使用new 操作符調(diào)用唐片,會拋出錯誤
var Obj = (name) => { this.name = name; } new Obj('noshower');
上面的代碼丙猬,箭頭函數(shù)作為構(gòu)造函數(shù)被調(diào)用,會報(bào)錯费韭。原因是茧球,箭頭函數(shù)沒有自己的this對象,就沒法給this添加屬性星持。
-
使用call和apply抢埋,bind()調(diào)用
var o = (val) => { console.log(this.name, val); // bar,bar }; var obj = { name: 'foo' } var name = 'bar'; o.call(obj, name);
上面代碼中督暂,箭頭函數(shù)使用了call方法來調(diào)用揪垄。原本想將函數(shù)的this綁定在obj對象上面。結(jié)果顯示逻翁,this被綁定在了全局對象上了饥努。這是因?yàn)椋^函數(shù)沒有自己的this對象八回,此時(shí)使用call方法僅僅起到了傳遞參數(shù)的作用酷愧,沒有改變它的this對象。它的this對象依舊來自外部執(zhí)行環(huán)境缠诅。
總結(jié)一下
箭頭函數(shù)沒有自己的this對象溶浴,它總是搬運(yùn)外部環(huán)境的this對象。因此管引,只要離它最近的外部環(huán)境中的this改變戳葵,箭頭函數(shù)中的this就改變。如果離它最近的環(huán)境中的this汉匙,沒有改變。那么箭頭函數(shù)中的this就不會改變生蚁。