Prototype source code analysis-function. Prototype (1)

Source: Internet
Author: User

Recently I learned nothing about what I think, and the progress is not obvious. So I occasionally look at the prototype source code and take notes for analysis.

I remember that when I used to look at jquery's source code, I searched the internet and analyzed a bunch of source code. However, most of them can only be regarded as comments. I am a beginner like me.

So now, jquery's source code only looks at the first few hundred lines. Select prototype source code because prototype is different from jqeury. All jquery operations are performed on one (Group) jquery object, but prototype extends the native type, for example, the function to be mentioned this time.

So... prototype... it's better to read ··

The previous analysis of a template in prototype can be consistent. Http://www.cnblogs.com/xesam/archive/2011/12/05/2277260.html

Several Methods Added in function. prototype:

  return {
argumentNames: argumentNames,
bind: bind,
bindAsEventListener: bindAsEventListener,
curry: curry,
delay: delay,
defer: defer,
wrap: wrap,
methodize: methodize
}

(In the definition process, there are two undisclosed functions, update and merge, which are mainly used to merge arrays (parameters), so there is nothing to say)

Among them, one of the most important methods is bind. After understanding this one, others will be well understood.

Don't look at bind first. Let's start with the problem.

Suppose we have a function and an object:

    function handler(greet){
console.log(greet,this.name);
}
var obj = {
name : 'xesam'
}

Now there is a requirement. We need to print the name of the OBJ, and direct handler (OBJ) obviously does not work, because handler's this points to window during definition, and handler (OBJ) is equivalent to console. log (window. name ). So you have to find a solution:

The most intuitive way is to pass OBJ directly to the handler function and change it:

    function handler(o,greet){
console.log(greet,o.name);
}
var obj = {
name : 'xesam'
}
handler(obj,'hello');

However, this destroys the original definition of handler, which is the next policy.

There are two roads:

1. Use call or apply to change the handler's scope, handler. Call (OBJ, 'Hello'). In this case, another function is required to wrap it.

2. Change handler to a method of OBJ so that it can call obj. Handler ()

 

 

Next, let's look at the first solution, which should be easy to think:

Function somefunction (OBJ, greet ){
Handler. Call (OBJ, greet );
// Or Xe. Apply (OBJ, [greet]);
}
VaR OBJ = {
Name: 'xesam'
}
Somefunction (OBJ, 'Hello ');

The problem here is how hard it is to add a somefunction for no reason. I just want to see handler and obj. Everything else is redundant.

In this regard, we must be brave enough to block anonymous functions.

If handler can return an anonymous function with functions similar to somefunction, everything is OK.

There is no doubt that handler is a function. I will write a post on the function prototype. Of course, it can also be done on the object prototype, but we don't want it.
The expected call method is handler. XXX (OBJ). xxx indicates the name of a method.
Respect prototype. The Implementation Method in prototype is handler. BIND (OBJ)

In this example, we implement the simplest version:

    Function.prototype.bind = function(obj,greet){
return function(){
handler.call(obj,greet);
}
}
function handler(o,greet){
console.log(greet,o.name);
}
var obj = {
name : 'xesam'
}
var handler_1 = handler.bind(obj,'hello');
handler_1();

Handler_1 refers to the handler copy after this point is converted (the word copy is not accurate, meaning it will be enough ).

Function. prototype. the BIND should not contain OBJ, greet, handler, and other people's desired names. Use this to replace handler, OBJ, and greet as parameters (only real parameters need to be taken into account when using this parameter). Therefore, the list can be improved:

    Function.prototype.bind = function(){
var _this = this;
var _obj = arguments[0];
var _params = Array.prototype.slice.call(arguments,1);
return function(){
return _this.apply(_obj,_params);
}
}

 

Let's look back at the original handler:

    function handler(greet){
console.log(greet,this.name);
}

