Javascript 在object或object.prototype上定义属性?

Javascript 在object或object.prototype上定义属性?,javascript,oop,Javascript,Oop,我最近看到了JavaScript代码,其中getter和setter方法在构造函数方法的原型对象上定义 例如: Person.prototype.getFirstName = function() { return this.firstName; } 这是正确的吗 我的意思是: “this”指向调用该方法的对象的描述符 当我打电话给 console.log(Person.getFirstName()); console.log(Person.getFirstName()); 。。。没有

我最近看到了JavaScript代码,其中getter和setter方法在构造函数方法的原型对象上定义

例如:

Person.prototype.getFirstName = function() {
  return this.firstName;
}
这是正确的吗

我的意思是: “this”指向调用该方法的对象的描述符

当我打电话给

console.log(Person.getFirstName());
console.log(Person.getFirstName());
。。。没有事先做一个物体

此外:

何时将属性附加到构造函数方法以及何时附加到原型对象,是否有一般规则


从我的观点来看,如果你不一定要创建一个对象的话,那么这个原型是正确的。因为该方法不使用必须单独设置对象的对象值。

原型通过使用
new
关键字实例化来继承

因此,代码

var Person = function(){}
Person.prototype.getFirstName = function() {
  return this.firstName;
}

Person.prototype.firstName = "test";

console.log(Person.getFirstName()); // Throw Uncaught TypeError 
正确的方法是:

var Person2 = new Person()
Person2.getFirstName() // "test"
要测试此对象,请执行以下操作:

因此,
Person
Prototype
被设置为
这个
Person2的对象(继承)

这与Java或C语言中的类类似

当我打电话给

console.log(Person.getFirstName());
console.log(Person.getFirstName());
。。。没有事先做一个物体

出现错误,
Person
没有
getFirstName
属性

何时将属性附加到构造函数方法以及何时附加到原型对象,是否有一般规则

是的:

如果希望通过构造函数函数创建的对象(例如,在
var obj=new Person()
中的
obj
上)可以使用该方法,请将该方法放在构造函数函数的
原型
对象(共享)上,或通过将该方法分配给
上的属性,将该方法分配给构造函数中的对象(不共享)

如果希望该方法在构造函数本身上可用,请按照某些内置JavaScript方法的方式(如
Date.parse
Object.create
),将其分配给构造函数上的属性:

Person.doSomething = function() {
    // ...
};
这些方法并不特定于构造函数创建的对象(
这些方法中的
是对构造函数函数本身的引用,除非您做了一些改变)

如果你来自一种基于类的语言,一个非常松散的类比是属性(包括方法)在构造函数中为
prototype
对象或
this
指定的是实例属性,为构造函数本身指定的是静态属性。这是一个非常松散的类比,但有时很有用

以下是旧ES5和早期语法的完整示例:

function Person(name) {
    this.getName = function() {
        return name;
    };
}
Person.prototype.sayHello = function() {
    console.log("Hello, my name is " + this.getName());
};
Person.copy = function(other) {
    return new Person(other.getName());
};

// Usage example
var joe = new Person("Joe");
joe.sayHello();
console.log("joe's name is " + joe.getName());
var joeagain = Person.copy(joe);
joeagain.sayHello();
在上述情况下:

  • getName
    可用于由
    new Person
    创建的实例。它是为每个对象单独创建的,不与其他实例共享。它允许我们获取人名,在本例中是只读的

  • sayHello
    在由
    new Person
    创建的实例上可用,因为它们从原型继承,原型由
    new Person
    Person.prototype
    属性分配给它们。它在实例之间共享

  • copy
    在实例上不可用(
    joe.copy()
    将是一个错误),它是
    Person
    本身的属性。在本例中,我们使用它来复制实例,但它可以用于任何用途


我个人不喜欢在原型中添加
getter
,如果您只想访问实例值。您已经可以通过实例访问这些值:

function Person(name) {
   this.firstname = name;
}
Person.prototype.getFirstname = function() {
   return this.firstname;
}
var p = new Person('o-o');
console.log(p.firstname); //o-o
console.log(p.getFirstname()); //o-o
您可以向原型添加一个
getter
,以传递不同的上下文:

var firstname = Person.prototype.getFirstname.call({firstname: 'other'});
console.log(firstname); // other
如果是这样的话,在原型中添加一个
getter
来增加一些计算是有意义的:

Person.prototype.getFirstname = function() {
   return new Date().toISOString + ': ' + this.firstname;
};
如果该策略适合您的需要,您可以以不同的方式编排代码:

var common = {
  getValue = function(propName) {
     return new Date().toISOString() + ': ' + this[propName];
  }
};

function Person(name) {
   this.firstname = name;
}

$.extend(Person.prototype, common); //jQuery extend
var p = new Person('o-o');
console.log(p.firstname); //o-o
console.log(p.getValue('firstname')); //today: o-o

使用通用的
扩展您的原型:在开发过程中添加日志信息,并在生产过程中删除那些多余的日志信息。

太棒了。您帮了我很多。谢谢。)