2

我正在尝试从在线教程中学习 JS - http://ejohn.org/apps/learn/#33,你可以在那里测试 JS 代码。我试图将嵌套函数理解为其他函数内部的方法以及“this”关键字当时引用的内容。为什么如果我从下面添加上面的站点代码 - 它不起作用?有人可以解释 JS 的那个方面吗?

function Ninja(name){
  this.name = name;
  this.changeName = function(newname) {
    this.name = newname;
    this.anotherFunction = function(newname2) {
      this.name2 = newname2;
    }
  }
}

var ninja = new Ninja("John");
assert( ninja.name == "John", "The name has been set on initialization" );

// ninja.anotherFunction("Luken");
// ninja.changeName.anotherFunction("Luken");
// Why both above functions doesn't work?

assert(ninja.name2, "It works?");

ninja.changeName("Bob");
assert( ninja.name == "Bob", "The name was successfully changed." );
4

2 回答 2

3

的值this是在调用函数时确定的,而不是在定义时确定的。所以在你的代码中,你必须有不同的值this: 当ninja.changeName()被调用时,你没有为 指定一个值this,所以它要么是未定义的,要么是现在的任何值。

new另一方面,操作符在调用函数之前确实设置thisNinja

您需要做的是“保存” thisinside of的值,Ninja以便内部函数继续使用它(而不是在this调用它们时可能存在的任何随机值)。这样做比听起来更简单:

function Ninja(name){
  this.name = name;

  var self = this; // Create a hidden reference to "this" that is only visible in
                   // any functions defined before we return

  self.changeName = function(newname) {
    self.name = newname;
    self.anotherFunction = function(newname2) {
      self.name2 = newname2;
    }
  }
}

这是因为 JavaScript 在定义函数时保留了上下文(= 所有可访问变量)的副本。

于 2012-10-03T13:25:09.620 回答
1

这很简单:

function Ninja(name)
{//this points to Ninja object inside constructor scope
    this.name = name;
    this.changeName = function(newname)
    {//method of Ninja, this points to context object, ie Ninja
        this.name = newname;//accesses the name property of Ninja
        this.anotherFunction = function(newname2)
        {//defines new method for this ==> Ninja object
            this.name2 = newname2;//context object is Ninja
        };
    };
}
var foo = new Ninja('foobar');
foo.name;//foobar
foo.changeName;//function, is defined in constructor
typeof foo.anotherFunction//undefined because it's assigned when the changeName method is called!
foo.changeName('Me');
foo.name;//Me
foo.anotherFunction('You');//works: changeName was called, and assigned anotherFunction to foo (instance of Ninja)
foo.name2;//You

发生了什么:简单,通过调用 changeName 方法,anotherFunction定义并分配给this. 当时this引用了该对象,因此该方法被分配给调用该方法Ninja的实例。在调用该方法之前,该方法根本不存在。NinjachangeNamechangeNameanotherFunction

虽然这可能看起来无用或愚蠢,但它确实是有道理的。您需要记住的是,函数/方法本质上是独立的对象。在这段代码中,它们恰好被定义为属性/方法,但它们不需要这样使用。回到上面的代码:

foo.name;//Me
bar = {};//some object
foo.changeName.apply(bar,['You']);
foo.name;//Me, nothing has changed, the changeName method was applied to the bar object
bar.name;//You, in the apply call, this pointed to bar, not foo
typeof bar.anotherFunction;//function
//You could even create the anotherFunction globally:
//  JUST TO SHOW YOU CAN, THIS IS DANGEROUS
//  ONLY USE THIS IF YOU KNOW WHAT THE POSSIBLE CONSEQUESES ARE!
foo.changeName.call();//in global scope
typeof antoherFunction;//function ==> this function is now globally available

changeName方法可以应用于任何对象,添加新方法,更改/添加某些属性到该特定实例。

于 2012-10-03T13:32:47.110 回答