Closure, this point, scope, bound object, this

Source: Internet
Author: User

Closure, this point, scope, bound object, this

After finishing object-oriented and inheritance, let's talk about this point and scope. Many people think Javascript is very simple, but I have learned so many languages and don't think js is simple T_T, one of the difficulties is that this points to the scope. Let's talk about the scope first. Let's analyze it:

I. No block-level scope

function fn1(){for (var i = 0; i < 5; i++) {//do somthing}if(false){var j=5;}console.log(i);console.log(j);}fn1();

I believe everyone has written the above code. What do you think is the result? Is it undefined or an error? no, let's get the result first.


The result is 5 and undefined. In C and other languages, variables defined in curly braces are invisible to the outside, but not in js, in js, the unit is function, because there is an activity object during function execution,

Scope chain:

Why is there a scope chain? This is because js is different from other languages. In other languages, functions cannot be defined in functions, but functions can be defined in js. For example:

function fn1(){var i=5;function fn2(){var c=1;}}
In this case, fn2 can access the I defined in fn1. Why? That is because at the execution stage, each execution environment assigns a variable object to the function, for example, the variable objects in fn2 store c, arguments, and arguments are dynamically added by js. The fn1 variable objects include I, fn2, and arguments. How does fn2 access I in fn1? In fact, this variable object is only a part. During execution, the function will create a scope chain object. This object can be seen as an array of classes. I will draw a little bit about the scope chain of fn2.

As you can see, fn has a pointer pointing to the scope chain array. First, it will find the 0 position of the scope chain, that is, the variable object of this function. The attributes in this function will contain all variables declared using var in the function, whether in the if or, as long as it is not in the function, it will become the attribute of the variable object. This is the pre-compilation process, and the initial value of each variable will be assigned as undefined. Of course there will be some variables, for example, the form parameter (if the form parameter is set, it is actually used with argument [0], argument [1]... Is a variable, you can also modify each other), if not found, then continue to look up, find the location of the scope chain 1, that is, the fn1 variable object, arguments cannot be accessed here, because it has been found on the variable object of fn2, and still cannot be found at location 1 of the scope chain, so we can continue to look up, find the global object, that is, the windows object, and access its properties. Let's analyze arguments a little.

function fn1(){var i=5;var ar=arguments;function fn2(){var c=6;console.log(ar);}return fn2;}var fn=fn1(1);fn();

In fn1, I assigned the arguments of fn1 to ar, and printed them in fn2 to prove that there are some results. This callee points to the function itself, and we all know that it is similar to fn1.prototype. like constructor, they all point to their own functions. Of course, this is not discussed here. This is the legendary closure. It returns a function, and then the scope chain pointer of this function points to the fn1, that is, the variable object of the outer function. So here, I in fn1 always exists in the memory, because in the global environment, there is a reference to the fn1 variable object. To eliminate the reference, you can use

Fn = null. In this way, the reference to the memory function is disconnected, and the reference to the variable object of fn1 is naturally disconnected. The js garbage collection mechanism will automatically recycle it. Note that the scope chain is determined in the definition, but the memory is allocated only during execution. We can verify that:

function fn1(){var i=5;function fn2(){var c=6;console.log(k);}return fn2;}(function(){var k=5;var fn=fn1();fn();})();

Some people think that the result here is 5, but the result is wrong, because the definition of k cannot be found in the scope chain.

At this point, you should have some knowledge about the scope chain.

Let's take a look at this point. this points to the nouns that appear in the object, but also in the function. Because the function itself is also an object and who executes it, then this points to whom, in the function, the window object is executed by default, so it can be considered as the method of the window object, so that is, the window.

Verification:

function fn1(){console.log(this);}fn1();


As you can see, the result is window. Let's change the method.

function fn1(){console.log(this);}var object=new Object();object.fn1=fn1;object.fn1();

As you can see, the object, that is, this object, can be changed as the execution object changes. Let's take a look at what is a function expression and a method.

function F(){this.data="5";this.say=function(){alert(this.data);}}var a=new F();var c=a.say;c();

As you can see, I just assigned the method of the object to c, and then the data attribute cannot be found after execution, because the value assignment expression actually points this to the modification by default, now the "this" in the "say" method points to the window, and "c" is the function expression. You can think like this: the window method is called the function expression, while the methods of other objects are called methods, their this point is different. Let's continue to link with the scope chain:

function F(){this.data="5";var data2="F";this.say=function(){console.log(data2);console.log(this.data);}}var a=new F();var c=a.say;c();


Do you understand the result? Although the function is bound to a windows Object, As a function, the say method is doomed to a scope chain in the dark, no matter who it is bound, or where is the execution? The scope chain has been determined and cannot be changed. So we can print data2 and write it here. Let's take a look at some confusing statements:

function F(){this.data="5";this.say=function(){console.log(this.data);}}var a=new F();(a.say)();

Here the result is 5. I will not pass it. Let's take a look at another one.

function F(){this.data="5";this.say=function(){console.log(this.data);}}var a=new F();(a.say=a.say)();

Here, only the last line is changed, but the result is undefined. That is because the value assignment statement is executed in the brackets above, and the returned function expression is bound to the window object. Let's take a look at the confusing setTimeout.

function F(){this.data="5";this.say=function(){console.log(this.data);}}var a=new F();setTimeout(a.say,10);


As you can see, setTimeout also turns into a function expression, and this point also turns into a window, so let's change it again:

function F(){this.data="5";this.say=function(){console.log(this.data);}}var a=new F();setTimeout(function(){a.say();},10);


Why can we print it out correctly here? That's because it is a function expression in the outer layer, but it does not change the say method into a function expression in this expression, but it is executed, of course, it is bound to object a. Just like the first blog I wrote earlier, the first blog did not write well, because it was not understood at that time. Let's review:

function F(){this.data="5";this.say=function(){console.log(this.data);}this.say2=function(){setTimeout(this.say,10);}}var a=new F();a.say2();

Like this, the final printed result is undefined. Why? First, In the say2 method, this is bound to object, this is because no function expression is used when calling the outer layer, that is, this. can be found, if changed to var c =. say2; c (); in this way, the say method in setTimeout cannot be found because it is bound to the window. Here we can find the say method, but this in the say method is the object. I just mentioned that the setTimeout will become a function expression, that is, window, so this. data cannot be found. Why does this happen? Why is a function expression? Let's take a look at the following example:

function exec(fn){fn();}function F(){this.data="5";this.say=function(){console.log(this.data);}this.say2=function(){setTimeout(this.say,10);}}var a=new F();exec(a.say);

Here, I have defined an exec method, and then executed this function in the exec method, and then it becomes undefined, because when passing parameters, it is a passed function expression, that is to say, I changed the point of this without knowing it. Here, we should have a better understanding of this point. Previously, I often mixed the scope chain and prototype chain. After my own analysis, mom no longer has to worry about my learning. At the end, let's take a look at the bind method. Let's take a look at the definition of the bind method.

function bind(obj,fn){<span style="white-space:pre"></span>return function(){<span style="white-space:pre"></span>fn.apply(obj,arguments);<span style="white-space:pre"></span>}}
Bind a method to an object. You can also use the value assignment statement.

function bind(obj,fn){obj.fn=fn;}

This is also bound, but there is no more than one attribute. This is not good. The above binding returns a function, which can be bound to any object. Let's take a look at the binding example.

var div1=document.getElementById("div1");function F(){this.data="5";this.say=function(){console.log(this.data);}}var a=new F();div1.onclick=a.say;




The result is undefined, because this object is bound to the dom object div1, but I still want it to pop up 5. What should I do? We can use the idea of seTimeout.

div1.onclick=function(){a.say();};

In this way, because the this pointer is bound to object a, it can also be as follows:

var div1=document.getElementById("div1");function F(){this.data="5";this.say=function(){console.log(this.data);}}var a=new F();div1.onclick=bind(a,a.say);function bind(obj,fn){return function(){fn.apply(obj,arguments);}}


The result is still 5. That is because a function expression is returned, and an apply is used to modify the this point of fn. If you want to use the first or the second type, it depends on you, And the situation. If this method exists on this object, we recommend the first method. If this method does not exist on this method object, we recommend the second method, let's see when to use the second method:

var div1=document.getElementById("div1");function F(){this.name=5;this.data="5";this.say=function(){console.log(this.data);}}function sayName(){alert(this.name);}var a=new F();div1.onclick=bind(a,sayName);function bind(obj,fn){return function(){fn.apply(obj,arguments);}}

This sayName is used for functions or other objects. I want to bind it to object a. It would be nice to use bind at this time. If it is a method call existing in this object, let's use the first one. Well, we have analyzed it here today. Thank you!



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.