一、先看個(gè)函數(shù)調(diào)用例子
例子來源https://blog.csdn.net/Rainy_X/article/details/80022684
function Foo() {
getName = function () { alert(1); };
return this;
}
Foo.getName = function () { alert(2); };
Foo.prototype.getName = function () { alert(3); };
var getName = function () { alert(4); };
Foo.getName(); // ------- 輸出 2 -------
// 調(diào)用 Foo函數(shù) 作為 對(duì)象 動(dòng)態(tài)添加的屬性方法 getName
// Foo.getName = function () { alert(2); };
getName(); // ------- 輸出 4 -------
// 這里 Foo函數(shù) 還沒有執(zhí)行,getName還沒有被覆蓋
// 所以 這里還是 最上面的 getName = function () { alert(4); };
Foo().getName(); // ------- 輸出 1 -------
// Foo()執(zhí)行,先覆蓋全局的 getName 再返回 this,
// this 是 window, Foo().getName() 就是調(diào)用 window.getName
// 此時(shí) 全局的 getName已被覆蓋成 function () { alert(1); };
// 所以 輸出 1
/* 從這里開始 window.getName 已被覆蓋 alert 1 */
getName(); // -------- 輸出 1 --------
// window.getName alert(1);
new Foo.getName(); // ------- 輸出 2 -------
// new 就是 找 構(gòu)造函數(shù)(),由構(gòu)造函數(shù)結(jié)合性,這里即使 Foo無參,也不能省略 (),所以不是 Foo().getName()
// 所以 Foo.getName 為一個(gè)整體,等價(jià)于 new (Foo.getName)();
// 而 Foo.getName 其實(shí)就是函數(shù) function () { alert(2); } 的引用
// 那 new ( Foo.getName )(), 就是在以 Foo.getName 為構(gòu)造函數(shù) 實(shí)例化對(duì)象。
// 就 類似于 new Person(); Person 是一個(gè)構(gòu)造函數(shù)
// 總結(jié)來看 new ( Foo.getName )(); 就是在以 function () { alert(2); } 為構(gòu)造函數(shù)來構(gòu)造對(duì)象
// 構(gòu)造過程中 alert( 2 ),輸出 2
new Foo().getName(); // ------- 輸出 3 -------
// new 就是 找 構(gòu)造函數(shù)(),等價(jià)于 ( new Foo() ).getName();
// 執(zhí)行 new Foo() => 以 Foo 為構(gòu)造函數(shù),實(shí)例化一個(gè)對(duì)象
// ( new Foo() ).getName; 訪問這個(gè)實(shí)例化對(duì)象的 getName 屬性
// 實(shí)例對(duì)象自己并沒有 getName 屬性,構(gòu)造的時(shí)候也沒有 添加,找不到,就到原型中找
// 發(fā)現(xiàn) Foo.prototype.getName = function () { alert(3); };
// 原型中有,找到了,所以 ( new Foo() ).getName(); 執(zhí)行,alert(3)
var p = new new Foo().getName(); // ------- 輸出 3 -------
// new 就是 找 構(gòu)造函數(shù)(),等價(jià)于 new ( ( new Foo() ).getName )() 輸出 3
// 先看里面的 ( new Foo() ).getName
// new Foo() 以Foo為構(gòu)造函數(shù),實(shí)例化對(duì)象
// new Foo().getName 找 實(shí)例對(duì)象的 getName屬性,自己沒有,去原型中找,
// 發(fā)現(xiàn) Foo.prototype.getName = function () { alert(3); }; 找到了
// 所以里層 ( new Foo() ).getName 就是 以Foo為構(gòu)造函數(shù)實(shí)例出的對(duì)象的 一個(gè)原型屬性
// 屬性值為一個(gè)函數(shù) function () { alert(3); } 的引用
// 所以外層 new ( (new Foo()).getName )()在以該函數(shù) function () { alert(3); } 為構(gòu)造函數(shù),構(gòu)造實(shí)例
// 構(gòu)造過程中 執(zhí)行了 alert(3), 輸出 3
二、 自執(zhí)行函數(shù)(匿名函數(shù))
每個(gè)函數(shù)在調(diào)用時(shí),都會(huì)去獲取2個(gè)值: arguments和this。
匿名函數(shù)在獲取這2個(gè)值時(shí),只會(huì)搜索自己執(zhí)行環(huán)境中的,永遠(yuǎn)不會(huì)直接訪問外部函數(shù)或執(zhí)行環(huán)境中的這2個(gè)變量。
匿名函數(shù)是一個(gè)沒有指針的全局變量,它的執(zhí)行環(huán)境具有全局性,所以它的this指向的就是全局window對(duì)象
(function(){
console.log(this);//this指向的是window
})();
三、 定時(shí)器中的函數(shù)
定時(shí)器中的函數(shù)和匿名函數(shù)一樣(沒有默認(rèn)的宿主對(duì)象),所以默認(rèn)this指向window,如果想要在setTimeout/setInterval中使用這個(gè)對(duì)象的this引用,可以使用如 _this = this保存this指針
var obj = {
func: function() {
console.log("123")
},
say: function () {
var _this = this; //此時(shí)的this就是obj對(duì)象
setTimeout(function () {
console.log(this) // window
_this.func() // "123"
});
}
}
obj.say();