preface
Some time ago, I had a telephone interview, and I remember that there was a content in the interview, asking me about HTTP. I felt very happy in my heart. I read the HTTP diagram twice, and basically refined and recorded all the knowledge points. So easy?
Balabala talked a lot, from HTTP to HTTPS to HTTP2, and added a little bit of http3, and balabala talked a lot, full of confidence. Who knew? One question caught me.
Interviewer: Http2 is multiplexed. Why can’t HTTP1.x be multiplexed? Me: I said because http1.x comes in order. Interviewer: Yes, but why do HTTP1.x come in order? Me: well… I don’t know… Interviewer: HTTP/1.1 is based on text segmentation protocol, also does not have serial number, if multiplexing will result in order confusion,http2 uses frame, equal to cut into blocks, each block has a corresponding serial number, so can achieve multiplexing.
It’s not that this question is good or bad, but it makes me realize that I haven’t studied deeply enough. I should know what it is and why. Think more and sum up more questions, and then yesterday happened to see such an interview question on a little summary
The body of the
What is?
Apply,call, and bind are built-in apis that js uses to specify the execution of this and pass arguments to functions.
How does it work?
//apply
func.apply(thisArg, [argsArray])
//call
fun.call(thisArg, arg1, arg2, ...)
//bind
const newFun = fun.bind(thisArg, arg1, arg2, ...)
newFun()
Copy the code
Apply and call pass different arguments, but both are functions that are called at the same time, while bind returns a function that is bound to this.
One other thing we need to know is what this points to.
This point
The orientation of this is determined during a function call. There are roughly five types of orientation of this.
1. Default binding
The default binding generally occurs in callback functions, which are called directly;
function test() {
// Undefined in strict mode
// Non-strict mode is Window
console.log(this);
}
setTimeout(function () {
//setTimeout is special
// Both strict and non-strict modes are Windows
console.log(this);
});
arr.forEach(function () {
// Undefined in strict mode
// Non-strict mode is Window
console.log(this);
});
Copy the code
2. Implicit binding
This common point can be summed up in one sentence: whoever calls is to whom
const obj = {
name:'joy',
getName(){
console.log(this); //obj
console.log(this.name); //joy}}; obj.getName();Copy the code
3. Display bind call,apply,bind
const obj1 = {
name: 'joy',
getName() {
console.log(this);
console.log(this.name); }};const obj2 = {
name: 'sam'
};
obj1.getName.call(obj2); //obj2 sam
obj1.getName.apply(obj2); //obj2 sam
const fn = obj1.getName.bind(obj2);
fn();//obj2 sam
Copy the code
4. The new binding
function Vehicle() {
this.a = 2
console.log(this);
}
new Vehicle(); // This refers to the object that comes out of Vehicle
Copy the code
5. Arrow functions in ES6
The arrow function in ES6 is special. The arrow function this is this in the parent scope, not this on the call. Remember that the first four methods are determined on call, which is dynamic, whereas the arrow function’s this pointer is static, which is determined when it’s declared. More in line with js lexical scope
window.name = 'win';
const obj = {
name: 'joy'.age: 12.getName: (a)= > {
console.log(this); // The parent scope of this is window, so it is window
console.log(this.name); //win
},
getAge: function () {
// call obj.getAge, where this refers to obj
setTimeout((a)= > {
// So this also refers to obj so the result is 12
console.log(this.age); }); }}; obj.getName(); obj.getAge();Copy the code
Since there are five ways to bind this, there must be a priority
Arrow functions -> New bind -> Show bind call/bind/apply -> Implicit bind -> Default bind
Here is a direct conclusion, interested partners can go to verify their own
To realize the apply
Let’s implement Apply first
- Extend the Function prototype with two methods and accept two parameters.
Function.prototype.myApply = function (context, args) {
}
Copy the code
- Because if you don’t pass the context,this will point to the window, and args will do some fault tolerance
Function.prototype.myApply = function(the context, the args) {/ / default is not on the window is here, you can also use es6 give parameters to set the default context = context | | window args = args? args : [] }Copy the code
- Remember that there are five ways to bind this, and now we’re going to bind this to the called function, and we’re not going to use the default binding and the new binding, so we’re going to use the implicit binding to implement the explicit binding
Function.prototype.myApply = function(the context, the args) {/ / default is not on the window is here, you can also use es6 give parameters to set the default context = context | | window args = args? Const key = Symbol() context[key] = this // Call context[key] by implicitly binding (... args) }Copy the code
- The last step is to return the return value of the function call, and delete the context properties so that it doesn’t matter
Function.prototype.myApply = function(the context, the args) {/ / default is not on the window is here, you can also use es6 give parameters to set the default context = context | | window args = args? args : Const key = Symbol() context[key] = this // Call the function const result = by implicitly binding context[key](... Args) // delete the added attribute delete context[key] // Returns the return value of the function callreturn result
}
Copy the code
Such a simple apply is implemented, there may be some boundary problems and misjudgments need to be improved, so I will not continue to optimize here
Now that Apply is implemented, call is also very simple, except that the parameters are passed differently
To realize the call
So let’s go straight to the code
// Pass parameters from an array to one by one instead of... Arguments can also be used instead of extension operators
Function.prototype.myCall = function (context, ... args) {
// You can also use es6 to set default parameters for parameters
context = context || window
args = args ? args : []
// Add a unique attribute to the context to avoid overwriting the original attribute
const key = Symbol()
context[key] = this
// Call the function with an implicit binding
constresult = context[key](... args)// Delete the added attribute
delete context[key]
// Returns the return value of the function call
return result
}
Copy the code
To realize the bind
The difference between bind and apply is that bind returns a bound function, while apply calls directly. In fact, the implementation is very simple to think about, just return a function, which performs the above apply operation. Point, but there is a need to decide because returns the new function, want to consider to use the new call, and the new priority is higher, so you need to judge the new call, there is also a feature is the bind call can pass, after the call to generate the new function can also be spread, the effect is the same, so it will do a piece Since you’ve already implemented Apply, I’m going to borrow it, but actually not borrowing is just copying the code
Function.prototype.myBind = function(context, ... args) { const fn = this args = args ? args : []return functionnewFn(... newFnArgs) {if (this instanceof newFn) {
returnnew fn(... args, ... newFnArgs) }return fn.apply(context, [...args,...newFnArgs])
}
}
Copy the code
All of the above implementations could use a little more judgment, such as returning or throwing an error when calling something other than function. I won’t deal with it here
So that’s the implementation of apply, Call,bind
At the end
I have been in a daze on the road of learning, stumbling, hoping to become better and better, promoted as soon as possible. Think more, summarize more, practice more. Develop the habit of lifelong learning. Come on!