From learning bind to implementing bind in Javascript, javascriptbind

Source: Internet
Author: User

From learning bind to implementing bind in Javascript, javascriptbind

What is bind?

Bind () method to create a new function. When called, set this keyword to the provided value. When calling a new function, provide a given parameter sequence before any provision.

var result = fun.bind(thisArg[, arg1[, arg2[, ...]]]) result(newArg1, newArg2...)

I can't understand it.

What did bind do?

From the above introduction, we can see three points. First, calling the bind method will return a new function (the function body of this new function should be the same as fun ). At the same time, bind passes two parameters. The first one is the point of this, that is, what is passed in this is equal to what. The following code is used:

This. value = 2var foo = {value: 1} var bar = function () {console. log (this. value)} var result = bar. bind (foo) bar () // 2 result () // 1, that is, this = foo

The second parameter is a sequence, and you can pass any number of parameters to it. The parameter is preset before the new function parameter.

This. value = 2var foo = {value: 1}; var bar = function (name, age, school) {console. log (name) // 'any' console. log (age) // 22 console. log (school) // ' '} var result = bar. bind (foo, 'any') // some parameters are preset, such as 'A' result (22, 'hometown ') // This parameter will be combined with the preset parameter and put into the bar

We can see that when the final call result (22, 'home ') is called, it contains the 'A' passed in when the bind is called '.

In a word, a new function is returned when bind is called. This in this function points to the first parameter of bind, and the parameters after this will be passed to this new function in advance. When the new function is called, the parameters that are passed are placed in the preset parameters and then passed to the new function.

Implement a bind by yourself

To implement a bind, you must implement the following two functions:

Returns a function, binds this, and passes the preset parameters.

The functions returned by bind can be used as constructors. Therefore, this should be invalidated as a constructor, but the input parameter is still valid.

1. Return a function, bind this, and pass the preset parameters.

This. value = 2var foo = {value: 1}; var bar = function (name, age, school) {console. log (name) // 'any' console. log (age) // 22 console. log (school) // ' 'console. log (this. value) // 1} Function. prototype. bind = function (newThis) {var returns GS = Array. prototype. slice. call (arguments, 1) // get the preset parameter sequence other than newThis var that = this return function () {return that. apply (newThis, runtime Gs. concat (Array. prototype. slice. call (arguments) // bind this to merge the sequence passed during the call and the preset sequence.} var result = bar. bind (foo, 'A') result (22,' ')

The details here are Array. prototype. slice. call (arguments, 1). We know that the variable arguments can get the parameters passed in the function call, but it is not an array, but has a length attribute. Why can it be changed to a pure array after such a call. Then we need to go back to the V8 source code for analysis. # The source code of this version is an earlier version with less content.

Function ArraySlice (start, end) {var len = ToUint32 (this. length); // if you need to pass this to the object, call (arguments), // You can bind this to arguments and obtain its length attribute. Var start_ I = TO_INTEGER (start); var end_ I = len; if (end! = Void 0) end_ I = TO_INTEGER (end); if (start_ I <0) {start_ I + = len; if (start_ I <0) start_ I = 0 ;} else {if (start_ I> len) start_ I = len;} if (end_ I <0) {end_ I + = len; if (end_ I <0) end_ I = 0 ;} else {if (end_ I> len) end_ I = len;} var result = []; if (end_ I <start_ I) return result; if (IS_ARRAY (this) SmartSlice (this, start_ I, end_ I-start_ I, len, result); else SimpleSlice (this, start_ I, end_ I-start_ I, len, result); result. length = end_ I-start_ I; return result ;};

From the source code, we can see that after the length attribute under arguments is assigned to slice through call, we can get the final array through start_ I & end_ I, therefore, an array variable can be obtained after a pure array is passed into slice.

2. Functions returned by bind can be used as constructors.

When being used as a constructor, this should point to the new instance and have the prototype attribute, pointing to the prototype of the instance.

This. value = 2var foo = {value: 1}; var bar = function (name, age, school ){... console. log ('this. value', this. value)} Function. prototype. bind = function (newThis) {var returns GS = Array. prototype. slice. call (arguments, 1) var that = this // that always points to bar var NoFunc = function () {} var resultFunc = function () {return that. apply (this instanceof that? This: newThis, invalid Gs. concat (Array. prototype. slice. call (arguments)} NoFunc. prototype = that. prototype // that points to bar resultFunc. prototype = new NoFunc () return resultFunc} var result = bar. bind (foo, 'any') result. prototype. name = 'lsc '// has the prototype attribute var person = new result (22, 'hometown ') console. log ('person ', person. name) // 'lsc'

The above simulated Code does two important tasks.

1. simulate a prototype attribute for the returned function ., Because the new instance of the constructor can query the properties and methods defined on the prototype.

Var NoFunc = function () {}... NoFunc. prototype = that. prototype // that points to barresultFunc. prototype = new NoFunc () return resultFunc

The code above shows that always points to bar. At the same time, the returned function inherits that. prototype, that is bar. prototype. Why not directly set the returned function's prototype attribute resultFunc. prototype to bar (that). prototype, because any new instance can access the prototype chain. If a value is assigned directly, the new object can directly modify the prototype chain of the bar function, which is the pollution of the prototype chain. Therefore, we use the Inheritance Method (assigning the prototype chain of the constructor to the instance of the parent constructor) to disassociate the prototype chain of the new object from the bar.

2. Determine whether this is used for normal bind or constructor to change the point of this.

How can we determine where this is currently directed? Through the first point, we know that the new function returned through the bind method already has a prototype chain, all we need to do is to change the point of this to simulate it. Determine the posture of the current call. The answer is instanceof.

The instanceof operator is used to test whether an object has a prototype attribute of a constructor in its prototype chain.

// Define the constructor function C () {} function D () {} var o = new C (); // true, because Object. getPrototypeOf (o) = C. prototypeo instanceof C; // false, because D. prototype is not in the o prototype chain. o instanceof D;

We can see from the above that instanceof can determine whether an object is new from this function. If it is new, the prototype chain of this object should be the prototype of this function.

So let's look at the key returned function structure:

var resultFunc = function() {  return that.apply(this instanceof that ?     this :     newThis,     aArgs.concat(Array.prototype.slice.call(arguments))) } 

In this case, we must first recognize that this in this instanceof that is the this in the new function returned after the bind function is called. Therefore, this may be executed in a common scope environment, and it may be changed by a new one. Again, that always points to bar, and its prototype chain that. prototype always exists. Therefore, if this new function is to be used for new operations, this points to the new function, and this instanceof that = true. Therefore, if this is input in apply, this indicates the new function. If it is a normal call, this is not new, that is, the new function is not a constructor, and this instanceof that = false is very obvious. This is a normal bind Call. Use the first parameter of the call as the point of this.

Complete code (implementation under MDN)

if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) {  if (typeof this !== 'function') {   // closest thing possible to the ECMAScript 5   // internal IsCallable function   throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');  }  var aArgs  = Array.prototype.slice.call(arguments, 1),    fToBind = this,    fNOP  = function() {},    fBound = function() {     return fToBind.apply(this instanceof fNOP         ? this         : oThis,         aArgs.concat(Array.prototype.slice.call(arguments)));    };  if (this.prototype) {   // Function.prototype doesn't have a prototype property   fNOP.prototype = this.prototype;   }  fBound.prototype = new fNOP();  return fBound; };}

We can see that it first determines whether the current bind is supported, and does not support compatibility. It also determines whether the object that calls this method is a function. If not, an error is returned.

At the same time, this simulation method also has some defects. You can pay attention to the Polyfill section on the MDN.

Summary

One of the biggest drawbacks of simulating bind is that prototype attributes exist in the simulated function, but native bind does not have prototype as the constructor. However, the new instance does not have a prototype chain, so what does it mean.

If you have any questions during your study, you can discuss them in the following message area. Thank you for your support.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.