Home > Article > Web Front-end > Follow me to learn this keyword of javascript_javascript skills
This article only discusses this issue. After reading this article, if readers can correctly answer the What's this question in JavaScript, as an author, I will feel that it is worth spending so much effort to write such an article. .
We have to remember one sentence: this always points to the object where the function is running! rather than the object in which the function was created. That is: whoever calls points to whom. Remember…
This article will analyze where this object is in three situations.
1. this
in ordinary functions
No matter where this is, the first priority is to find the location when the function is running.
var name="全局"; function getName(){ var name="局部"; return this.name; }; alert(getName());
When this appears in the function getName of the global environment, the runtime location of the function getName is
alert(getName());
Obviously, the object where the function getName is located is the global object, that is, window, so the home of this must be in window. At this time, this points to the window object, so the this.name returned by getName is actually window.name, so the alert comes out as "global"!
So, when this does not appear in the function of the global environment, but appears in the function of the local environment, where will it fall?
var name="全局"; var xpg={ name:"局部", getName:function(){ return this.name; } }; alert(xpg.getName());
The function getName in which this is located is not in the global environment, but in the xpg environment. No matter where this is, you must find the location when the function is running. The position of the function getName when it is running at this time
alert(xpg.getName());
Obviously, the object where the function getName is located is xpg, so the home of this must be in xpg, that is, it points to the xpg object. Then the this.name returned by getName is actually xpg.name, so the alert comes out as "partial"!
Give an example to consolidate:
var someone = { name: "Bob", showName: function(){ alert(this.name); } }; var other = { name: "Tom", showName: someone.showName } other.showName(); //Tom
Although the this keyword is declared in someone.showName, it is other.showName when running, so this points to the current object of the other.showName function, which is other, so the final alert is other.name.
2. this in closure
Closure is also a troublemaker. This article will not go into details about it for the time being. In short: the so-called closure is to create another function inside a function, and the internal function accesses external variables.
The prodigal son is mixed with the ruffian closure, which shows that there will never be peace!
var name="全局"; var xpg={ name:"局部", getName:function(){ return function(){ return this.name; }; } }; alert(xpg.getName()());
At this time, this is obviously in trouble. It is actually in the anonymous function in the getName function, and the anonymous function calls the variable name, thus forming a closure, that is, this is in the closure.
No matter where this is, you must find the location when the function is running. At this time, it cannot be judged based on the runtime position of the function getName, but based on the runtime position of the anonymous function.
function (){ return this.name; };
Obviously, the object where the anonymous function is located is window, so the home of this must be in window, then the this.name returned by the anonymous function is actually window.name, so what comes out of alert is the "global"!
So, how to make this in xpg in the closure? —Cache this
var name="全局"; var xpg={ name:"局部", getName:function(){ var that=this; return function(){ return that.name; }; } }; alert(xpg.getName()());
Define that=this in the getName function. At this time, the getName function is running at
alert(xpg.getName());
Then this points to the xpg object, so that also points to the xpg object. If that.name is returned in the anonymous function of the closure, the that.name returned at this time is actually xpg.name, so the "local" can be alerted!
3. The new keyword creates a new object
This in the constructor after the new keyword points to the new object constructed with the constructor:
function Person(__name){ this.name = __name; //这个this指向用该构造函数构造的新对象,这个例子是Bob对象 } Person.prototype.show = function(){ alert(this.name); //this 指向Person,this.name = Person.name; } var Bob = new Person("Bob"); Bob.show(); //Bob
4. this in call and apply
The only ones that can manage this in JavaScript are call and apply.
call and apply are like this's parents, they will live wherever they let this live, and they have to obey! When there are no parameters, the current object is window
var name="全局"; var xpg={ name:"局部" }; function getName(){ alert(this.name); } getName(xpg); getName.call(xpg); getName.call();
Where this is in the function getName. No matter where this is, you must find the location when the function is running. The position of the function getName when it is running at this time
getName(xpg);
Obviously, the object where the function getName is located is window, so the home of this must be in the window, that is, pointing to the window object. Then the this.name returned by getName is actually window.name, so the alert comes out as "global"!
Then, it’s time to call and apply, because this must listen to their command!
getName.call(xpg);
Among them, call specifies that the home of this is the xpg object, because this is forced to settle only in xpg, then this points to the xpg object at this time, this.name is actually xpg.name, so the alert comes out as "local" !
5. this in eval
For the eval function, it seems that the current object is not specified when it is executed, but in fact its this does not point to the window, because the scope when the function is executed is the current scope, which is equivalent to filling in the code inside in that line. The following example illustrates this problem:
var name = "window"; var Bob = { name: "Bob", showName: function(){ eval("alert(this.name)"); } }; Bob.showName(); //Bob
6、没有明确的当前对象时的this
当没有明确的执行时的当前对象时,this指向全局对象window。
例如对于全局变量引用的函数上我们有:
var name = "Tom"; var Bob = { name: "Bob", show: function(){ alert(this.name); } } var show = Bob.show; show(); //Tom
你可能也能理解成show是window对象下的方法,所以执行时的当前对象时window。但局部变量引用的函数上,却无法这么解释:
var name = "window"; var Bob = { name: "Bob", showName: function(){ alert(this.name); } }; var Tom = { name: "Tom", showName: function(){ var fun = Bob.showName; fun(); } }; Tom.showName(); //window
在浏览器中setTimeout、setInterval和匿名函数执行时的当前对象是全局对象window,这条我们可以看成是上一条的一个特殊情况。
var name = "Bob"; var nameObj ={ name : "Tom", showName : function(){ alert(this.name); }, waitShowName : function(){ setTimeout(this.showName, 1000); } }; nameObj.waitShowName();
所以在运行this.showName的时候,this指向了window,所以最后显示了window.name。
7、dom事件中的this
(1)你可以直接在dom元素中使用
<input id="btnTest" type="button" value="提交" onclick="alert(this.value))" />
分析:对于dom元素的一个onclick(或其他如onblur等)属性,它为所属的html元素所拥有,直接在它触发的函数里写this,this应该指向该html元素。
(2)给dom元素注册js函数
a、不正确的方式
<script type="text/javascript"> function thisTest(){ alert(this.value); // 弹出undefined, this在这里指向?? } </script> <input id="btnTest" type="button" value="提交" onclick="thisTest()" />
分析:onclick事件直接调用thisTest函数,程序就会弹出undefined。因为thisTest函数是在window对象中定义的,
所以thisTest的拥有者(作用域)是window,thisTest的this也是window。而window是没有value属性的,所以就报错了。
b、正确的方式
<input id="btnTest" type="button" value="提交" /> <script type="text/javascript"> function thisTest(){ alert(this.value); } document.getElementById("btnTest").onclick=thisTest; //给button的onclick事件注册一个函数 </script>
分析:在前面的示例中,thisTest函数定义在全局作用域(这里就是window对象),所以this指代的是当前的window对象。而通过document.getElementById(“btnTest”).onclick=thisTest;这样的形式,其实是将btnTest的onclick属性设置为thisTest函数的一个副本,在btnTest的onclick属性的函数作用域内,this归btnTest所有,this也就指向了btnTest。其实如果有多个dom元素要注册该事件,我们可以利用不同的dom元素id,用下面的方式实现:
document.getElementById("domID").onclick=thisTest; //给button的onclick事件注册一个函数。
因为多个不同的HTML元素虽然创建了不同的函数副本,但每个副本的拥有者都是相对应的HTML元素,各自的this也都指向它们的拥有者,不会造成混乱。
为了验证上述说法,我们改进一下代码,让button直接弹出它们对应的触发函数:
<input id="btnTest1" type="button" value="提交1" onclick="thisTest()" /> <input id="btnTest2" type="button" value="提交2" /> <script type="text/javascript"> function thisTest(){ this.value="提交中"; } var btn=document.getElementById("btnTest1"); alert(btn.onclick); //第一个按钮函数 var btnOther=document.getElementById("btnTest2"); btnOther.onclick=thisTest; alert(btnOther.onclick); //第二个按钮函数 </script> 其弹出的结果是: //第一个按钮 function onclick(){ thisTest() } //第二个按钮 function thisTest(){ this.value="提交中"; }
从上面的结果你一定理解的更透彻了。
By the way,每新建一个函数的副本,程序就会为这个函数副本分配一定的内存。而实际应用中,大多数函数并不一定会被调用,于是这部分内存就被白白浪费了。所以我们通常都这么写:
<input id="btnTest1" type="button" value="提交1" onclick="thisTest(this)" /> <input id="btnTest2" type="button" value="提交2" onclick="thisTest(this)" /> <input id="btnTest3" type="button" value="提交3" onclick="thisTest(this)" /> <input id="btnTest4" type="button" value="提交4" onclick="thisTest(this)" /> <script type="text/javascript"> function thisTest(obj){ alert(obj.value); } </script>
这是因为我们使用了函数引用的方式,程序就只会给函数的本体分配内存,而引用只分配指针。这样写一个函数,调用的地方给它分配一个(指针)引用,这样效率就高很多。当然,如果你觉得这样注册事件不能兼容多种浏览器,可以写下面的注册事件的通用脚本:
//js事件 添加 EventUtil.addEvent(dom元素,事件名称,事件触发的函数名) 移除EventUtil.removeEvent(dom元素,事件名称,事件触发的函数名) var EventUtil = new eventManager(); //js事件通用管理器 dom元素 添加或者移除事件 function eventManager() { //添加事件 //oDomElement:dom元素,如按钮,文本,document等; ****** oEventType:事件名称(如:click,如果是ie浏览器,自动将click转换为onclick);****** oFunc:事件触发的函数名 this.addEvent = function(oDomElement, oEventType, oFunc) { //ie if (oDomElement.attachEvent) { oDomElement.attachEvent("on" + oEventType, oFunc); } //ff,opera,safari等 else if (oDomElement.addEventListener) { oDomElement.addEventListener(oEventType, oFunc, false); } //其他 else { oDomElement["on" + oEventType] = oFunc; } } this.removeEvent = function(oDomElement, oEventType, oFunc) { //ie if (oDomElement.detachEvent) { oDomElement.detachEvent("on" + oEventType, oFunc); } //ff,opera,safari等 else if (oDomElement.removeEventListener) { oDomElement.removeEventListener(oEventType, oFunc, false); } //其他 else { oDomElement["on" + oEventType] = null; } } }
正像注释写的那样,要注册dom元素事件,用EventUtil.addEvent(dom元素,事件名称,事件触发的函数名)即可, 移除时可以这样写:EventUtil.removeEvent(dom元素,事件名称,事件触发的函数名),这是题外话,不说了。
以上就是本文的全部内容,希望通过这篇文章大家更加了解javascript的this关键字,大家共同进步。