在學習廖雪峰前輩的JavaScript教程中,遇到了一些需要注意的點,是以作為學習筆記列出來,提醒自己注意!
如果大家有需要,歡迎通路前輩的部落格https://www.liaoxuefeng.com/學習。
在一個對象中綁定函數,我們稱這個函數是這個對象的方法。
在前面的學習中,對象的定義如下:
var xiaoming = {
name: '小明',
birth: 1990
};
如果我們給 xiaoming 這個對象綁定一個函數,就可以做更多的事情了。比如,寫個age()方法,傳回xiaoming的年齡:
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年調用是25,明年調用就變成26了
綁定到對象上的函數稱為方法,和普通函數沒什麼差別,但是我們發現,它在内部使用了一個this關鍵字。
在一個方法内部,this是一個特殊的變量,它始終指向目前對象。在上面的例子中,也就是xiaoming這個變量。是以this.birth取到xiaoming的birth屬性。
如果把上面的代碼拆開寫:
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25, 正常結果
getAge(); // NaN
我們發現,單獨調用函數 getAge() 傳回了 NaN 。
注意,在JavaScript中,如果函數内部調用了 this , this 指向誰,有以下幾種情況:
- 如果以對象的方法形式調用,比如 xiaoming.age() ,該函數的this指向被調用的對象,也就是 xiaoming ,這是符合我們預期的。
- 如果單獨調用函數,比如 getAge() ,此時,該函數的 this 指向全局對象,也就是 window 。
如果采用下面的方式,也是錯誤的:
var fn = xiaoming.age; // 先拿到xiaoming的age函數
fn(); // NaN
要保證this指向正确,必須用obj.xxx()的形式調用。
由于種種原因,ECMA決定,在strict模式下讓函數的this指向undefined,是以,在strict模式下,會得到一個錯誤提示,卻并沒有解決this應該指向的正确位置:
'use strict';
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var y = new Date().getFullYear();
return y - this.birth;
}
};
var fn = xiaoming.age;
fn(); // Uncaught TypeError: Cannot read property 'birth' of undefined
假如我們把方法重構一下:
'use strict';
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - this.birth;
}
return getAgeFromBirth();
}
};
xiaoming.age(); // Uncaught TypeError: Cannot read property 'birth' of undefined
結果又報錯了!原因是 this 指針隻在 age 方法的函數内指向 xiaoming ,在函數内部定義的函數, this 又指向 undefined 了!(在非strict模式下,它重新指向全局對象 window !)
我們可以用一個 that 變量首先捕獲 this :
'use strict';
var xiaoming = {
name: '小明',
birth: 1990,
age: function () {
var that = this; // 在方法内部一開始就捕獲this
function getAgeFromBirth() {
var y = new Date().getFullYear();
return y - that.birth; // 用that而不是this
}
return getAgeFromBirth();
}
};
xiaoming.age(); // 25
用 var that = this; ,你就可以放心地在方法内部定義其他函數,而不是把所有語句都堆到一個方法中。
apply
雖然在一個獨立的函數調用中,我們通過strict模式,讓 this 指向 undefined 或者 window ,不過,我們還是有其他辦法控制 this 的指向的:
要指定函數的 this 指向哪個對象,可以用函數本身的 apply 方法,它接收兩個參數,第一個參數就是需要綁定的 this 變量,第二個參數是 Array ,表示函數本身的參數。
用 apply 修複 getAge() 調用:
function getAge() {
var y = new Date().getFullYear();
return y - this.birth;
}
var xiaoming = {
name: '小明',
birth: 1990,
age: getAge
};
xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 參數為空
另一個與 apply() 類似的方法是 call() ,唯一差別是:
- apply() 把參數打包成 Array 再傳入;
- call() 把參數按順序傳入。
比如調用 Math.max(3, 5, 4) ,分别用 apply() 和 call() 實作如下:
Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5
對普通函數調用,我們通常把 this 綁定為 null 。
裝飾器
利用 apply() ,我們還可以動态改變函數的行為。
JavaScript的所有對象都是動态的,即使内置的函數,我們也可以重新指向新的函數。
現在假定我們想統計一下代碼一共調用了多少次 parseInt() ,可以把所有的調用都找出來,然後手動加上
count += 1 ,不過這樣做太傻了。最佳方案是用我們自己的函數替換掉預設的 parseInt() :
'use strict';
var count = 0;
var oldParseInt = parseInt; // 儲存原函數
window.parseInt = function () {
count += 1;
return oldParseInt.apply(null, arguments); // 調用原函數
// 測試:
parseInt('10');
parseInt('20');
parseInt('30');
console.log('count = ' + count); // 3
轉載于:https://www.cnblogs.com/whucs2012/p/7885488.html