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