This binding
This is actually a binding that happens when the function is called, and what it points to depends entirely on where the function is called, right
Four binding rules for this
- The default binding
- Implicit binding
- Explicitly bound
- The new binding
Note: the arrow function does not create its own this, it only inherits this from its upper scope.
The default binding
If a function is called using a function reference without any decoration, only the default binding will be used, pointing to the global object window. In strict mode, this will be bound to undefined(because you cannot use the global object in the default binding).
function foo() { console.log(a); } var a = 2; foo(); / / 2Copy the code
Implicit binding
The call location has context objects
function foo() { console.log(this.a); } var obj = { a: 2, foo: foo } obj.foo(); / / 2Copy the code
Pay attention to
Only the last or upper level of the object attribute reference chain is involved in the call location
function foo() { console.log(this.a); } var obj2 = { a: 42, foo: foo } var obj1 = { a: 2, obj2: obj2 } obj1.obj2.foo(); / / 42Copy the code
Common implicitly bound functions lose the bound object, that is, apply the default binding
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
var bar = obj.foo;
var a = "juejin";
bar(); //juejin
Copy the code
Explicitly bound
By calling call, apply, bind
function foo() { console.log(this.a); } var obj = { a: 2, } var bar = function() { foo.call(obj); } bar(); //2 setTimeout(bar, 100); / / 2Copy the code
The new binding
Javascript’s new operator is completely different from class-oriented languages
In JS, constructors are simply functions that are called when the new operator is used. They do not belong to a class and do not instantiate a class.
All functions, including built-in object functions, can be called with new. Such function calls are called constructor calls
Calling a function with new does the following
- Create a brand new object
- This object is attached to the prototype chain of the executing function, adding a __proto__ attribute to the newly created object
- This new object is bound to the function call’s this
- If the function has no other return object, the function call in the new expression automatically returns the new object.
The new implementation
Grammar:
new constructor[([arguments])]
Copy the code
Implementation:
Function myNew (fn) {// create a new object let res = {}; // if(fn. Prototype! == null) { res.__proto__ = fn.prototype; } let mayberes = fn. Apply (res, [...arguments].slice(1)); / / 4. The judge if ((typeof mayberes = = "object" | | typeof mayberes = = "function") && mayberes! == null) {//4.1 Return mayberes if any other object is returned; } //4.2 does not return a new object created by new; } / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- test mynew function Foo () {enclosing a = 2; } function Boo() { return { b: 2 }; } let obj = mynew(Foo); console.log(obj); //Foo{a:2} let obj2 = mynew(Boo); console.log(obj2); / / {2} b: / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- comparing new let obj1 = new Foo (); console.log(obj1); //Foo{a:2} let obj3 = new Boo(); console.log(obj3); //{b:2}Copy the code
priority
Conclusion: New binding > Explicit binding > Implicit binding > Default binding
It goes without saying that the default binding has the lowest priority
Implicit binding vs. display binding:
function foo() { console.log(this.a); } var obj = { a: 2, foo, }; var obj1 = { a: 4, }; obj.foo(); //2 obj.foo.call(obj1); / / 4Copy the code
Result: Explicit binding has higher priority than implicit binding
Implicit binding vs. new binding:
function foo(val) { this.a = val; } var obj = { foo, }; obj.foo(2); console.log(obj.a); //2 obj1 = new obj.foo(4); console.log(obj1.a); / / 4Copy the code
Result: New binding has higher priority than implicit binding
Explicit binding versus new binding
function foo(val) { this.a = val; } var obj = {}; var boo = foo.bind(obj); boo(2); console.log(obj.a); //2 var obj1 = new boo(3); console.log(obj1.a); / / 3Copy the code
The new binding has higher priority than the explicit binding
call,apply,bind
Three differences:
- Call differs from Apply in the arguments that follow. Call takes a list of arguments, while Apply takes an array of arguments
- Bind returns a function that has changed the context
call
Grammar:
function.call(thisArg, arg1, arg2, ...)
Copy the code
Note:
- ThisArg: When thisArg is null or undefined, it will be automatically replaced with the global object Window
- Call the return value of the function with the this value and arguments provided by the caller. If the method returns no value, undefined is returned.
Implementation:
Function. The prototype. MyCall = Function (context) {/ / by a note that 0 the context = context | | window; Var args = [...arguments].slice(1); // add method 1 //context.fn = this; Var fn = Symbol("juejin"); var fn = Symbol("juejin"); context[fn] = this; Var res = context[fn](context[fn]); args); // Delete method delet context[fn]; return res; } / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- test var name = "yly"; function foo(val) { console.log(this.name, val); return val; } var obj = { name: "dzz", } foo("diy"); //"yly" "diy" console.log(foo.myCall(obj , "diy")); //"dzz" "diy" //diyCopy the code
apply
Grammar:
function.apply(thisArg, [argsArray])
Copy the code
Note:
- ThisArg: When thisArg is null or undefined, it will be automatically replaced with the global object Window
- ArgsArray: An array or array-like object whose array elements are passed as individual arguments to the calling function.
Implementation: Similar to call, except that the parameters are passed differently
Function.prototype.myApply = function(context) { context = context || window; Var args = arguments[1] var args = arguments[1]; [...arguments[1]] : []; var fn = Symbol("juejin"); context[fn] = this; Var res = context[fn](... args); delete context[fn]; return res; } / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- test function foo (val, val1) {the console. The log (this name, val, val1); return val; } var name = "yly"; Var obj = {name: "DZZ ",} var arr = [0,1]; console.log(foo.myApply(obj, arr)); //dzz 0 1 //0 console.log(foo.apply(obj, arr)); //dzz 0 1 //0Copy the code
bind
Grammar:
function.bind(thisArg[, arg1[, arg2[, ...]]])
Copy the code
Note:
- Returns a copy of the original function with a value and initial arguments specifying this, creating a new binding function
- Corrification: Converting a function that takes multiple arguments to a function that takes a single argument.
- The binding function can be constructed using the new operator, which behaves as if the target function has already been constructed. The supplied this value is ignored, but the leading argument is still supplied to the simulation function.
- Bind inherits properties from the function prototype
To:
Simple implementation 1: from 1, you need to use myApply or apply
Function.prototype.myBind = function(context) { //1. Var self = this; var self = this; Return function() {//3. Return self.myapply (context); }} / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- test var a = 1; var b = 2; function foo() { return this.a + this.b; } console.log(foo.myBind({a: 3, b: 4})()); / / 7Copy the code
Next, we need to implement Currization
Simple implementation 12: From 2, here is the simple implementation of the argument into two passes
Function.prototype.myBind = function(context) { //1. Var self = this; var self = this; / / 2. In addition to the context for var preArgs = Array parameters. The prototype. Slice. The call (the arguments, 1); Return function() {//4. Var curArgs = [...preArgs,...arguments]; Return self.myApply(context, curArgs); } //-------------------------- test var a = 1; var b = 2; function foo(c, d) { return this.a + this.b + c + d; } console.log(foo.myBind({a: 3, b: 4}, 5)(6)); / / 18Copy the code
Implementation 3 then points this to the instance and has access to things on the prototype chain
Simple implementation 123: To change this reference after new, we need to check this in the returned function and determine whether the return function is on the current this prototype chain (i.e. we need to name the function before we can proceed).
Function.prototype.myBind = function(context) { //1. Var self = this; var self = this; / / 2. In addition to the context for var preArgs = Array parameters. The prototype. Slice. The call (the arguments, 1); Return function fb() {//4. Var curArgs = [...preArgs,...arguments]; Context = this instanceof fb? this : context; Return self.myApply(context, curArgs); return self.myApply(context, curArgs); }} / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - test var val = "window"; var obj = { val: "obj", }; function foo(name) { this.like = "apple"; console.log(this.val); console.log(name); } var tempFoo = foo.myBind(obj); var boo = new tempFoo("dzz"); / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the bind test var tempFoo1 = foo bind (obj); var coo = new tempFoo1("dzz"); / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the console / / undefined / / DZZ / / undefined / / DZZCopy the code
Finally implementation 4: The prototype of the binding function here can use object.create ()
Final refinement 1234:
Function.prototype.myBind = function(context) { //1. Var self = this; var self = this; / / 2. In addition to the context for var preArgs = Array parameters. The prototype. Slice. The call (the arguments, 1); //3. Return function fb() {//4. Var curArgs = [...preArgs,...arguments]; Context = this instanceof fb? this : context; Return self.myApply(context, curArgs); return self.myApply(context, curArgs); } // Fb.prototype = object.create (this.prototype); return fb; } / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - test var val = "window"; var obj = { val: "obj", }; Foo. Prototype. Card = "name "; function foo(name) { this.like = "apple"; } var tempFoo = foo.myBind(obj); var boo = new tempFoo("dzz"); console.log(boo.card); / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- the bind test var tempFoo1 = foo bind (obj); var coo = new tempFoo1("dzz"); Coo. card = "2"; console.log(coo.card); //-------------- console output // business card // business card 2Copy the code
The caller must be a function, judge
Final version:
Function. The prototype. MyBind = Function (context) {/ / addition to determine whether the Function if (typeof this! == "function") { throw new Error("this must be a function"); } //1. Bind the current this pointer to prevent the return function this pointer error (such as window, actually need to refer to the calling function); / / 2. In addition to the context for var preArgs = Array parameters. The prototype. Slice. The call (the arguments, 1); //3. Return function fb() {//4. Var curArgs = [...preArgs,...arguments]; Context = this instanceof fb? this : context; Return self.myApply(context, curArgs); return self.myApply(context, curArgs); } // Fb.prototype = object.create (this.prototype); return fb; }Copy the code
Extras: Corrified
Currie,
Concept: The technique of converting a function that takes multiple arguments into a series of functions that take one argument
What it does: Use Corrification to avoid passing in the same parameters over and over again
Simple implementation:
Function currying(fn) {//1. To obtain a list of currying parameters, not fn var args = Array. The prototype. Slice. The call (the arguments, 1); Return the function () {/ / 3. Get next to the parameters of the var nextArgs = Array. The prototype. Slice. The call (the arguments); Var finalArgs = args. Concat (nextArgs); Return fn. Apply (null, finalArgs); return fn. }} / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- to test the function sum (a, b) {return a + b; } console.log(sum(2, 3)); Var currySum = currySum; console.log(currySum(2, 3)); //5 var currySum = currying(sum, 2); console.log(currySum(3)); Var currySum = currySum (sum); console.log(currySum(2)); //NaNCopy the code
You can only pass it in two times, and if you pass it in multiple times, then you have to think about it, add judgments and recurse to see if you’ve reached the value that the function passed
Specific implementation:
Function currying(fn) {//1. To obtain a list of currying parameters, not fn var args = Array. The prototype. Slice. The call (the arguments, 1); Return the function () {/ / 3. Get next to the parameters of the var nextArgs = Array. The prototype. Slice. The call (the arguments); Var finalArgs = args. Concat (nextArgs); If (finalArgs. Length < fn.length) {//6. Return a currying function (fn,... finalArgs); } return fn. Apply (null, finalArgs); return fn. }} / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- to test the function sum (a, b, c, d) {return a + b + c + d. } var currySum = currying(sum, 2); console.log(currySum(2)(3)(4)); / / 11Copy the code
conclusion
During the interview, interviewers will sometimes ask about the “this” binding, and having you write a “call” binding yourself. The author is trying to sum up some of his own, improve his JS basic ability. This article is equivalent to a summary article, I hope to see friends harvest full.