前兩篇文章“執(zhí)行環(huán)境和作用域”和“js中的閉包”行剂,我對談了執(zhí)行環(huán)境、作用域钳降、作用域鏈和閉包的理解厚宰。但當(dāng)牽涉到對象中的方法時(shí),前面談的東西就不那么適用了遂填。先來看一個(gè)例子:
var name = 'a';
function getName(){
console.log(name);
}
var o1 ={
name: 'a1',
getName: getName
}
var o2 ={
name: 'a2',
getName: getName
}
o1.getName() // 'a'
o2.getName() // 'a'
上面的代碼中铲觉,o1.getName()和o2.getName()都輸出‘a(chǎn)’澈蝙,根據(jù)"作用域的規(guī)則"很好解釋。但問題是:我們既然使用了這種方式調(diào)用函數(shù)撵幽,肯定更希望gentName方法訪問的是對象內(nèi)部的‘name’屬性灯荧。這時(shí),就需要修改外部定義的getName方法了并齐。前面談過在函數(shù)執(zhí)行時(shí)漏麦,會(huì)動(dòng)態(tài)的創(chuàng)建一個(gè)活動(dòng)對象,這個(gè)活動(dòng)對象况褪,被作為變量對象撕贞,推進(jìn)執(zhí)行環(huán)境棧中。同時(shí)测垛,還會(huì)創(chuàng)建“arguments”對象和綁定this對象捏膨,arguments對象最為變量對象的第一個(gè)屬性,保存著傳入函數(shù)中的參數(shù)食侮;this對象根據(jù)函數(shù)的執(zhí)行環(huán)境動(dòng)態(tài)地綁定号涯。有句很經(jīng)典的判斷this指向的話:誰調(diào)用了函數(shù),this就指向誰锯七。
這樣链快,只要把getName函數(shù)修改成下面的代碼,就可以實(shí)現(xiàn)訪問對象中name屬性的效果:
function getName(){
console.log(this.name)
}
依靠上面經(jīng)典的話眉尸,可以在很多情況下判斷this的指向域蜗,但還有一些情況不使用。下面就分類來說下this噪猾。
1霉祸、純粹的函數(shù)調(diào)用
這是函數(shù)最通常的用法。這時(shí)袱蜡,不論函數(shù)是在全局作用域下執(zhí)行丝蹭,還是在函數(shù)中執(zhí)行,this都是指向全局對象坪蚁,也就是window對象奔穿。例如:
var person = 'xiaoming'
function f1(){
var person = 'xiaohong'
function f2(){
console.log(this.person)
}
f2()
}
f1(); // 'xiaoming'
2、作為對對象的方法調(diào)用
在函數(shù)作為對象的方法調(diào)用時(shí)迅细,上面的那句經(jīng)典的話巫橄,就很適用了。這里來看一個(gè)很典型的例子:
var age = 18;
var obj = {
age : 21,
fn: functoin(){
console.log(this.age)
}
}
(false || obj.fn)() // 18
在上面的代碼中茵典,在對象中的fn方法執(zhí)行之前湘换,會(huì)先執(zhí)行‘||’運(yùn)算,相當(dāng)于:
(false || function(){
console.log(this.age)
})()
實(shí)際上,也就是fn方法在全局作用域中執(zhí)行彩倚。所以筹我,結(jié)果是18。
3帆离、構(gòu)造函數(shù)
構(gòu)造函數(shù)中的this蔬蕊,指向?qū)ο蟮膶?shí)例。例如:
function People(name){
this.name = name
}
People.prototyope.sayName() = function(){
console.log(this.name)
}
var p = new People('張三');
p.name //‘張三’l
p.sayName //'張三'
4哥谷、call岸夯、apply和bind
call、apply和bind方法都是函數(shù)對象中的方法们妥,用來動(dòng)態(tài)地改變函數(shù)中this的指向猜扮,只是用法不同。call和apply被調(diào)用時(shí)监婶,不僅改變函數(shù)中this指向旅赢,而且執(zhí)行該函數(shù),但bind僅僅是改變函數(shù)中this的指向惑惶,并不執(zhí)行煮盼。如下:
var x = 2;
var y = 3;
function getY(){
console.log(this.y)
}
var o = {
x: 1,
y: 4,
getX: function(){
console.log(this.x)
}
}
o.getX.call() //2
getY.bind(o)() // 4
call、apply和bind方法在未傳入指定對象時(shí)带污,默認(rèn)傳入window 對象僵控,因此,o.getX.call() 輸出結(jié)果是2鱼冀。使用bind方法時(shí)喉祭,僅僅改變函數(shù)中this指針的指向,而要執(zhí)行需要在后面添加'()'雷绢。call 和 apply方法在使用時(shí),除了第一個(gè)指定this對象的參數(shù)外理卑,后面還可以添加原油函數(shù)的其他參數(shù)翘紊,call方法接受單個(gè)參數(shù)的羅列,而apply方法接受數(shù)組格式的參數(shù)(arguments對象也可以)藐唠。如下:
fn.call(o, param1,param2)
fn.call(o,[param1,param2])
注意點(diǎn)
- this的指向是不確定的帆疟,不要在函數(shù)中包含多層的this。在必要時(shí)宇立,可以將this賦值給其他的變量踪宠,再使用。例如:self妈嘹,that等柳琢。例如:
var o = {
f1: function() {
console.log(this);
var that = this;
var f2 = function() {
console.log(that);
}();
}
}
o.f1()
// Object
// Object
- 避免回調(diào)函數(shù)中的this:回調(diào)函數(shù)中的this往往會(huì)改變指向,最好避免使用。例如:
var o = new Object();
o.f = function () {
console.log(this === o);
}
o.f() // true
上面的代碼是沒什么問題的柬脸,但當(dāng)把 o.f 作為事件處理的回調(diào)函數(shù)就不一樣了他去。例如:
$('#button').on('click', o.f);
寫在結(jié)尾:
如果覺得我寫的文章對你有幫助,歡迎掃碼關(guān)注我的公眾號(hào):海痕筆記
微信號(hào):haihenbiji
![](https://dn-mhke0kuv.qbox.me/cf3137a57e8c26b29602.jpg)