“这个”的范围

时间:2013-05-30 09:09:05

标签: javascript

我有一个简单的对象,我不通过调用此对象的函数来理解this的概念(范围)。

为什么在最后一个变体(3)中调用show()(对象中没有父对象的函数show())结果是“这是全局的”而不是内部变量title("Color Picker")

我有一个含糊的想法,即在定义了全局变量popup.show()之后调用函数showthis指的是全局对象。这是逻辑解释吗?

代码: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"

5 个答案:

答案 0 :(得分:5)

this取决于您如何调用使用this的函数。

1。作为一个函数调用

functionName();

在这种情况下,this将始终引用全局对象(通常是window对象)。

Example

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仍然引用全局对象。

2。使用新关键字

进行通话
var obj = new functionName();

在这种情况下,this将引用新创建的对象。

Example

a = 2;
function XY(a) {
    this.a = a;
}

var xy = new XY(1);
console.log(xy.a); //1

3。作为方法调用

obj.functionName();

在这种情况下,this将引用包含您正在调用的函数的对象。

Example

a = 2;
var xy = {
    a: 1,
    func: function() {
        console.log(this.a);
    }
}
xy.func(); //1

4。使用apply

进行呼叫
functionName.apply(thisObj, argArray);

在这种情况下,this将为new Object(thisObj),其中thisObj是函数apply的第一个参数。

Example

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"}

5。由事件处理程序调用

正如用户Mifeet所建议的那样,事件也会改变this

的上下文

事件是一个单独的主题。它们不是EcmaScript的一部分,通常由不同的浏览器以不同方式处理。然而,关于this的差异很小,对于IE> 8据我所知,不存在。

this将引用触发事件的DOM元素,除非您使用内联事件处理程序。在这种情况下,this将引用全局对象。

Example

<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>

对活动的评论

  • 版本9之前的Internet Explorer不支持addEventListener,而是attachEvent。使用此函数还将导致this引用全局对象。
  • 直接位于HTML标记内的
  • 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));