When handler. BIND (OBJ, 'Hello') is executed, the GREET parameter is initialized unintentionally, that is, a default parameter is provided. This is not our purpose, but it does.

If we just look at it one by one, this is obviously the function's "colitization". The aforementioned curry method is just like this.

  function curry() {
if (!arguments.length) return this;
var __method = this, args = slice.call(arguments, 0);
return function() {
var a = merge(args, arguments);
return __method.apply(this, a);
}
}

This is a zombie version like bind.

 

Let's continue to look at our example. the following sentence:

var _params = Array.prototype.slice.call(arguments,1);

In the above implementation, only the param parameter in BIND (OBJ, Param) can be processed. We discard handler. param_1 in BIND (OBJ, Param) (param_1);, so this must be supplemented. Then, the parameters of the two parts are combined to obtain the following function:

Function. Prototype. Bind = function (){
VaR _ this = this;
VaR _ OBJ = arguments [0];
VaR _ Params = array. Prototype. Slice. Call (arguments, 1 );
Return function (){
VaR _ ARGs = _ Params. Concat (array. Prototype. Slice. Call (arguments, 0); // The merged parameter Array
Return _ this. Apply (_ OBJ, _ ARGs );
}
}

Now we get most of the BIND implementation code in prototype (the bind in prototype also contains some code for parameter detection, but parameter detection is not the Focus)

A few short examples:

Handler. BIND (OBJ, 'Hello') (); // equivalent to handler. Call (OBJ, 'Hello ')
Handler. BIND (OBJ, 'Hello') ('Go'); // equivalent to handler. Call (OBJ, 'Hello', 'Go ')
Handler. BIND (OBJ) ('Go'); // equivalent to handler. Call (OBJ, 'Go ')

 

Next we will discuss that if handler is an event listening function, you can pass the value like BIND:

The following is a demo:

<! Doctype HTML public "-// W3C // dtd xhtml 1.0 transitional // en"
Http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd>
<HTML>
<Head>
<Meta http-equiv = "Content-Type" content = "text/html; charset = UTF-8"/>
<Title> </title>
</Head>
<Body>
<Input type = "button" value = "click" id = "BTN"/>
<SCRIPT type = "text/JavaScript">
// Event binding function. You should be familiar with this function:
Function bindeventlistener (El, type, Handler ){
If (window. addeventlistener ){
El. addeventlistener (type, handler, false );
} Else if (window. attachevent ){
El. attachevent ('on' + type, Handler );
} Else {
El ['on' + type] = handler;
}
}
Function handler (){
Console. Log (this. Name );
}
VaR OBJ = {
Name: 'xishanzi'
}
Bindeventlistener (document. getelementbyid ('btn '), 'click', Handler );
</SCRIPT>
</Body>
</Html>

When you click input # BTN, undefined is printed, because in IE, this points to window, not in IE, and this points to input # BTN, no matter where it points, they all have no name attribute.

Now I want to print obj. name when I click it. The principle is described above. To achieve this with bind, you only need to change one place:

bindEventListener(document.getElementById('btn'),'click',handler.bind(obj));

 

However, for event processing functions, the first parameter of non-IE browser will have a default event (current event ):

Therefore, prototype provides a bind specific event version -- bindaseventlistener

The Code is as follows:

Function. Prototype. bindaseventlistener = function (context ){
VaR _ this = this;
VaR _ Params = array. Prototype. Slice. Call (arguments, 1 );
Return function (event ){
VaR _ ARGs = []. Concat (_ Params); // The merged parameter Array
Return _ this. Apply (context, _ ARGs );
}
}

It was originally intended to be written, but it was found to be very smelly and very long, so this article wrote three functions: bind, curry and bindaseventlistener, and the rest will be supplemented in the next article.

In fact, after reading this part, we will find that Nima is an object in Js.

 

For more information, see http://www.cnblogs.com/xesam /]
Address: http://www.cnblogs.com/xesam/archive/2011/12/17/2290797.html

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.