02 knowledge review --this, call and apply

EDITORIAL

This series of articles is through the study of "JavaScript Design Patterns" book summarizes come, just start to feel when just learning to read, no longer need to take notes, but later found the book to understand some of the content and is not very easy, so the book will be described in conjunction with their own understanding also sort out a bit and a note of it, and we hope to learn together, the article if I understand correctly content, please criticism and common progress ~

 

table of Contents

EDITORIAL

table of Contents

content

this basic knowledge

this loss problem

And apply the basics of call

apply and call uses

to sum up

 

content

this basic knowledge

JS when we learn the most puzzling is that this, with a lot of different languages ​​are, this is always in JS is to an object, but this is not the point of this function is defined in the object definition or when OK, but when we run the program it is a dynamic binding. Here we take a look at some of the most common scenario on this point is:

1, functions as an object method calls

When we write code, if we will call the function as a method of an object, such as "obj.code ()" this, then this time we are this has always been pointing to this object, we look at the following passage Code:

        var objectone = {
            name: 'xbeichen.cn',
            getName: function () {
                console.log(this === objectone);
                console.log(this.name);
            }
        };
        objectone.getName();

Can be seen from the above, our getName function is a method objectone object, on line 8 we call this function by objectone.getName (), the function on the inside of this dynamic binding to objectone the object above, so we got the result in the figure above.

2, functions as an ordinary function call

In most cases we will function only as an ordinary function call, this time this is a pointer to the default global object in our browser JS inside the global object is the default window object, but in this case ES5's strict mode is less accurate, when in ES5 strict mode functions as a normal function call, this provision is not our point to the global object, but point undefined. Look at the following two cases:

Ordinary scene:

        window.name = "xbeichen.cn";

        var getName = function () {
            return this.name;
        };
        console.log(getName());

        //或者这样
        var objecttwo = {
            name: "test",
            getName: function () {
                return this.name;
            }
        };

        var getNameNew = objecttwo.getName;
        console.log(getNameNew());

The above two pieces of code you can see, our first piece of code is well understood, getName () is invoked as a normal function, the function inside of this points to the default global object window; the second paragraph of the code we are first defined an object, then this object also has a name attribute, then we are going to quote this object getName () method address to a variable getNameNew, then this variable to call the object inside the method, when, in fact, by in the form of ordinary function to call, so this here is still pointing to the global window object, so we see the output image above.

If we use the above code ES5 strict mode to write, it would be the following scenario:

Strict Mode Scene:

        "use strict"

        window.name = "xbeichen.cn";

        var getName = function () {
            return this.name;
        };
        console.log(getName());

        //或者这样
        var objecttwo = {
            name: "test",
            getName: function () {
                return this.name;
            }
        };

        var getNameNew = objecttwo.getName;
        console.log(getNameNew());

The code is run in strict mode of ES5, we can see the end result being given a run, saying it was not found "name" attribute of this, but clearly advised the code attribute specifies the name of the window object ah, this is why ? The reason is that we have said before, in ES5 strict mode, which is inside of this function call as an ordinary function is undefined point of no longer point to the default window object, so although we have defined the name attribute of the window object, but still it will complain it is running. In order to more clearly see this in the end of this points to at runtime, let us take a look and then run the following code:

        "use strict"

        window.name = "xbeichen.cn";

        var getName = function () {
            return this;
        };
        console.log(getName());

        //或者这样
        var objecttwo = {
            name: "test",
            getName: function () {
                return this;
            }
        };

        var getNameNew = objecttwo.getName;
        console.log(getNameNew());

In the above code, we modified the original code function returns a value, it simply returns this, this time we are not error codes, and finally returned to undefined, which validates our said before: in ES5's strict mode next, when the function is called as an ordinary function inside it is this point undefined, and no longer point to the default window object.

Function as a regular function call at the scene we often encounter a situation: within the event of a dom node has a local function, this time as a local function is an ordinary function call, but it points to the inside of this window, but we the original will is it inside this points to the dom node. In order to solve the above problems, we look at the following code:

Original code:

<body>
    <div id="xbeichen">
        click me
    </div>
    <script>
        window.id = "xbeichen.cn";

        document.getElementById("xbeichen").onclick = function () {
            console.log(this.id);

            var currentCallback = function () {
                console.log(this.id);
            };
            currentCallback();
        }
    </script>
</body>

