JavaScript中的this比較靈活,根據(jù)在不同環(huán)境下,或者同一個(gè)函數(shù)在不同方式調(diào)用下,this都有可能是不同的。但是有一個(gè)總的原則,那就是this指的是,調(diào)用函數(shù)的那個(gè)對(duì)象。
下面是我的學(xué)習(xí)筆記,把它羅列成8種情況。
全局的this(瀏覽器)
全局作用域的this一般指向全局對(duì)象,在瀏覽器中這對(duì)象就是window,在node中這對(duì)象就是global。
console.log(this.document === document); // true (document === window.document) console.log(this === window); // true this.a = 37; //相當(dāng)于創(chuàng)建了一個(gè)全局變量a console.log(window.a); // 37
一般函數(shù)的this(瀏覽器)
一般的函數(shù)聲明或者函數(shù)表達(dá)式,直接調(diào)用函數(shù)的話,this依然指向全局對(duì)象,在瀏覽器中這對(duì)象就是window,在node中這對(duì)象就是global。
function f1(){
return this;
}
f1() === window; // true, global object
再舉一個(gè)例子,看完就非常透徹了
function test(){
this.x = 1;
alert(this.x);
}
test(); // 1
為了證明this就是全局對(duì)象,對(duì)代碼做一些改變:
var x = 1;
function test(){
alert(this.x);
}
test(); // 1
運(yùn)行結(jié)果還是1。再變一下:
var x = 1;
function test(){
this.x = 0;
}
test();
alert(x); //0
但是在嚴(yán)格模式下,一般函數(shù)調(diào)用的時(shí)候this指向undefined,這也是node為什么要用嚴(yán)格模式的一個(gè)原因。
function f2(){
"use strict"; // see strict mode
return this;
}
f2() === undefined; // true
作為對(duì)象方法的函數(shù)的this
this作為對(duì)象方法來使用是比較常見的。
下面這個(gè)例子,我們創(chuàng)建了一個(gè)對(duì)象字面量o,o里面有個(gè)屬性f,它的值是一個(gè)函數(shù)對(duì)象,把函數(shù)作為對(duì)象屬性的值這種方式我們常常叫作對(duì)象的方法。作為對(duì)象的方法調(diào)用的時(shí)候,這時(shí)候this指向?qū)ο髈
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // logs 37
我們不一定要定義成函數(shù)字面量這樣子的對(duì)象,像下面這種情況,我們只定義了一個(gè)對(duì)象o,如果直接調(diào)用independent()函數(shù)的話,this會(huì)指向window,但是我們通過賦值的方式,臨時(shí)創(chuàng)建一個(gè)屬性f,并指向函數(shù)對(duì)象的時(shí)候,我們?nèi)匀荒玫搅?7。
var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // logs 37
所以并不是看函數(shù)是怎么創(chuàng)建的,而是只要將函數(shù)作為對(duì)象的方法去調(diào)用,this就會(huì)指向這個(gè)對(duì)象。
對(duì)象原型鏈上的this
下面這個(gè)例子中:我們先創(chuàng)建了一個(gè)對(duì)象o,里面有一個(gè)屬性f,函數(shù)作為對(duì)象屬性的值,我們通過Object.create(o)創(chuàng)建了一個(gè)對(duì)象p,p是一個(gè)空對(duì)象,它的原型會(huì)指向o,然后使用p.a = 1; p.b = 4創(chuàng)建對(duì)象p上的屬性,那么我們調(diào)用原型上的方法時(shí),this.a,this.b依然能取到對(duì)象p上的a和b。這里需要注意的是p的原型才是o,我們調(diào)用p.f(),調(diào)用的是原型鏈o上的屬性f,原型鏈上的this可以拿到當(dāng)前的對(duì)象p。
var o = {f:function(){ return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
get/set方法與this
get/set方法中的this一般會(huì)指向get/set方法所在對(duì)象里面
function modulus(){
return Math.sqrt(this.re * this.re + this.im * this.im);
}
var o = {
re: 1,
im: -1,
get phase(){
return Math.atan2(this.im, this.re);
}
};
Object.defineProperty(o, 'modulus', { //臨時(shí)動(dòng)態(tài)給o對(duì)象創(chuàng)建modules屬性
get: modulus, enumerable:true, configurable:true});
console.log(o.phase, o.modulus); // logs -0.78 1.4142
構(gòu)造函數(shù)中的this
用new把MyClass作為構(gòu)造函數(shù)調(diào)用的話,this會(huì)指向空的對(duì)象,并且這個(gè)對(duì)象的原型會(huì)指向MyClass.prototype(可以看這篇文章對(duì)原型鏈的總結(jié)),但是調(diào)用的時(shí)候做了this.a = 37的賦值,所以最后this會(huì)作為返回值(沒寫return語句,或者return的是基本類型的話,會(huì)將this作為返回值),第二個(gè)例子return語句返回了對(duì)象,那么就會(huì)將a = 38作為返回值
function MyClass(){
this.a = 37;
}
var o = new MyClass();
console.log(o.a); // 37
function C2(){
this.a = 37;
return {a : 38};
}
o = new C2();
console.log(o.a); // 38
call/apply方法與this
除了不同的調(diào)用方式外,函數(shù)對(duì)象有些方法能修改函數(shù)執(zhí)行的this,比如call/apply。
call和apply基本上沒差別,只不過call傳參的方式是扁平的,而apply是把一個(gè)數(shù)組傳進(jìn)去。如下面這個(gè)例子
什么時(shí)候用call和apply呢?比如我們想調(diào)用Object.prototype.toString,但是我們想指定某個(gè)this的時(shí)候,那我們就可以就用Object.prototype.toString.call(this)這樣子的方式來調(diào)用些無法直接調(diào)用的方法。如下面這個(gè)例子:
function add(c, d){
return this.a + this.b + c + d;
}
var o = {a:1, b:3};
add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 //第一個(gè)參數(shù)接收的是你想作為this的對(duì)象
add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
function bar() {
console.log(Object.prototype.toString.call(this));
}
bar.call(7); // "[object Number]"
bind方法與this
bind方法是es5開始提供的,所以ie9+才支持
function f(){
return this.a;
}
var g = f.bind({a : "test"}); //想把某個(gè)對(duì)象作為this的時(shí)候,就把它傳進(jìn)去,得到一個(gè)新對(duì)象g
console.log(g()); // test //重復(fù)調(diào)用的時(shí)候,this已經(jīng)指向bind參數(shù)。這對(duì)于我們綁定一次需要重復(fù)調(diào)用依然實(shí)現(xiàn)綁定的話,會(huì)比apply和call更加高效(看下面這個(gè)例子)
var o = {a : 37, f : f, g : g};
console.log(o.f(), o.g()); // 37, test //o.f()通過對(duì)象的屬性調(diào)用,this指向?qū)ο髈;比較特殊的是即使我們把新綁定的方法作為對(duì)象的屬性調(diào)用,o.g()依然會(huì)按之前的綁定去走,所以答案是test不是g
總結(jié)
做項(xiàng)目的時(shí)候才發(fā)現(xiàn)這些基礎(chǔ)概念有多么的重要,如果不把它們逐個(gè)落實(shí)了,真的是一不小心就會(huì)掉進(jìn)坑里。后續(xù)我還會(huì)對(duì)原型鏈,作用域,繼承,鏈?zhǔn)秸{(diào)用,正則等知識(shí)進(jìn)行總結(jié),歡迎關(guān)注
哈爾濱品用軟件有限公司致力于為哈爾濱的中小企業(yè)制作大氣、美觀的優(yōu)秀網(wǎng)站,并且能夠搭建符合百度排名規(guī)范的網(wǎng)站基底,使您的網(wǎng)站無需額外費(fèi)用,即可穩(wěn)步提升排名至首頁。歡迎體驗(yàn)最佳的哈爾濱網(wǎng)站建設(shè)。
