我有一个简单的对象,我不通过调用此对象的函数来理解this
的概念(范围)。
为什么在最后一个变体(3)中调用show()
(对象中没有父对象的函数show()
)结果是“这是全局的”而不是内部变量title("Color Picker")
?
我有一个含糊的想法,即在定义了全局变量popup.show()
之后调用函数show
,this
指的是全局对象。这是逻辑解释吗?
代码:http://jsbin.com/otuzac/1/edit。
var title="'This' is global";
var popup={
dom_element:("#popup"),
title :"Color Picker",
prev_color :'#fff',
set_color : function(color){
color=color || this.prev_color;
//set the color
return color;
},
show :function(){
return("showing "+this.title);
}
};
var show=popup.show();
//Case 1: var show=popup.show()
alert(show); //output "Color Picker"
//Case 2: var show=popup.show()
alert(popup.show()); //output "Color Picker"
//Case 3: var show=popup.show !!! (no parent.)
alert(show()); //output "This is global"
答案 0 :(得分:5)
this
取决于您如何调用使用this
的函数。
functionName();
在这种情况下,this
将始终引用全局对象(通常是window
对象)。
a = 2;
function XY(a) {
this.a = a;
this.b = function () {
func();
};
function func () {
console.log(this.a);
}
}
var xy = new XY(1);
xy.b(); //2
说明
func
即可调用函数func();
。因此,即使您的函数位于构造函数(XY
)中,并从作为方法调用的函数调用(请参阅第3点),this
仍然引用全局对象。var obj = new functionName();
在这种情况下,this
将引用新创建的对象。
a = 2;
function XY(a) {
this.a = a;
}
var xy = new XY(1);
console.log(xy.a); //1
obj.functionName();
在这种情况下,this
将引用包含您正在调用的函数的对象。
a = 2;
var xy = {
a: 1,
func: function() {
console.log(this.a);
}
}
xy.func(); //1
apply
functionName.apply(thisObj, argArray);
在这种情况下,this
将为new Object(thisObj)
,其中thisObj
是函数apply
的第一个参数。
function xy (a,b) {
console.log(this);
}
xy.apply({f:3}, [1,2]); //Object {f: 3}
xy.apply("hello", [1,2]); //String {0: "h", 1: "e", 2: "l", 3: "l", 4: "o"}
正如用户Mifeet所建议的那样,事件也会改变this
:
事件是一个单独的主题。它们不是EcmaScript的一部分,通常由不同的浏览器以不同方式处理。然而,关于this
的差异很小,对于IE> 8据我所知,不存在。
this
将引用触发事件的DOM元素,除非您使用内联事件处理程序。在这种情况下,this
将引用全局对象。
<button id="1" onclick="clickit()">click me</button> <!-- 0 -->
<button id="2">click me</button>
<button id="3">click me</button>
<script>
var button1 = document.getElementById("1");
var button2 = document.getElementById("2");
var button3 = document.getElementById("3");
id = "0";
window.clickit = function(){
console.log(this.id);
};
button2.onclick = clickit; //2
button3.addEventListener("click", clickit, false); //3
</script>
对活动的评论
addEventListener
,而是attachEvent
。使用此函数还将导致this
引用全局对象。this
将引用表示该标记的DOM元素。因此<button id="1" onclick="clickit(this)">click me</button>
会将DOM元素传递给clickit
事件处理程序。在前两种情况下,您将函数作为一种方法调用,在最后一种情况下,您将其称为函数。这就是为什么在最后一种情况下,this
引用了全局对象。
修改强>
我最近在StackOverflow上看到了一个非常相似的问题答案。不幸的是我再也找不到了,所以我决定自己发一个答案。但如果有人知道我的意思是什么,请发表评论,我很乐意在答案中提供原始答案的链接。
答案 1 :(得分:3)
在你的
案例1: var show=popup.show()
正在调用在弹出对象中定义的函数show。
并且显示函数有这个对象是指弹出对象,弹出对象有自己的标题变量,调用show函数。这就是为什么显示“颜色选择器”。
案例2:这也是案例1的silimar,你在这里调用show函数而不使用变量。所以输出相同。
案例3:如果是第三种情况,你正在调用函数show而不像在案例1和2中那样引用任何对象。 所以默认它是取对象od文件。并且在文档中标题的值是“'这是'全局的'所以它显示结果”'这'是全局的“。这是指文档对象。
希望这会对你有所帮助。
答案 2 :(得分:1)
那是因为你把变量show视为一个函数。让我们更简单:
function a(){
return "textA";
}
var obj={
b: function(){ return "text b";}
};
console.log(a); // will output the function object
console.log(a()); // will call a then output the result of the function --> "textA"
console.log(obj.b); //will output the function object same as console.log(a)
console.log(obj.b()); // will call b then output the result of the function --> "text b"
现在想象一下我做的第三个例子:
var anotherObj = a();
console.log(anotherObj()); // you try to treat the return of a() as a function. will not work --> "string is not a function "
你可以这样做:
console.log(window[anotherObj]());
这将调用名为“textA”的函数。 Full Fiddle here
对于范围,此默认指向窗口。在对象内部运行时,这将引用此对象unless the function is applied to something else.
答案 3 :(得分:1)
正如其他人所解释的,在前两种情况下,您在popup
对象上调用该函数,因此this
引用popup
。在第三种情况下,您只能单独调用函数,而不是对象,因此this
引用全局范围(window
)。此外,在您的示例中,您不能使用alert(show());
,因为show
这里不是函数而是字符串。
如果您想获得所需的结果,可以使用以下模式(由许多框架使用,例如jQuery):
var title="'This' is global";
(function() {
var popup = {
dom_element:("#popup"),
title :"Color Picker",
prev_color :'#fff',
set_color : function(color){
color=color || this.prev_color;
//set the color
return color;
},
show :function(){
return("showing " + popup.title); // refer to the local variable popup instead of this
}
};
window.popup = popup; // add the (now initialized) local variable popup to the global scope
})(); // execute immediately
var show=popup.show();
var showFn = popup.show; // You cannot use the result of popup.show() as a function because it's a string
//Case 1:
alert(show); //output "Color Picker"
//Case 2:
alert(popup.show()); //output "Color Picker"
//Case 3:
alert(showFn()); // output "Color Picker"
(JS Bin)
答案 4 :(得分:0)
this
始终引用当前对象或上下文
在案例2中,该对象是弹出的。这就是你在警报中看到popup.title的原因。
当您将popup.show
分配给show
时,您在案例3中实际执行的操作是在要显示的window
对象(或至少是当前范围)上创建句柄。因此对于该句柄,对象是window
。
所以现在如果你调用这个句柄,它将显示你也在title
对象上注册的window
。
您可以使用call设置上下文和/或像这样应用:
var show=popup.show
alert(show.call(popup));