The code can be seen operating results, we click event div node, the first time you run this command output this is a pointer to our dom node, which is consistent with our ideas, but in local functions currentCallback click event () the point of this was a window, which contrary to our original intention, which is why we developed the most typical JS "this loss" situation. Then how can we solve this problem does, in fact, very simple, since the local function in this point to change, then we will hand it back to the point to modify OK, so, the modified code is as follows:

After the optimized code:

<body>
    <div id="xbeichen">
        click me
    </div>
    <script>
        window.id = "xbeichen.cn";

        document.getElementById("xbeichen").onclick = function () {
            var _self = this;

            console.log(this.id);

            var currentCallback = function () {
                console.log(_self.id);
            };
            currentCallback();
        }
    </script>
</body>

Above optimized code can be seen, in fact, we increased the "var _self = this;" This line of code, our role is to click on the inside of this binding event in the custom variable _self above, after whatever you bind on click event nested inside a local function of how many layers, as long as _self variable to obtain this, we get to this point has always been the dom node.

3, constructor calls

No one we know from the JS class, all objects in it are based on a prototype copy from, but we are encoding, you can use the constructor and the new operator to create an object, such wording looks also like a class constructor. In addition to an existing constructor we offer a host of JS, JS most of the functions can be used as a constructor, the constructor function and normal function may look exactly the same, the only difference is their calling embodiment, the constructor function to call through the new operator.

When the call to the constructor function to create an object, we constructor function always returns an object, usually, we function inside the constructor that this points to the object that is returned, the following code:

        var myBlog = function () {
            this.url = "http://www.xbeichen.cn";
        };

        var blogone = new myBlog();
        console.log(blogone.url);

Above we said, under normal circumstances, create objects using the constructor when the constructor inside this point is to return this object, that under special circumstances what is it? If we create an object with the constructor, the constructor explicitly returns an object, then we end up with the object returned, but not before looking forward to this, the following code:

        var myBlog = function () {
            this.url = "http://www.xbeichen.cn";
            return {
                url: "http://www.geov.online"
            }
        };

        var blogone = new myBlog();
        console.log(blogone.url);

The code can be seen, the configuration is explicitly returns an object, at this time we received the url attribute url url attribute property explicitly returned object constructor is not defined, but if the structure does not explicit returns the object, will not cause the above case, even if it returns a non-display data object type, as follows:

        var myBlog = function () {
            this.url = "http://www.xbeichen.cn";
            return  "http://www.geov.online";
        };

        var blogone = new myBlog();
        console.log(blogone.url);

4、Function.prototype.call和Function.prototype.apply

Compared with the previous three cases, and more Function.prototype.call Function.prototype.apply is the use of the above change passed into the function this point the problem, let's look at the code is simple to understand, more knowledge will in the second half do Details:

       var myBlog1 = {
            url: "http://www.xbeichen.cn",
            getUrl: function () {
                return this.url;
            }
        };

        var myBlog2 = {
            url: "https://xuqwblog.blog.csdn.net/"
        };

        console.log(myBlog1.getUrl());
        console.log(myBlog1.getUrl.call(myBlog2));

Can be seen by the code, we define two objects, the result is the first line of output sentence according to the normal mode of writing, we also obtained the desired results; however, the second statement we call () method to dynamically changing the object bound to myBlog1 this point, it will be tied to myBlog2 change object, so that the output 2 of the above objects url attribute.

Above four cases are the most common on the scene when we encode this point, in addition to the above four scenes, as well as less common with and eval scene, not be introduced here, we are interested can own Baidu understand the next, because the number of daily encountered in the development of not too much.

this loss problem

We look at the above piece of code:

        var objecttwo = {
            name: "test",
            getName: function () {
                return this.name;
            }
        };

        console.log(objecttwo.getName());

        var getNameNew = objecttwo.getName;
        console.log(getNameNew());

The code can be seen from the above, the first line of output statement name attribute our normal output, the second output line of the output statement a null value, this is because the first line output statement getName () function as a method of an object calls, so this is the point where the object objecttwo; a second output line an output statement is null because here getNameNew () function is a pointer address objecttwo.getName though, but ultimately it is the function invoked by an ordinary manner, so this here is the default points to the global window object, the output of the null value, if here we use strict mode, then the second line of output statements will be given as:

This is because the global window object here we did not specify its name attribute. It is this loss of one of the cases, then we look at another scenario.

 

Above us for specific dom node when using the native JS wording "document.getElementById (" xbeichen ")" to get an id of "xbeichen" of a div, that when encoding such an approach is very complicated, we can be used as such a framework prototype.js practice, it will be abbreviated as follows:

        var getId = function (id) {
            return document.getElementById(id);
        };

        getId("xbeichen");

