const person = { name:"小明" } function sayName() { console.log(this.name) } sayName.call(person) //result: 小明
上面的代碼有兩個步驟javascript
- call 改變了this 的指向,指向變爲 person
- sayName 函數執行了
//猜想 const person = { name:"小明", sayName() { console.log(this.name) } } //此時的this絕壁指向person,可是要實現call 咱們很差給每一個對象都加屬性,but 加了在刪除好像也沒啥
- 給person 對象添加fn方法
- sayName函數執行
- 刪除person中的fn方法
Function.prototype.myCall = function (obj) { console.log(obj) // { name: '小明' } console.log(this) //[Function: sayName] } //看到上面的打印結果是否是心中已經有了答案
按照三個步驟實現java
Function.prototype.myCall = function (obj) { obj.fn = this obj.fn() delete obj.fn } sayName.myCall(person) //result: 小明
咱們知道call函數的參數除了能夠改變this指向的對象,還能夠傳入指定的其餘參數 好比下面:數組
const person = { name: "小明" } function sayName(age, phone) { console.log(age) console.log(phone) console.log(this.name) } sayName.call(person, 12, 12345) // 12 12345 小明
可是參數的數量不可控 因而咱們能夠這麼寫 tips:1.arguments 是一個類數組對象 不是一個真的數組 2.eval 是個很特殊的方法 網上褒貶不一函數
Function.prototype.myCall = function (obj) { obj.fn = this let _arguments = deepCopy(arguments) delete _arguments[0] let args = [] for (let key in _arguments) { args.push(_arguments[key]) } let args_str= args.join() // obj.fn(args_str) 這種作法顯然不行 至關於只傳進了一個字符串 eval('obj.fn(' + args_str +')'); //經過eval處理 delete obj.fn } sayName.myCall(person, 12, 12345) //12 12345 小明
寫到這裏是否是很開心(^▽^),咱們已經完成90%啦優化
1.call(obj) 萬一obj爲null怎麼辦?this
let name = "上帝" function sayName() { console.log(this.name) } console.log(sayName.call(null)) //上帝
2.call 最終應該有返回spa
function getU(age, phone) { return{ age, phone } } console.log(getU.call(person)) //{ age: undefined, phone: undefined }
解決起來很簡單,代碼以下prototype
Function.prototype.myCall = function (obj) { obj = obj || window ... ... ... const result = eval('obj.fn(' + args_str +')'); ... return result } console.log("result",getU.myCall(person, 12, 12345)) //result { age: 12, phone: 12345 }
到此爲止咱們的call 就寫完啦,(^▽^)code