前兩篇文章「執行環境和做用域」和「js中的閉包」,我對談了執行環境、做用域、做用域鏈和閉包的理解。但當牽涉到對象中的方法時,前面談的東西就不那麼適用了。先來看一個例子:javascript
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’,根據"做用域的規則"很好解釋。但問題是:咱們既然使用了這種方式調用函數,確定更但願gentName方法訪問的是對象內部的‘name’屬性。這時,就須要修改外部定義的getName方法了。前面談過在函數執行時,會動態的建立一個活動對象,這個活動對象,被做爲變量對象,推動執行環境棧中。同時,還會建立「arguments」對象和綁定this對象,arguments對象最爲變量對象的第一個屬性,保存着傳入函數中的參數;this對象根據函數的執行環境動態地綁定。有句很經典的判斷this指向的話:誰調用了函數,this就指向誰。java
這樣,只要把getName函數修改爲下面的代碼,就能夠實現訪問對象中name屬性的效果:數組
function getName(){
console.log(this.name)
}複製代碼
依靠上面經典的話,能夠在不少狀況下判斷this的指向,但還有一些狀況不使用。下面就分類來講下this。微信
這是函數最一般的用法。這時,不論函數是在全局做用域下執行,仍是在函數中執行,this都是指向全局對象,也就是window對象。例如:閉包
var person = 'xiaoming'
function f1(){
var person = 'xiaohong'
function f2(){
console.log(this.person)
}
f2()
}
f1(); // 'xiaoming'複製代碼
在函數做爲對象的方法調用時,上面的那句經典的話,就很適用了。這裏來看一個很典型的例子:app
var age = 18;
var obj = {
age : 21,
fn: functoin(){
console.log(this.age)
}
}
(false || obj.fn)() // 18複製代碼
在上面的代碼中,在對象中的fn方法執行以前,會先執行‘||’運算,至關於:函數
(false || function(){
console.log(this.age)
})()複製代碼
實際上,也就是fn方法在全局做用域中執行。因此,結果是18。post
構造函數中的this,指向對象的實例。例如:ui
function People(name){
this.name = name
}
People.prototyope.sayName() = function(){
console.log(this.name)
}
var p = new People('張三');
p.name //‘張三’l
p.sayName //'張三'複製代碼
call、apply和bind方法都是函數對象中的方法,用來動態地改變函數中this的指向,只是用法不一樣。call和apply被調用時,不只改變函數中this指向,並且執行該函數,但bind僅僅是改變函數中this的指向,並不執行。以下:this
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方法在未傳入指定對象時,默認傳入window 對象,所以,o.getX.call() 輸出結果是2。使用bind方法時,僅僅改變函數中this指針的指向,而要執行須要在後面添加'()'。call 和 apply方法在使用時,除了第一個指定this對象的參數外,後面還能夠添加原油函數的其餘參數,call方法接受單個參數的羅列,而apply方法接受數組格式的參數(arguments對象也能夠)。以下:
fn.call(o, param1,param2)
fn.call(o,[param1,param2])複製代碼
var o = {
f1: function() {
console.log(this);
var that = this;
var f2 = function() {
console.log(that);
}();
}
}
o.f1()
// Object
// Object複製代碼
var o = new Object();
o.f = function () {
console.log(this === o);
}
o.f() // true複製代碼
上面的代碼是沒什麼問題的,但當把 o.f 做爲事件處理的回調函數就不同了。例如:$('#button').on('click', o.f);複製代碼
寫在結尾:
若是以爲我寫的文章對你有幫助,歡迎掃碼關注個人公衆號:海痕筆記
微信號:haihenbiji