js中call和apply的實現原理
實現call的思路:
/*
還有就是call方法是放在Function().prototype上的也就是構造函數才有的call方法
(我門可以查看自己的方法的原型鏈上的也就是
方法名.__proto__==Function.prototype 自己定義的構造函數通過原型鏈可以找到原型 Function.prototype中就有call方法 )
那我門就在Function.prototype中定義一個自己的方法實現call的功能
*/
Function.prototype.myCall = function() {
/* 先接受參數把對象和參數區分開 center:對象 arg:參數 */
let [center, ...arg] = [...arguments]
/* 重點 用傳遞過來的對象 添加一個屬性賦值為this(這是我感覺最神奇的地方 后面通過隱式綁定) */
center.storageA = this;
/* 然后執行調用call這個方法的對象 */
/* js中有誰調用的this 就指向誰->this的隱式綁定 然后接收執行的結果 */
let result = center.storageA(...arg)
/* 這句話 就是隱式綁定 center.that(...arg) <==>this.(...arg) 這兩句話等同
在這個函數中this指向的是調用call的這個方法 就是應為Person.call 導致this指向了 Person
同樣的方法通過 center.that讓this指向了center
這個that屬性是自己為了儲存調用call的對象的 在原來的對象中是沒有這個屬性的所有要刪除這個屬性
不刪除的話可以看到that中的結構式Person對象 影響繼承的結構
*/
delete center.storageA return result;
}
補充下:對象的隱式調用,就是在A.call(B)的時候,在call函數內部的this是指向A的(應為js中誰調用this就指向誰的)。
call的第一個參數B是一個我們想讓A函數內部屬性指向的對象,只能再通過隱式調用,把函數A聲明在B的一個屬性中,也就是B.storageA =A ,
我們執行A(),也就是在執行B.storageA() 。把結果返回出去,就是實現了this.指向的變化了
實現apply的思路:
apply和call的區別是參數的傳遞方式不一樣apply的第二個參數式一個數組
實際應用
Function.prototype.myCall = function() {
let [center, ...arg] = [...arguments]
center.that = this;
let result = center.that(...arg)
delete center.that
return result;
}
function Person() {
this.firstname = 'Join'
this.say = function() {
console.log(`my name is: ${this.firstname} ~${this.listname}`)
}
}
function Baby(name) {
this.listname = name Person.myCall(this, this.name)
}
let a = new Baby('inter')