将函数挂钩到原型与否之间的差异

时间:2013-06-28 10:00:07

标签: javascript prototype

有什么区别:

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

Gandalf.prototype.comeBack = function() {
    this.color = 'white';
}

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

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

我应该在哪种情况下将方法挂钩到原型上?

3 个答案:

答案 0 :(得分:4)

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

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

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


好吧,现在我要做一些很棒的事。我将从radagast创建gandalf

var radagast = Object.create(gandalf);

radagast.color = "brown";

这里发生了什么?让我们分手吧:

  1. 我们使用Object.createradagast创建一个名为gandalf的新对象。因此radagast继承自gandalf
  2. 我们将color的{​​{1}}设置为棕色而不是灰色。
  3. 为了让事情更简单,想象一下你和我进行了以下对话:

    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.

    这正是继承在JavaScript中的作用。您看到JavaScript具有原型继承。在原型继承中,对象继承自其他对象。在这种情况下,I: Well Radagast is just like Gandalf except that he's brown instead of white.继承自radagast


    现在他们的方式原型继承通常在JavaScript中实现很奇怪。我称之为constructor pattern of prototypal inheritance。例如,拿你的代码:

    gandalf

    现在,当您创建function Gandalf() { this.color = "grey"; } Gandalf.prototype.comeBack = function() { this.color = "white"; return this; }; 实例时,实例会从哪个对象继承?它继承自Gandalf

    Gandalf.prototype

    当你说var gandalf = new Gandalf; alert(Object.getPrototypeOf(gandalf) === Gandalf.prototype); // true 时,会发生什么:

    new Gandalf

    如果您展开var gandalf = Object.create(Gandalf.prototype); Gandalf.call(gandalf); ,则获得:

    Gandalf.call(gandalf)

    现在举个例子:

    var gandalf = Object.create(Gandalf.prototype);
    gandalf.color = "grey";
    

    在这种情况下,当您创建function Gandalf() { this.color = "grey"; this.comeBack = function() { this.color = "white"; return this; }; } 的实例时,您基本上是这样做的:

    Gandalf

    因此,每次创建新var gandalf = Object.create(Gandalf.prototype); gandalf.color = "grey"; gandalf.comeBack = function () { this.color = "white"; return this; }; 时,都会创建一个新函数Gandalf。因此,如果您拨打comeBack 10次,您将拥有10个不同的new Gandalf功能。

    与第一个示例中的情况相比,comeBack定义了comeBack后,每次调用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
    

    请记住,在函数调用之前使用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 时,实际上是从函数的new继承。不是功能本身。


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

    prototype

    感谢您阅读我的回答。

答案 1 :(得分:3)

将它放在原型上的原因是因为创建的每个对象都可以使用相同的函数对象(函数只是可调用对象),它们只需要不同的标识和数据。但在第二种情况下,即使它们可以使用相同的函数对象,也要为每个对象创建唯一的函数对象。

由于您似乎了解PHP,因此PHP中的差异类似:

class Gandalf {
    public $color = "grey";

    public function comeBack() {
        $this->color = "white";
    }
}


class Gandalf {
    public $color = "grey";

    //Create the method inside constructor everytime
    public function __construct() {
        $this->comeBack = function() {
            $this->color = "white";
            return $this;
        }->bindTo($this, $this);
    }
}

当表现不是一个问题时,很难说何时使用另一个。个人而言 构造函数和additional indentation level的模糊处理足以让我更喜欢原型。

答案 2 :(得分:0)

回答:

  

我应该在哪种情况下将方法挂钩到原型上?

如果你有一个函数需要访问用构造函数创建的对象的私有vars,它需要在构造函数内部。

function Gandalf() {
    var age = '30000'; //approximate

    this.alertAge1 = function() {
        alert( age );
    };
}

Gandalf.prototype.alertAge2 = function() {
    // age not visible from here
};