向原型添加函数 vs 对象字面量(使用 this)

Adding function to prototype vs object literal (using this)

我知道,如果我将一个函数添加到构造函数原型中,那么使用该构造函数的每个对象都可以使用该函数。而且我知道,如果您将函数添加为(我认为它被称为对象文字?),您将必须将其作为构造函数本身的 属性 来访问。 (Difference between adding function to prototype and object literal in javascript).

但是,如果您在构造函数中将新函数声明为 'this.xxx()' 会怎么样。这与在原型上声明 属性 有什么不同?

我的猜测是,在原型上声明函数对象会导致委托(并且该函数只会存在一个副本)。与 'this' 相比,每个构造的对象都会有自己的函数副本。

对吗?

function A () {
}

A.prototype.printNum = function () {
    console.log('hi');
}

x = new A ();
x.printNum(); // hi

function B () {
    this.printNum = function () {
        console.log('hi');
    }
}

y = new B ();
y.printNum(); // hi

不同的是当你调用构造函数(使用new)你执行里面的东西,所以,如果你添加声明一堆时间new B()你会遇到性能问题。

您的直觉是正确的,通过检查函数引用是否相同很容易自己检查。只需将这些行添加到您的示例代码中:

var x2 = new A();
var y2 = new B();

y.printNum === y2.printNum; //will return false
x.printNum === x2.printNum; //will return true

所以确实,当函数在原型上时,两个实例对象将共享引用。 (因为当 printNum 属性 查找在 xx2 上失败时,它将被委托给相同的原型对象,A.prototype。如果 yy2,两个实例都有一个自己的printNum属性,所以原型链甚至都没有被查询。)

(顺便说一句,对象字面量是一个几乎不相关的主题,请参阅 MDN 了解它的定义。)

你是对的。

function A() {}
A.prototype.printNum = function() {};

function B() {
  this.printNum = function() {};
}

var a1 = new A();
var a2 = new A();
console.log(a1.printNum == a2.printNum); // true

var b1 = new B();
var b2 = new B();
console.log(b1.printNum == b2.printNum); // false

在第一种情况下,函数实现有一个实例printNum。在第二种情况下,B 的每个实例都有自己的函数 printNum.

拥有许多函数会占用更多内存并且对象创建成本更高,但原型查找也会成为性能问题(根据某些人的说法,我仍然更喜欢它们)。


还有一个区别:很多库使用object.hasOwnProperty()来判断一个属性是否是"is part of"一个对象。 object.hasOwnProperty() returns true 如果 属性 是在对象本身上定义的而不是被继承的。

var a = new A();
cosole.log(a.hasOwnProperty('printNum')); // false

var b = new B();
console.log(b.hasOwnProperty('printNum')); // true

例如,JSON.stringify 使用它来检查哪些属性应包含在其输出中。这并不重要,因为我们正在谈论函数(JSON.stringify 将忽略它),但让我们使用这个例子:

function C() {}
C.prototype.myvar = "Hello world!";

function D() { this.myvar = "Hello world!"; }

var c = new C();
var d = new D();
console.log(JSON.stringify(c)); // {}
console.log(JSON.stringify(d)); // {"myvar":"Hello world!"}

在 ES5 之前,在 JavaScript 中创建变量 "final" (Java) / "readonly" (C#) 是相当困难的。第二种方法允许这样做:

function C(finalVariable) {
  this.getMyVariable = function() { return finalVariable };
}

我并不是说这是好的风格或者应该在实践中使用(它甚至不安全,因为 getMyVariable 也可能被覆盖),这只是一个事实:使用这个函数实例化允许从构造函数访问变量,而不通过对象属性将它们暴露给其他函数。