call()方法在使用一個指定的 this 值和若干個指定的參數值的前提下調用某個函數或方法
舉例:git
var foo = { value: 1 }; function bar() { console.log(this.value); } bar.call(foo); // 1
根據上面的案例,咱們能夠注意到兩點github
call
改變了this
指向,指向了foobar
函數執行了看到上面的效果,咱們該如何實現呢?
首先咱們能夠將代碼改寫成如下形式數組
var foo = { value: 1, bar:function(){ console.log(this.value) } } foo.bar()
改造事後咱們能夠看到此時的this也是指向foo
的,可是這樣倒是給foo
對象添加了一個屬性bar
的函數,這樣是不合適的,不過咱們能夠使用delete
方法將其刪除,所以步驟能夠分爲如下三步:函數
以上三個步驟就能夠寫作:this
注意:由於是在對象中添加屬性,fn屬性名字能夠隨便寫,反正也要刪除
foo.fn = bar foo.fn() delete foo.fn
根據以上思路實現初版:prototype
Function.prototype.call2 = function (context) { // this誰調用指向誰,此時是函數bar調用call2,由於this指向bar context.fn = this context.fn() delete context.fn } var foo = { value: 1 } function bar() { console.log(this.value) // 1 } bar.call2(foo)
咱們知道call方法還能夠給定參數,能夠看以下案例:code
var foo = { value: 1 } function bar(name, age) { console.log(name) // 張三 console.log(age) // 18 console.log(this.value) // 1 } bar.call(foo, '張三', 18)
可是咱們要知道參數傳遞是不固定的,所以咱們能夠使用在argument
中取值,取出咱們傳遞的第二個參數到最後一個參數,任何添加到一個數組中,實現代碼以下對象
var arg = [] for(var i = 1; i < argument.length; i++){ args.push('arguments[' + i + ']'); } 注意:arguments是一個僞數組,所以要用for循環
解決了傳遞參數不定長的問題,那麼參數放到須要執行的函數參數中應該如何實現呢?get
context.fn(arg.join('')) 這種方法是確定不行的
咱們能夠經過ES3中的eval來實現,這樣就能夠實現函數參數傳遞以及調用了it
eval('context.fn(' + args +')')
因此第二版就實現以下
Function.prototype.call2 = function (context) { context.fn = this var args = [] for (var i = 1; i < arguments.length; i++) { args.push('arguments[' + i + ']') } eval('context.fn(' + args + ')') delete context.fn }
var value = 1 function bar() { console.log(this.value) }
var obj = { value: 1 } function bar(name, age) { return { value: this.value, name, age } } console.log(bar.call(obj, '張三', 18))
不過這個很好實現,直接上最終版
Function.prototype.call2 = function (context) { var context = context || window context.fn = this var args = [] for (var i = 1; i < arguments.length; i++) { args.push('arguments[' + i + ']') } var result = eval('context.fn(' + args + ')') delete fn return result } var obj = { value: 1 } function bar(name, age) { return { value: this.value, name, age } } console.log(bar.call2(obj, '張三', 18))
也能夠使用ES6的語法實現
Function.prototype.call2 = function (context, ...args) { context = context || window // Symbol爲了防止有相同的函數名 let fn = Symbol() context.fn = this const result = context.fn(...args) delete context.fn return result } var foo = { value: 1 } function bar(name, age) { console.log(name) console.log(age) console.log(this.value) }