【问题标题】:When does aPerson.firstname and aPerson.lastname actually change in this code snippet?此代码段中的 aPerson.firstname 和 aPerson.lastname 何时实际更改?
【发布时间】:2017-12-11 22:48:55
【问题描述】:

我正在通过一些 JavaScript koans 来学习语言语法,但我对这组测试感到困惑:

it("should know that variables inside a constructor and constructor args are private", function () {
    function Person(firstname, lastname)
    {
      var fullName = firstname + " " + lastname;

      this.getFirstName = function () { return firstname; };
      this.getLastName = function () { return lastname; };
      this.getFullName = function () { return fullName; };
    }
    var aPerson = new Person ("John", "Smith");

    aPerson.firstname = "Penny";
    aPerson.lastname = "Andrews";
    aPerson.fullName = "Penny Andrews";

    expect(aPerson.getFirstName()).toBe("John");
    expect(aPerson.getLastName()).toBe("Smith");
    expect(aPerson.getFullName()).toBe("John Smith");

    aPerson.getFullName = function () {
      return aPerson.lastname + ", " + aPerson.firstname;
    };

    expect(aPerson.getFullName()).toBe("Andrews, Penny");
  });

我知道构造函数中的变量是私有的,这就是为什么即使在尝试设置 aPerson.firstname、lastname 和 fullName 之后调用 getFullName() 时仍会打印“John Smith”的原因。但随后创建了一个名为 getFullName() 的函数,然后调用函数“Andrews, Penny”打印出来。

我本来希望打印“Smith, John”,因为这个新函数是在“失败”尝试将 firstname 设置为“Penny”并将 lastname 设置为“Andrews”之后创建的。为什么要打印“Andrews, Penny”?

谢谢

【问题讨论】:

  • 这不取决于it()expect()toBe() 的实际作用吗?你错过了一些代码吗?
  • 当您说它们是“私人的”时,您几乎已经确定了。如果没有二传手,您还能期待什么?
  • 嗯,是的,那些作用域变量是私有的。除了在构造函数中定义的函数之外,没有其他函数能够访问它们。如果特权方法被不同的方法覆盖,这不会改变。另请注意,覆盖函数确实专门访问 aPerson 属性,而不是范围内的任何变量。

标签: javascript syntax


【解决方案1】:

这里的关键是new operatorvar aPerson = new Person ("John", "Smith") 创建一个新的Person,传入JohnSmith 作为Person 函数使用的名称,并将函数的新实例分配给变量aPerson

注意Person 函数内部的var fullName = firstname + " " + lastname。这将在调用 Person 函数时将传递的任何内容作为函数参数。此时,this.getFullName 将等于 John Smith

当你运行aPerson.firstname = "Penny" 这只会更新Personnew 实例;它不会修改原始的Person 函数。当您调用 aPerson.getFirstName() 时,getFirstName() 方法返回为 Person (John) 最初设置为 firstname 的内容,而不是为新实例 aPerson (Penny) 设置的内容)。

因此,您第一次拨打aPerson.getFullName()时,姓名为John Smith

您的新函数aPerson.getFullName = function () { } 返回aPerson.lastname + ", " + aPerson.firstname。与前面的函数不同,它从Person (Penny Andrews) 的new 实例中获取姓氏和名字。

因此,您第二次拨打aPerson.getFullName()时,姓名为Penny Andrews

希望这会有所帮助! :)

【讨论】:

    【解决方案2】:

    首先,你需要明白这一点:

    function Person(firstname, lastname)
    {
      var fullName = firstname + " " + lastname;
      ...
    }
    
    var aPerson = new Person ("John", "Smith");
    

    在这里,您创建的唯一东西是一个只有方法的对象,甚至没有属性,如名字、姓氏。 (用 var 声明的参数和变量不会附加到您的对象上)

    所以你的对象 aPerson 是这样的:

    {
        getFirstName: function(), // => John
        getLastName: function(), // => Smith
        getFullName: function() // => John Smith
    }
    

    然后:

    aPerson.firstname = "Penny";
    aPerson.lastname = "Andrews";
    aPerson.fullName = "Penny Andrews";
    

    您为您的 aPerson 对象分配了新属性。于是,就变成了这样:

    {
        firstname: "Penny",
        lastname: "Andrews",
        fullName: "Penny Andrews",
        getFirstName: function(), // => John
        getLastName: function(), // => Smith
        getFullName: function() // => John Smith
    }
    

    接下来,你用这个覆盖 getFullName:

    aPerson.getFullName = function () {
        return aPerson.lastname + ", " + aPerson.firstname;
    };
    

    如您所见,您使用了这些新属性。

    现在,您应该能够理解您的结果了。 如果你进行替换,你会得到这个:

    aPerson.getFullName = function () {
        return aPerson.lastname + ", " + aPerson.firstname;
        //     Andrews             ,     Penny
    };
    

    瞧!这就是你得到结果的原因;)

    【讨论】:

      猜你喜欢
      • 2019-03-04
      • 2018-02-22
      • 1970-01-01
      • 2021-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多