【问题标题】:Beginner JavaScript Pattern初学者 JavaScript 模式
【发布时间】:2016-05-03 04:19:01
【问题描述】:

我最近开始研究对象、闭包、作用域等。我正在尝试使用这些技术实现我自己的代码,但遇到了问题。

function Person(name, age) {
    this.name = name;
    this.age  = age;

    return {
        ageUp: function ageUp() {
            this.age++;
        },
        printInfo: function printInfo() {
            console.log(this.name + " is " + this.age + " years old");
        },
        changeName: function changeName(newName) {
            this.name = newName;
        }
    }
}


var jeff = new Person('jeff', 28);
jeff.printInfo();

奇怪的是,这会返回undefined is undefined years oldprintInfo 属性在其范围内是否没有 this.name,因为返回的对象没有对该函数的回忆?

同样奇怪的是,如果我将 this.namethis.age 的所有实例更改为常规私有变量(例如 var personName = name;),返回的对象会以某种方式正常运行,我可以使用 ageUp 和 @ 987654329@ 符合预期。

我是否结合了两种不应该的设计模式?解决此问题的最佳方法是什么?

【问题讨论】:

    标签: javascript object design-patterns


    【解决方案1】:

    问题是当你这样做时:

    return { ...
    

    您正在创建一个新对象,该对象与先前使用 new 关键字创建的对象(您为其分配了两个属性的对象)分开。你可能会注意到jeff instanceof Person 是假的,jeff.constructor === Object

    看这个例子:

    function Person(name, age) {
        this.name = name;
        this.age  = age;
    
        return {
            theObjectThatNewCreated: this
        }
    }
    
    var jeff = new Person('jeff', 28);
    console.log( JSON.stringify( jeff ) );
    // {"theObjectThatNewCreated":{"name":"jeff","age":28}}
    console.log( jeff.constructor );
    // Object
    console.log( jeff.theObjectThatNewCreated.constructor );
    // Person
    

    您可以通过将 name 和 age 属性分配给您返回的对象而不是 this 来修复它:

    function Person(name, age) {
        return {
            name: name,
            age: age,
            ageUp: function ageUp() {
                this.age++;
            },
            printInfo: function printInfo() {
                console.log(this.name + " is " + this.age + " years old");
            },
            changeName: function changeName(newName) {
                this.name = newName;
            }
        }
    }
    
    
    var jeff = new Person('jeff', 28);
    jeff.printInfo();
    

    但是 Person 并不是真正的构造函数,它只是一个对象工厂,用new 调用它是没有意义的。它返回的对象不是 Person 的实例,它们是普通的旧对象。有更好的办法。

    我是否结合了两种不应该的设计模式?解决此问题的最佳方法是什么?

    我会说你正在将显示模块模式与普通的 JavaScript 构造函数结合起来。

    您可以一直使用this,而不是返回一个新对象,将这些函数分配为 Person 对象的属性,而不是一个新对象:

    function Person(name, age) {
        this.name = name;
        this.age  = age;
    
        this.ageUp = function ageUp() {
            this.age++;
        };
    
        this.printInfo = function printInfo() {
            console.log(this.name + " is " + this.age + " years old");
        };
    
        this.changeName = function changeName(newName) {
            this.name = newName;
        };
    }
    
    
    var jeff = new Person('jeff', 28);
    jeff.printInfo();
    

    但由于这些函数不使用构造函数中的任何封闭变量,因此实际上应该将它们添加到构造函数的原型中:

    function Person(name, age) {
        this.name = name;
        this.age  = age;
    }
    
    Person.prototype.ageUp = function ageUp() {
        this.age++;
    };
    
    Person.prototype.printInfo = function printInfo() {
        console.log(this.name + " is " + this.age + " years old");
    };
    
    Person.prototype.changeName = function changeName(newName) {
        this.name = newName;
    };
    
    var jeff = new Person('jeff', 28);
    jeff.printInfo();
    

    【讨论】:

    • 好答案,您能否澄清一下“那些函数不使用构造函数中的任何封闭变量”这句话?没看懂……
    • @chenop 我的意思是在构造函数中用var 声明的变量,或者构造函数的参数。
    【解决方案2】:

    您是正确的,因为您正在组合两种模式。首先,在正常情况下,构造函数不会返回任何内容。 (有一些例外,我不会在这里深入研究)。

    你可能想做这样的事情:

    function Person(name, age) {
        this.name = name;
        this.age  = age;
    }
    
    Person.prototype.printInfo = function() {
        console.log(this.name + " is " + this.age + " years old");
    };
    
    // and so on. Now you can say
    
    var jeff = new Person('jeff', 28);
    jeff.printInfo(); // => jeff is 28 years old
    

    我假设您想要原型上的这些方法,以便共享它们(但这不是强制性的)。

    【讨论】:

      【解决方案3】:

      您在构造函数中返回了一个新对象。因此,在调用 new Person(...) 时,您不会收到 Person 的实例,而不是具有您定义的属性的转储对象。

      尝试将方法对象定义为构造函数的原型:

      function Person(name, age) {
          this.name = name;
          this.age  = age;
      }
      
      Person.prototype = {
          ageUp: function ageUp() {
              this.age++;
          },
          printInfo: function printInfo() {
              console.log(this.name + " is " + this.age + " years old");
          },
          changeName: function changeName(newName) {
              this.name = newName;
          }
      }
      

      或者,如果你想保持你的属性 nameage 私有,你可以在构造函数中定义你的方法。只需将方法分配给this.。对于私有属性,您不必将属性本身分配给您的实例:

      function Person(name, age) {
          this.ageUp = function ageUp() {
              age++;
          };
      
          this.printInfo = function printInfo() {
              console.log(name + " is " + age + " years old");
          };
      
          this.changeName = function changeName(newName) {
              name = newName;
          };
      }
      

      但我更喜欢第一个例子。第二,每个新实例都会创建新方法。在第一个示例中,您的所有实例都引用了应该使用更少内存的单个原型对象。

      【讨论】:

        【解决方案4】:

        在你的类中移除周围的 return {},它应该可以工作。

        【讨论】:

          猜你喜欢
          • 2016-09-10
          • 1970-01-01
          • 1970-01-01
          • 2021-06-06
          • 1970-01-01
          • 1970-01-01
          • 2022-10-15
          • 2018-06-18
          • 2017-02-24
          相关资源
          最近更新 更多