在JavaScript中,函數運行時都具備特定的做用域,以下代碼:javascript
var name = 'Jack'; var person = { name: 'Bob', sayName: function(code, msg){ console.log(code, msg + this.name); } } person.sayName(0, 'hello ');// 0 "hello Bob" var newSay = person.sayName; newSay(0, 'hello ');// 0 "hello Jack"
先聲明一個name
變量,而後聲明一個person
對象,person
包含name
和sayName
屬性。當直接在對象上進行方法的調用時:person.sayName()
,函數的做用域遵循「誰調用就是誰」的原則,sayName
的做用域(也就是this
)指向的就是person
。java
當把person.sayName
賦值給新變量newSay
時,調用newSay()
爲直接的函數調用,此時函數的做用域變爲了window
。本質上來說,newSay()
至關於window.newSay()
,因此一樣也是遵循「誰調用就是誰」的原則。數組
可是函數有三個方法能夠用來設置做用域,分別爲apply
、call
、bind
。app
仍是上面的例子,使用以下方式調用:函數
person.sayName.apply(window, [0, 'hello ']);//0 "hello Jack"
apply
接收兩個參數,第一個參數爲函數運行時的做用域,也就是this
的值,這樣就能夠人爲的改變函數運行時的做用域了。this
使用call
方法也是同樣:code
person.sayName.call(window, 0, 'hello ');//0 "hello Jack"
區別在於apply
接收一個數組用於函數的參數,而call
須要把參數一一列出。對象
對於bind
,來看下面的代碼:ip
var newSay2 = person.sayName.bind(person); newSay2(0, 'hello');//0 "hello Bob" console.log(person.sayName === newSay);// true console.log(person.sayName === newSay2);// false
bind
也是改變了做用域,但bind
建立了一個新的函數,這個函數具備和原函數相同的代碼體。而apply
和call
都是調用的原函數。作用域