apply call bind related
For apply call bind, I also wrote a very detailed entry-level article before apply, call, bind usage and differences
After understanding the usage, it is better to understand its implementation principle so that you can grasp it thoroughly
The difference between the three
call
Andapply
they are made to address changingthis
points. The effect is the same, but the way of passing parameters is different- In addition to the first parameter,
call
you can receive a list of parameters, andapply
only accept an array of parameters bind
The effect is the same as the other two methods, except that the method returns a function. Will not be executed immediately
Handwritten call
-
Handle the needs:
- Change this point. Point to window by default
- Can receive multiple parameters
- Execute the method after changing this request
- All methods mount this
myCall
-
Analyze the realization ideas:
- For
this
. Just remember that whoever calls the method, this will point to (except for arrow functions), and let the object/window passed in to call the method. - Receive multiple parameters:
arguments
or es6 new syntax:...args
- Execute the function immediately, sprinkle water
- All methods are mounted, then the prototype chain is used, mounted on the
Function
object
- For
-
Everything is ready, start to achieve:
Function.prototype.myCall = function(context, ...args) {
// 默认的window对象
context = context && typeof context === 'object' ? context : window
// 防止覆盖掉原有属性
const key = Symbol()
// 这里的this为需要执行的方法
context[key] = this
// 方法执行
const result = context[key](...args)
delete context[key]
return result
}
- Summarize the implementation
- First, make sure that the new pointer is an object type
object
. Otherwise, all are windows by default. Of course, typeof null is also equal to "object". So we have to use a judgment to ensure that the context exists Symbol
Role: to prevent conflicts of attribute names. Why do you want to do this? Because we need to put a property on the new object, this property is the old onethis
. But how to ensure that new properties and notcontext
the original attributes conflict it? Then useSymbol
- It might be above
context[key] = this
doubt. This is why in the end, why should the newcontext
release of this old object? There will be code explanation principles later - There is no problem with the execution method~
- Finally
delete
out our new property, after all, can not affect the originalcontext
target
- First, make sure that the new pointer is an object type
What is the small expansion context[key] = this?
Understanding context[key] = this
has a very important significance for the entire handwritten code implementation
First of all, the principle that has remained unchanged for thousands of years: whoever calls a method, this points to whom.
Then why notcontext
call the corresponding method?
Becausecontext
basically there is no corresponding method
Use a small example to understand the problem
let data = {
key: 1,
name: 'Jioho',
say: function() {
console.log(this.name)
}
}
function fn() {
console.log(this.name)
}
data.say() // Jioho
fn() // 打印为空
// 那如果这样:
data.sayfn = fn
data.sayfn() // Jioho
- Gap appeared, as long as the corresponding method in which an object, the method will be able to get the current
this
instance context[key] = this
The same is true. This timethis
is the original functionthis
. The this in the original function has its own method. So we directly assign the entire this tocontext
. Just like the 16th line of the code above- As we start
key
whySymbol
. It's just that we are afraid of the same name if our 16th new attribute is not calledsayfn
. Calledsay
, then our subsequent operations will affect the properties of the original object. This is a problem that must not arise!
Handwriting apply
If handwriting call after understanding apply just a question pass Senate
The rest of the code does not need to be changed, just need to be an array type when receiving the second parameter
Function.prototype.myApply = function(context, args = []) {
// 默认的window对象
context = context && typeof context === 'object' ? context : window
// 防止覆盖掉原有属性
const key = Symbol()
// 这里的this为需要执行的方法
context[key] = this
// 方法执行
const result = context[key](...args)
delete context[key]
return result
}
Handwriting bind
-
Handle the needs:
- Change this point. Point to window by default
- Parameters before calling bind, you can pass in multiple
- In the returned function, you can continue to pass parameters. This scene is still very practical
- All methods mount this
myBind
-
Analyze the realization ideas:
- No need to change this point on to say, whether it is handwritten achieve, or use the original
apply
orcall
will do - Can pass multiple parameters before calling bind, it is still used
arguments
or...args
unified received - bind needs to return one
函数
. And you can continue to pass parameters in the new function, then you need to use closures - All methods are mounted, then the prototype chain is used, mounted on the
Function
object
- No need to change this point on to say, whether it is handwritten achieve, or use the original
Function.prototype.myBind = function(context, ...args) {
context = context && typeof context === 'object' ? context : window
const _self = this
return function(...args2) {
return _self.apply(context, [...args, ...args2])
}
}
// 接下来验证一下:
var data = {
baseCount: 10 }
function add(num1, num2) {
return this.baseCount + num1 + num2
}
// 调用方法
var addBind = add.myBind(data, 1)
addBind(2) // 13
// 或者这样写
add.myBind(data, 1)(2) // 13
- Summarize the implementation
- The same years
context
to achieve - Because there are ways to receive a plurality of parameters two times, we used
...args
to receive also must be an array of. So it’s most appropriate to use apply in the returned function.
- The same years
Don't underestimate the seemingly weird way of writing bind. Why do you have to pass the parameter twice? When we talk about complex currying later, we will discover the charm of bind now.
The original post was published in: apply call bind related new blog address, if you are interested, you can check it out~