Function. prototye. bind in javascript
This article mainly introduces information about Function. prototye. bind in javascript. For more information, see
Function binding is probably the least important thing you pay attention to when using JavaScript, but when you realize that you need a solution to solve how to maintain this context in another Function, what you really need is Function. prototype. bind (), but you may still be unaware of this.
When you encounter this problem for the first time, you may prefer to set this to a variable, so that you can continue to reference it after changing the context. Many people choose to use self, _ this, or context as the variable name (that is also used ). These methods are useful, and of course there is no problem. But there are actually better and more dedicated methods.
What problems do we really need to solve?
In the example code below, we can properly cache the context to a variable:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
Var myObj = { SpecialFunction: function (){ }, AnotherSpecialFunction: function (){ }, GetAsyncData: function (cb ){ Cb (); }, Render: function (){ Var that = this; This. getAsyncData (function (){ That. specialFunction (); That. anotherSpecialFunction (); }); } }; MyObj. render (); |
If we simply use this. specialFunction () to call a method, we will receive the following error:
Uncaught TypeError: Object [object global] has no method 'specialfunction'
We need to maintain reference to the context of the myObj object for callback function execution. Calling that. specialFunction () enables us to maintain the scope context and correctly execute our functions. However, using Function. prototype. bind () can be more concise and clean:
?
1 2 3 4 5 6 7 8 9 10 11 |
Render: function (){ This. getAsyncData (function (){ This. specialFunction (); This. anotherSpecialFunction (); }. Bind (this )); } |
What did we do just now?
. Bind () creates a function. When this function is called, its this keyword is set to the passed value (here, bind () is called () parameters ). Therefore, we pass in the desired context, this (actually myObj), to the. bind () function. Then, when the callback function is executed, this points to the myObj object.
If you want to know what the minister of Function. prototype. bind () is and how it works, here is a very simple example:
?
1 2 3 4 5 6 |
Function. prototype. bind = function (scope ){ Var fn = this; Return function (){ Return fn. apply (scope ); }; } |
There is also a very simple use case:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
Var foo = { X: 3 } Var bar = function (){ Console. log (this. x ); } Bar (); // Undefined Var boundFunc = bar. bind (foo ); BoundFunc (); // 3 |
We have created a new function. When it is executed, its this will be set to foo -- instead of the global scope as we call bar.
Browser support
Browser Version support
Chrome 7
Firefox (Gecko) 4.0 (2)
Internet Explorer 9
Opera 11.60
Safari 5.1.4
As you can see, unfortunately, Function. prototype. bind is not supported in IE8 or earlier versions. Therefore, if you do not have an alternative solution, problems may occur during running.
Fortunately, Mozilla Developer Network (a great resource library) provides an absolutely reliable alternative for browsers that do not implement the. bind () method themselves:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
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 events GS = Array. prototype. slice. call (arguments, 1 ), FToBind = this, FNOP = function (){}, FBound = function (){ Return fToBind. apply (this instanceof fNOP & oThis ? This : OThis, Using Gs. concat (Array. prototype. slice. call (arguments ))); }; FNOP. prototype = this. prototype; FBound. prototype = new fNOP (); Return fBound; }; } |
Applicable Mode
When I learned about technology, I found that not only is it useful to thoroughly learn and understand concepts, but also to see if there is anything that fits it in the work at hand, or something close to it. I hope that some of the following examples can apply to your code or solve the problems you are facing.
Click handlers (CLICK handler)
One purpose is to record click events (or execute an operation after clicking). This may require us to store some information in an object, such:
?
1 2 3 4 5 6 7 |
Var logger = { X: 0, UpdateCount: function (){ This. x ++; Console. log (this. x ); } } |
We may use the following method to specify the click handler and then call the updateCount () method in the logger object.
?
1 2 3 |
Document. querySelector ('button '). addEventListener ('click', function (){ Logger. updateCount (); }); |
However, we must create an extra anonymous function to ensure that the this keyword in the updateCount () function has a correct value.
We can use the following clean method:
Document. querySelector ('button '). addEventListener ('click', logger. updateCount. bind (logger ));
We cleverly use the convenient. bind () function to create a new function and bind its scope to a logger object.
SETTIMEOUT
If you have used a template engine (such as Handlebars) or especially some music videos * frameworks (from my experience, I can only talk about Backbone. js), then you may know the issues discussed below about accessing the new DOM node immediately after the rendering template.
Suppose we want to instantiate a jQuery plug-in:
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Var myView = { Template: '/* a template string containing <select/> */', $ El: $ ('# content '), AfterRender: function (){ This. $ el. find ('select'). myPlugin (); }, Render: function (){ This.cancel.html (this. template ()); This. afterRender (); } } MyView. render (); |
You may find that it works normally-but not every time, because there is a problem in it. This is a competition problem: only those who arrive first can win. Sometimes rendering is first served, and sometimes plug-in instantiation is first served. [Note] If the rendering process is not completed (DOM Node has not been added to the DOM tree), find ('select') cannot find the corresponding Node for instantiation .]
Currently, it may not be known to many people. We can use the setTimeout ()-based slight hack to solve the problem.
Let's rewrite our code a little, so we can safely instantiate our jQuery plug-in after loading the DOM node:
?
1 2 3 4 5 6 7 8 |
AfterRender: function (){ This. $ el. find ('select'). myPlugin (); }, Render: function (){ This.cancel.html (this. template ()); SetTimeout (this. afterRender, 0 ); } |
However, the error message cannot be found in function. afterRender.
What we need to do next is to use. bind () in our code:
?
1 2 3 4 5 6 7 8 9 10 11 12 |
// AfterRender: function (){ This. $ el. find ('select'). myPlugin (); }, Render: function (){ This.cancel.html (this. template ()); SetTimeout (this. afterRender. bind (this), 0 ); } // |
The above is all the content of this article. I hope you will like it.