function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
var func = john.says;
func();
我尝试此示例时,我收到以下消息undefined rocks!
而不是Ruby rocks!
。
你能解释一下为什么会这样吗。
答案 0 :(得分:7)
this
关键字 JavaScript 函数在调用时具有执行上下文,以便this
关键字绑定到从中调用它们的对象。如果您致电john.says()
,该函数的执行上下文将包含指向this
的{{1}}关键字。如果您将全局变量john
分配给在对象func
上找到的方法says
,则已将执行上下文更改为全局对象。当您调用john
函数时,func
取消引用this
(或window
*)并且由于undefined
未定义,window.skill
将强制执行将值转换为字符串以将其与字符串'连接起来。岩石'!
您可以将函数的副本绑定到对象(有效地锁定它的上下文引用):
says
或者,您可以通过在构造函数中使用闭包来关闭相关位:
var func = john.says.bind(john);
您可以直接从方法中引用function Developer(skill){
var _this = this; // we keep a reference here
this.skill = skill;
this.says = function(){
alert(_this.skill + ' rocks!');
// when invoked _this refers to the context at construction
}
return this;
}
值,因此根本不需要上下文:
skill
最后的选项是在调用时使用您想要的上下文调用该方法:
function Developer(skill){
// because skill is defined in this context, says will refer to this context
// to get the value of the skill variable.
this.says = function(){
alert(skill + ' rocks!');
}
}
如果我们想在对象实例或类型之间重用一个方法,但在调用时有正确的执行上下文,我们可以使用prototype属性。
func.call(john /*, optional arguments... */);
func.apply(john /*, optional arguments as an array */);
*"使用严格"激活表示JavaScript未来的特殊严格模式。当尚未设置上下文时,此特殊严格执行环境将无法解析为全局对象,而是将其解析为适当范围的值function Developer(skill){
this.skill = skill;
this.says();
}
Developer.prototype.says = function(){
alert(this.skill + ' rocks!');
}
var john = new Developer("Ruby"); // alert("Ruby rocks!")
var tony = new Developer("JavaScript"); // alert("JavaScript rocks!")
。
答案 1 :(得分:2)
让我们通过实际返回对象来说明发生了什么:
function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
return this; //this is basically { skill: skill, says: function() {} }
}
var john = new Developer('Ruby');
var func = john.says; // all it knows is the function() part, has no knowledge of skill
func(); //undefined rocks!
好的,为什么我们会变得不确定?好吧,一旦我们删除了该函数,它就不再具有上下文 - 它不知道this
是什么。如果我们这样做:
func.apply(john);
然后我们将John作为this
参数传递给我。一种解决方法,它在我们创建它时将值传递给函数:
function Developer(skill) {
this.skill = skill;
this.says = function(skill) { //<--calling this function
return function() { //<--returning this function
alert(skill + ' rocks!');
};
}(this.skill); //<--passing in the value here
return this;
}
答案 2 :(得分:1)
因为func()
只有该功能,而没有任何其他相关信息。(this.skill)
背景丢失了。调用this
时john
引用says()
。
但现在,当您致电func()
this
时,会引用window
。因此this.skills
将返回undefined
,除非您有一个同名的全局变量。
答案 3 :(得分:1)
调用函数时,this
将引用调用该函数的对象。
当你说
时var func = john.says;
您只是获取功能对象(它不记得定义它的对象)。
当你调用这个函数时,就像这样
func();
没有当前对象,在其上调用func
。因此,默认情况下,JavaScript将全局对象(浏览器中的window
对象)指定为this
。由于skill
未在全局对象中定义,因此返回undefined
。
注意:在严格模式下,如果没有当前对象,this
将为undefined
。
这就是为什么我们必须将对象显式绑定到函数,就像这个
func.bind(john)();
Function.prototype.bind
将返回一个新函数,该函数绑定到john
。因此,当您调用此this
时,将引用john
。
答案 4 :(得分:0)
保持上述模式的最快方法是将this
直接绑定到方法this.says = function () { ... }.bind(this);
:
function Developer(skill) {
this.skill = skill;
this.says = function () {
alert(this.skill + ' rocks!');
}.bind(this);
}
var john = new Developer('Ruby');
var func = john.says;
func(); // Ruby rocks!
答案 5 :(得分:-1)
试试这个
function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
john.says();