Simulation Implementation of call method
Preliminary consideration
const person = { name:"Xiao Ming" } function sayName() { console.log(this.name) } sayName.call(person) //result: Xiaoming
The above code has two steps
- call changes the direction of this to person
- The sayName function executed
//guess const person = { name:"Xiao Ming", sayName() { console.log(this.name) } } //At this time, the "this" cliff points to person, but to implement call, we can't add attributes to every object, but adding and deleting doesn't seem to matter
First step trial version
- Add fn method to person object
- sayName function execution
- Remove fn method from person
Function.prototype.myCall = function (obj) { console.log(obj) // {name: 'Xiaoming'} console.log(this) //[Function: sayName] } //See the printing result above, do you have the answer in mind
Implement in three steps
Function.prototype.myCall = function (obj) { obj.fn = this obj.fn() delete obj.fn } sayName.myCall(person) //result: Xiaoming
Step 2 add parameter version
We know that the parameters of the call function can not only change the object this points to, but also pass in other specified parameters, such as the following:
const person = { name: "Xiao Ming" } function sayName(age, phone) { console.log(age) console.log(phone) console.log(this.name) } sayName.call(person, 12, 12345) // 12 12345 Xiaoming
But the number of parameters is not controllable, so we can write tips as follows: 1.arguments is an array like object, not a real array. 2.eval is a very special method. There are different opinions on the Internet
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) is obviously not the same as passing in only one string eval('obj.fn(' + args_str +')'); //Processed by eval delete obj.fn } sayName.myCall(person, 12, 12345) //12 12345 Xiaoming
Are you happy to write here? We have finished 90%
Step 3 ultimate evolution optimized version
1.call(obj) what if obj is null?
let name = "lord" function sayName() { console.log(this.name) } console.log(sayName.call(null)) //lord
2.call should return at last
function getU(age, phone) { return{ age, phone } } console.log(getU.call(person)) //{ age: undefined, phone: undefined }
The solution is very simple. The code is as follows
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 }
So far, we have finished our call