This article mainly introduces the Function.prototye.bind of JavaScript in the relevant data, the need for friends can refer to the
Functional bindings (function binding) are probably the least of your concerns when you start using JavaScript, but when you realize that you need a solution to maintain this context in another function, what you really need is actually Function.prototype.bind (), but you may still not be aware of this.
The first time you encounter this problem, you may prefer to set this to a variable so that you can continue referencing it after changing the context. Many people choose to use Self, _this or context as the variable name (and others use that). These methods are useful, and of course there is no problem. But there are better, more dedicated ways.
What are the real problems we need to solve?
In the following example code, we can safely cache a context into 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.anothersp Ecialfunction (); }); } }; Myobj.render (); |
If we simply use This.specialfunction () to invoke the method, we receive the following error:
Uncaught typeerror:object [Object Global] has no method ' specialfunction '
We need to keep a reference to the MyObj object context for the execution of the callback function. Calling That.specialfunction () allows us to maintain the scope context and execute our functions correctly. However, the use of Function.prototype.bind () can have a more concise and clean way:
?
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 just do?
. Bind () Creates a function that, when invoked, is set to the value passed in (this refers to the parameters passed in when bind () is invoked). So, we pass in the desired context, this (in fact, myobj), into the. bind () function. Then, when the callback function is executed, this points to the MyObj object.
If you are interested to know what and how the Function.prototype.bind () Minister is working, here's 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 created a new function, and when it was executed, it was set to foo--rather than the global scope when we called 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 and the following versions, so if you don't have a backup plan, you may have problems running.
Fortunately, Mozilla Developer Network (a great repository) provides an absolutely reliable alternative to browsers that do not have their own implementation. Bind () Method:
?
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 thi Ng possible to the ECMAScript 5 internal iscallable function throw new TypeError ("Function.prototype.bind-what is trying To be bound are not callable "); var Aargs = Array.prototype.slice.call (arguments, 1), Ftobind = this, Fnop = function () {}, Fbound = function () {RE Turn ftobind.apply (this instanceof fnop && othis? This:othis, Aargs.concat ( arguments))); }; Fnop.prototype = This.prototype; Fbound.prototype = new Fnop (); return fbound; }; } |
The applicable pattern
In learning technical points, I find it useful not only to thoroughly study and understand the concept, but also to see if the work at hand has a place to apply it, or something closer to it. I hope that some of the following examples can be applied to your code or solve the problem you are facing.
Click handlers (click Processing function)
One use is to record the Click event (or perform an action after clicking), which may require us to deposit some information into an object, such as:
?
1 2 3 4 5 6 7 |
var logger = {x:0, updatecount:function () {this.x++; Console.log (this.x);}} |
We may specify the click handler function in the following manner, and then call the Updatecount () method in the Logger object.
?
1 2 3 |
Document.queryselector (' button '). AddEventListener (' click ', Function () {Logger.updatecount ();}); |
But we have to create an extra anonymous function to ensure that the this keyword in the Updatecount () function has the correct value.
We can use the following cleaner way:
Document.queryselector (' button '). AddEventListener (' Click ', Logger.updateCount.bind (logger));
We cleverly used the convenient. Bind () function to create a new function and bind its scope to the Logger object.
SetTimeout
If you have used a template engine (such as handlebars) or have specifically used some mv* frameworks (I can only talk about backbone.js from my experience), then you may know the following discussion about the problems you will encounter when you immediately access a new DOM node after rendering the template.
Let's say we want to instantiate a jquery plugin:
?
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. $e L.find (' select '). Myplugin (); }, Render:function () {this. $el. HTML (this.template ()); This.afterrender ();}} Myview.render (); |
You may find it works-but not every time, because there is a problem. This is a question of competition: only those who arrive first can win. Sometimes the rendering is first, and sometimes the instantiation of the plug-in is first arrived. Translator Note: If the render process has not been completed (DOM node has not been added to the DOM tree), then find (' select ') will not be able to locate the corresponding node to perform the instantiation. 】
Now, perhaps not many people know, we can use settimeout () based on the slight hack to solve the problem.
Let's rewrite our code a little bit, and then safely instantiate our jquery plugin after the DOM node is loaded:
?
1 2 3 4 5 6 7 8 |
Afterrender:function () {this. $el. Find (' select '). Myplugin ();}, Render:function () {this. $el. HTML (this.template ()); settimeout (this.afterrender, 0); } |
However, we get the error message that the function. AfterRender () cannot be found.
The next thing we need to do is to use the. 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. $el. HTML (this.template ()); SetTimeout (This.afterRender.bind (this), 0); } // |
The above mentioned is the entire content of this article, I hope you can enjoy.