我在下面创建了两个员工类,一个使用构造函数,另一个使用JSON表示法。在构造函数中,print
函数是由原型(prototype)创建的,因此将仅保留一个副本,并且对象(emp1
和emp2
)共享此print
函数。
问题:在JSON表示法(EmployeeNew
)中,print
函数是否仅作为一个副本保存在内存中?还是每个对象都保留自己的副本?这两种方法之间的根本区别是什么?哪种情况最适合?
var Employee = function (name) {
this.name = name;
};
Employee.prototype.print = function () {
console.log(this.name);
}
var emp1 = new Employee("jack"),
emp2 = new Employee("mark");
emp1.print();
emp2.print();
var EmployeeNew = {
init: function (name) { this.name = name; },
print: function () {
console.log(this.name);
}
};
var empNew1 = Object.create(EmployeeNew),
empNew2 = Object.create(EmployeeNew)
empNew1.init("jack")
empNew1.print();
empNew2.init("jack");
empNew2.print();
最佳答案
您的两个代码示例通常是等效的(除了一些与问题无关的小细节)。
这个...
Object.create(EmployeeNew)
...以
EmployeeNew
对象为其原型(prototype)创建一个新对象。因此,print
和init
函数是共享的。console.log(empNew1.init === empNew2.init); // true
console.log(empNew1.print === empNew2.print); // true
为了进一步说明,这是一个采用以下步骤的示例...
EmployeeNew
使用的Object.create
对象Object.create
创建2个唯一的对象EmployeeNew
EmployeeNew
添加新函数步骤1:创建
EmployeeNew
对象var EmployeeNew = {
init: function (name) { this.name = name; },
print: function () {
console.log(this.name);
}
};
步骤2:使用
Object.create
创建2个唯一的对象var empNew1 = Object.create(EmployeeNew),
empNew2 = Object.create(EmployeeNew)
步骤3:验证新对象可以使用
EmployeeNew
提供的功能empNew1.init("jack");
empNew1.print();
empNew2.init("jack");
empNew2.print();
步骤4:向
EmployeeNew
添加新功能EmployeeNew.foo = function() {
console.log( 'Foo was invoked' );
};
步骤5:查看步骤2中的对象是否可以使用该新功能
empNew1.foo(); // logs 'Foo was invoked'
empNew2.foo(); // logs 'Foo was invoked'
因此,您可以看到
empNew1
和empNew2
能够观察到EmployeeNew
的更改。这是因为当我们将EmployeeNew
作为Object.create
的第一个参数传递时,我们创建了一个新对象,并将EmployeeNew
设置为该对象的prototype
。简单来说,当我们在
empNew1
上查找属性时,如果empNew1
没有该属性,它将自动查找其原型(prototype)以查看该对象上是否存在该属性。如果是这样,它将使用它。关于您的评论...
是的,如果我们这样做...
EmployeeNew.name = "unknown"
...然后该属性将在所有以
EmployeeNew
作为其原型(prototype)对象的实例之间共享。但
因为原型(prototype)上的
.name
属性是一个不变的原始值(字符串),所以如果我们尝试对该属性进行写入,则会发生的情况是.name
属性被自动直接添加到实例中。继续上面的示例...
EmployeeNew.name = "unknown";
现在,先前创建的实例将引用该属性...
empNew1.name; // "unknown"
empNew2.name; // "unknown"
...但是现在让我们在一个实例上更新属性...
empNew1.name = "bubba";
empNew1.name; // "bubba"
empNew2.name; // "unknown"
这是因为
empNew1
现在具有引用.name
的自己的"bubba"
属性。这遮盖了.name
原型(prototype)上的empNew1
属性,因此对该属性的搜索永远不会扩展到原型(prototype)对象中。由于没有为
empNew2
分配.name
,因此它仍然会针对该属性使用其原型(prototype)。