Since then, in order to obtain the specific dom node in the follow-up process, we simply call getId () method to this, so a lot simpler, that we may wish to consider another simpler wording:

       var getId = document.getElementById;

        getId("xbeichen");

Above wording is easier than writing prototype.js this framework, just one line of code to simplify the native JS obtain dom node operation, but we will complain to run in the browser when this is why? When we had the getElementById () method as a function of this document is to call it which used this, at this time this is the document points to the object, so get written by a native particular dom can be acquired, but as we the above code, the reference address with document.getElementById getId variable, then call getId () when this function, it becomes the ordinary function call, this time the internal function is no longer pointing to the document object, instead of pointing to the default window object, so such a wording error. Next we modify it under our code, use the upper part of the introduction to apply () method to dynamically change this point, the code is as follows:

   <div id="xbeichen"></div>
    <script>
        document.getElementById = (function (func) {
            return function () {
                return func.apply(document, arguments);
            }
        })(document.getElementById);

        var getId = document.getElementById;

        console.log(getId("xbeichen"));
    </script>

These are the two most common problems of this loss, plus dom node before the event local function in this loss, this loss has introduced three issues in more detail this loss situations and solutions will be late again I sorted out a to introduce a separate article, enjoy looking forward to.

And apply the basics of call

Function.prototype.call and ES3 Function.prototype.apply two methods started from the two methods defined Function prototypes of these two ways of writing in the actual functional code development process is particularly useful in the design and the JS mode is also very important and extensive use of two methods. The role of the two methods of call and apply exactly the same, just with different arguments passed it.

apply method takes two parameters, the first parameter for this point to specify a function in the body, the second parameter is an array or array type, this will apply the method of collection or array elements are passed as parameters to the called function.

call method also accepts two parameters, the first parameter is also used to specify a point within this function, but starting from the second parameter are sequentially passed to the function. So the number of parameters passed in a method call is not fixed, it is more like a syntactic sugar on top of the apply method, if we know how many function accepts parameters and want to express the correspondence between formal and actual parameters at a glance, that we can call methods for passing parameters; if we do not care how many specific parameters, then we just use the method to apply the parameters to the function will fall to push in on it. Let us look at specific examples of code:

apply methods Demo:

       var testfunc = function (a, b, c) {
            console.log([a, b, c]);
        };

        testfunc.apply(null, [1, 3, 2]);

call presentation method:

        var testfunc = function (a, b, c) {
            console.log([a, b, c]);
        };

        testfunc.call(null, 1, 9, 7);

In the first piece of code, we placed the three numbers into an array passed by the apply method testFunc () function, an array of three values ​​which respectively correspond to the function parameters a, b, c three parameter. JS interpreter, when executed first code parameter and not accounting than the difference in the number, type and order of arguments, because JS parameters within the array is represented by a, so we can say apply method higher utilization rate than the method call.

Like the above two pieces of code, we apply when using the method and call, if we pass the first argument is null, the body of this function that will point to the default host object, then the browser is the window object, if it is in ES5 strict mode, this point is null, as follows:

Browser environment:

        var testfunc = function (a, b, c) {
            console.log(this === window);
        };

        testfunc.call(null, 1, 9, 7);

Strict mode:

        var testfunc = function (a, b, c) {
            "use strict"
            
            console.log(this);
        };

        testfunc.call(null, 1, 9, 7);

These are the basic introduction to apply and call methods, let's look at what are two ways to use.

apply and call uses

Mentioned above, apply and use the call method is particularly widespread in JS design patterns inside, and these two methods is particularly important in functional programming there, in that they are in the end what use is it, I summarized the following three uses, following on to under detail the various usage scenarios.

1, of this point to change

Like as mentioned above, Apply and most widely used method call is used to point to dynamically vary as a function of this body, as shown in the following code:

        window.url = "http://www.geov.online";

        var myblog1 = {
            url: "http://www.xbeichen.cn"
        };

        var myblog2 = {
            url: "https://xuqwblog.blog.csdn.net/"
        };

        var getUrl = function() {
            console.log(this.url);
        };

        getUrl();
        getUrl.apply(myblog1);
        getUrl.apply(myblog2);

The above code getUrl () a function common call function in vivo this defaults to the window object, the output of the url attribute window object; however, when used apply methods are invoked getUrl () function, a function of the body of this point are dynamically bound to the myblog1 and myblog2 objects, the final properties of the two outputs url objects.

