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

  1. Create a brand new object
  2. This object is attached to the prototype chain of the executing function, adding a __proto__ attribute to the newly created object
  3. This new object is bound to the function call’s this
  4. 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:

  1. Call differs from Apply in the arguments that follow. Call takes a list of arguments, while Apply takes an array of arguments
  2. Bind returns a function that has changed the context

call

Grammar:

function.call(thisArg, arg1, arg2, ...)
Copy the code

Note:

  1. ThisArg: When thisArg is null or undefined, it will be automatically replaced with the global object Window
  2. 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:

  1. ThisArg: When thisArg is null or undefined, it will be automatically replaced with the global object Window
  2. 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:

  1. Returns a copy of the original function with a value and initial arguments specifying this, creating a new binding function
  2. Corrification: Converting a function that takes multiple arguments to a function that takes a single argument.
  3. 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.
  4. 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.