将函数挂钩与原型上的区别

gsk*_*lee 5 javascript prototype

之间有什么区别:

function Gandalf() {
    this.color = 'grey';
}

Gandalf.prototype.comeBack = function() {
    this.color = 'white';
}
Run Code Online (Sandbox Code Playgroud)

和:

function Gandalf() {
    this.color = 'grey';

    this.comeBack = function() {
        this.color = 'white';
        return this;
    };
}
Run Code Online (Sandbox Code Playgroud)

在什么情况下我应该将该方法挂接到原型上,或者不挂接?

Aad*_*hah 6

好的,Kay 特工,我将以与 Esailija 不同的方式来处理这个问题。让我们从简单的对象开始。例如,假设您已经有一个名为的对象gandalf

var gandalf = {
    color: "grey",
    comeBack: function () {
        this.color = "white";
        return this;
    }
};
Run Code Online (Sandbox Code Playgroud)

此代码中没有构造函数。因此这段代码很容易理解。我到底是对还是对?


好吧,现在我要做一些了不起的事情。我将从radagast以下位置创建gandalf

var radagast = Object.create(gandalf);

radagast.color = "brown";
Run Code Online (Sandbox Code Playgroud)

这里发生了什么事?让我们把它分解一下:

  1. 我们创建一个名为radagastfrom gandalfusing的新对象Object.create。因此radagast继承自gandalf.
  2. 我们将color的设置radagast为棕色而不是灰色。

为了更简单地想象你和我进行了以下对话:

I: Hey Agent Kay, I met Radagast yesterday.

U: Who's Radagast?

I: Hmm... do you know who's Gandalf?

U: Yes, I do.

I: Well Radagast is just like Gandalf except that he's brown instead of white.

这正是继承在 JavaScript 中的工作原理。你会看到 JavaScript 具有原型继承。在原型继承中,对象继承自其他对象。在本例中radagast继承自gandalf.


现在,在 JavaScript 中实现原型继承的方式通常很奇怪。我将其称为原型继承的构造函数模式。例如,以您的代码为例:

function Gandalf() {
    this.color = "grey";
}

Gandalf.prototype.comeBack = function() {
    this.color = "white";
    return this;
};
Run Code Online (Sandbox Code Playgroud)

现在,当您创建一个实例时,Gandalf该实例继承自哪个对象?它继承自Gandalf.prototype

var gandalf = new Gandalf;
alert(Object.getPrototypeOf(gandalf) === Gandalf.prototype); // true
Run Code Online (Sandbox Code Playgroud)

当你说的new Gandalf是:

var gandalf = Object.create(Gandalf.prototype);
Gandalf.call(gandalf);
Run Code Online (Sandbox Code Playgroud)

如果你扩展Gandalf.call(gandalf)你会得到:

var gandalf = Object.create(Gandalf.prototype);
gandalf.color = "grey";
Run Code Online (Sandbox Code Playgroud)

现在来看第二个例子:

function Gandalf() {
    this.color = "grey";

    this.comeBack = function() {
        this.color = "white";
        return this;
    };
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,当您创建一个实例时,Gandalf您实际上是在执行以下操作:

var gandalf = Object.create(Gandalf.prototype);

gandalf.color = "grey";

gandalf.comeBack = function () {
    this.color = "white";
    return this;
};
Run Code Online (Sandbox Code Playgroud)

因此,每次创建一个新函数时,Gandalf您都会创建一个新函数comeBack。因此,如果您调用new Gandalf10 次,您也会有 10 个不同的comeBack函数。

与第一个示例中的 this 相比,sincecomeBack是在 上定义的Gandalf.prototype,每次调用new Gandalf我们都会得到一个继承自 的新对象Gandalf.prototype。因此,只有一个comeBack函数在 的所有实例之间共享Gandalf。那不是更好吗?


基本上想想你的第一个例子是这样的:

var gandalfPrototype = {
    create: function () {
        var gandalf = Object.create(this);
        gandalf.color = "grey";
        return gandalf;
    },
    comeBack: function () {
        this.color = "white";
        return this;
    }
};

var gandalf = gandalfPrototype.create(); // there's only one comeBack function
Run Code Online (Sandbox Code Playgroud)

同样,您的第二个示例相当于:

var gandalfPrototype = {
    create: function () {
        var gandalf = Object.create(this);

        gandalf.color = "grey";

        gandalf.comeBack = function () {
            this.color = "white";
            return this;
        };

        return gandalf;
    }
};

var gandalf = gandalfPrototype.create(); // there's 1 comeBack for each instance
Run Code Online (Sandbox Code Playgroud)

new请记住,当您在函数调用之前使用时,您实际上是从prototype该函数继承的。不是函数本身。


最后我想说(因为我是 JRR Tolkien 的忠实粉丝)这就是我编写代码的方式:

var wizard = {
    create: function (color) {
        var wizard = Object.create(this);
        wizard.color = color;
        return wizard;
    }
};

var gandalf = wizard.create("grey");

gandalf.comeBack = function () {
    this.color = "white";
    return this;
};

var saruman = wizard.create("white");
var radagast = wizard.create("brown");
Run Code Online (Sandbox Code Playgroud)

感谢您阅读我的回答。