this changed scenario we often encounter in the development, above we mentioned two: First, in the event dom node, this point in the local function will be changed to the default window object; two document.getElementById is in the correction of this points to the scene.

About the event dom node, the local internal function this changed scenario, we are using the most simple approach to solve, namely the definition of a variable _self, use it to save the dom node references. Here we can apply the same approach to resolve or call, as follows:

<body>
    <div id="xbeichen">
        click me
    </div>
    <script>
        window.id = "xbeichen.cn";

        document.getElementById("xbeichen").onclick = function () {
            //var _self = this;

            console.log(this.id);

            var currentCallback = function () {
                console.log(this.id);
            };
            currentCallback.call(this);
        }
    </script>
</body>

In addition to the above dom node event, a local internal function this changed scenario, we also encountered when document.getElementById shorthand method of this changed scenario, by apply methods to solve, as follows:

        document.getElementById = (function (func) {
            return function () {
                return func.apply(document, arguments);
            }
        })(document.getElementById);

        var getId = document.getElementById;

        console.log(getId("xbeichen"));

2、Function.prototype.bind

Most browsers have built-in method to achieve a Function.prototype.bind used to bind this point, the code is as follows:

        var myblog1 = {
            url: "http://www.xbeichen.cn"
        };

        var getUrl = function () {
            console.log(this.url);
        }.bind(myblog1);

        getUrl();

The code to bind this point by the bind () method, the final output is the url attribute myblog1 object. If you do not bind to bind this point, that our getUrl () function as an ordinary function call, which is a pointer to the default inside this window global object.

But in some low version of the browser is not implemented Function.prototype.bind method, so if we want to use this method to bind bind will complain, this time we can write your own bind a simplified version of the method, as follows:

Function.prototype.bind = function( context ){
	var self = this; 							// 保存原函数
	return function(){ 							// 返回一个新的函数
		return self.apply( context, arguments ); // 执行新的函数的时候,会把之前传入的 context
												// 当作新函数体内的 this
	}
};

var obj = {
	name: 'sven'
};

var func = function(){
	alert ( this.name ); 						// 输出:sven
}.bind( obj);

func();

In the above code, we are through Function.prototype.bind to "package" func function and pass an object as a parameter context, the context is that we want to amend the object of this object.

Internally Function.prototype.bind, we put a reference to the function func saved, and then returns a new function. When we perform the function func in the future, in fact, it is the first implementation of this new function just returned. Within the new function, self.apply (context, arguments) of this code is executed original func function and specify the context object for the function func the this body.

3, borrow other object methods

apply and call methods other than the use of two or more, there is a third purpose that is borrowed from other objects. Here can be divided into two scenarios to tell you about:

3.1, to borrow constructors

Method borrowed objects borrowing scenario is the constructor, by this technique, we can achieve some similar effect inherited together look at the following code:

        var myblog1 = function (url) {
            this.url = url;
        };

        var myblog2 = function () {
            myblog1.apply(this, arguments);
        };

        myblog2.prototype.getUrl = function () {
            return this.url;
        };

        var testblog = new myblog2("http://www.xbeichen.cn");
        console.log(testblog.url);

Parameter list arguments 3.2, the operating function

JS list of function parameters in the arguments array object is a class, it also has a lower standard, but it is after all not a real array, so we can not sort it directly or adding new elements such as the operation. This time we need to borrow Array.prototype method on the object to operate the arguments, for example: if we want to add a new element to the arguments, you can borrow Array.prototype object push () method, as follows:

        (function () {
            Array.prototype.push.call(arguments, 3);
            console.log(arguments);
        })(1, 2);

In fact, in the actual development process, if we want to operate arguments when very frequent method on the object Array.prototype borrow. But when borrowing Array.prototype.push method, any object can not borrow, borrow Array.prototype.push method of the object must meet the following two requirements:

  • To the object itself can access attribute;
  • length read-write property of the object.

These are the methods call and apply the three most common use of the currently in development actually on the first and third most common and second is to take into account some lower versions of the browser does not support bind method was introduced.

 

to sum up

This article is another one knowledge point in the first chapter "JavaScript object-oriented," the article on the basis of the review, through these two articles, we have briefly reviewed what object-oriented JS in, this, call, apply these knowledge, then we have an article that finally JS closures and higher order functions do some knowledge review, we then began JS design patterns learning journey.

Published 138 original articles · won praise 201 · views 280 000 +

Guess you like

Origin blog.csdn.net/qq_35117024/article/details/104447779