1. 程式人生 > >JavaScript學習(3)——方法

JavaScript學習(3)——方法

在一個物件中繫結函式,稱為該物件的方法。

在JS中,物件的定義是這樣的:

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;
xiaoming.age();

this指向當前物件。但是this在JS設計中是一個很坑的東西。要保證this的指向正確,必須用obj.xxx()的形式呼叫!
由於這是一個巨大的設計錯誤,要想糾正可沒那麼簡單。ECMA決定,在strict模式下讓函式的this指向undefined,因此,在strict模式下,你會得到一個錯誤:

'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

而且如果在方法的函式內部再指定函式,this又會指向undefined了(strict模式下)。this只在方法的函式中指向物件本身。
所以一個比較好的辦法時,在方法的函式中先用一個變數that捕獲this,然後在定義的函式中用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;
		}
		return getAgeFromBirth();
	}
};

xiaoming.age(); //25

apply
雖然在一個獨立的函式呼叫中,根據是否是strict模式,this指向不同的物件,但是其實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();
getAge.apply(xiaoming, []);

另一個類似的方法是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()我們還可以動態改變函式的行為。
JS的所有物件是動態的,即使內建的函式,我們也可以重新指向新的函式。
例如想要統計一個程式中呼叫了多少次parseInt(),,可以通過替換函式來完成:

'use strict';

car 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