对于那些来自C#等语言的人,我可以声称'this'关键字是Javascript中最令人困惑的部分。
我已经在互联网和StackOverflow上阅读了很多相关内容。例如here和here。
我知道'this'关键字将绑定到上下文。并且在构造函数中它将被绑定到正在创建的对象,并且当没有直接上下文时,它将绑定到全局对象(即窗口)
我知道这一切,但是混乱还没有完全清除;因此,最好的理解方法是测试代码。
所以我决定编写一些小代码,我对this
关键字的复杂程度感到惊讶。
这是我测试的代码:
function sayHi(name){
var tt = name;
return {
ss: tt,
work: function(anotherName){
alert ("hiiiii " + anotherName);
}
};
}
//this method invocation has no effect at all right now
sayHi("John");
var hi2 = new sayHi("wallace");
hi2.work("May");
alert(hi2.ss);
正如预期的那样,警报窗口将显示(Hiiiiii May)然后(华莱士)。现在请注意,sayHi("John");
行根本没有效果。
现在只有改变一件事时才会开始混淆(改变var tt => this.tt):
function sayHi(name){
//this is the ONLY change I did.
this.tt = name;
return {
ss: tt,
work: function(anotherName){
alert ("hiiiii " + anotherName);
}
};
}
// Now this line invocation will be problematic
sayHi("John");
var hi2 = new sayHi("wallace");
hi2.work("May");
alert(hi2.ss);
当警报方法(Hiiiiiii May)和(John)没有(华莱士)时,结果让我感到惊讶;
所以我有想法对sayHi("John");
行进行评论,但这导致整个代码无法正常运行。
我知道这可能是一个新问题。但这里真的很混乱,我确实尝试阅读很多文章和SO问题,但我忽略了这一点。
为什么行sayHi("John");
将hi2.ss设置为John?为什么在删除代码时会破坏代码;虽然我们之后使用sayHi
关键字调用new
方法?
答案 0 :(得分:6)
因为您指定了参数" name"对于this
引用的对象的属性(在本例中为window
),您随后引用" tt"在那个对象文字中将是" tt"全局对象的属性,因为它是下一个封闭范围。
你第一次打电话给" sayHi"在没有new
运算符的情况下生成,因此调用this
将引用全局对象(window
)。第二个版本中的第一行
this.tt = name;
因此会将window.tt
设置为" John"。
下一次调用是使用new
运算符进行的。因此,函数中的this
引用了新实例化的对象。这条线
this.tt = name;
因此,对任何事物都没有任何净影响,因为该函数在所有情况下都会返回不同的对象。测试的最后一行:
alert(hi2.ss);
约翰"因为那是window.tt
中的内容。为什么这么重要?因为" sayHi"返回一个对象,该对象具有从符号" tt"的值设置的属性(" ss")。唯一的" tt"在范围内将window.tt
,这是在第一次调用函数时设置的。
答案 1 :(得分:3)
当调用构造函数时,如果函数中不存在return语句,则隐式返回this
,否则返回返回值,并忽略this
。
在第二个示例中,您将name参数保存为this.tt
,但返回另一个对象。这就是事情不起作用的原因。基本上使用this
或返回自定义对象,但不要同时执行这两项操作。
答案 2 :(得分:3)
首次调用sayHi("John");
时,this
将指向全局对象window
。这意味着this.tt = name
实际上会创建一个全局tt
变量。
然后,当您调用new sayHi("wallace");
时,this
正确指向sayHi
的新实例,但您要返回另一个对象,而不是让new
自然返回实例。
如果仔细查看对象字面值,请将ss
定义为ss: tt,
。由于您没有使用this.tt
并且在构造函数的作用域中找不到tt
符号,因此该值将被解析为全局变量(之前已设置为John
)。