编写JS Prototypes,是否所有函数都使用Prototype对象?

时间:2013-12-09 13:19:06

标签: javascript prototype

我开始学习使用Prototype对象编写JS的更多信息,但我想确保我不会从其他开发人员那里汲取任何坏习惯。我对使用Prototype的理解是为您的实例创建公共方法。例如:

var module = new Module();
module.method();

但我看到很多开发人员在Prototype对象中创建了所有代码,我认为这些代码是“私有的”。这是不好的做法还是认为好吗?这只是意味着我可以这样做:

module.privateFn();

他们知道吗?这样可以吗?任何帮助赞赏。我一直在浏览GitHub上的源代码以尝试建立最好的前进方法,这里是一个使用Prototypes的脚本(例如,他们显然想私下保留的attachEvent):

https://github.com/WickyNilliams/headroom.js/blob/master/dist/headroom.js

非常感谢,我想确保使用正确的实现进行开发。

2 个答案:

答案 0 :(得分:0)

用几句话解释这个是不可能的。一个好的模式是在想要优化代码时通过原型构建方法。一个好的准则是只将最重要的数据放在内存中,使用原型对此至关重要,因为原型变量和方法在您请求之前不会注入内存。

当你的例子出现时,没有原型。

简单示例

// new object
var Dog = function() {
    var that = this;

    // add a property
    that.name = "Fido";

    // add a method
    that.getName = function() {
        return that.name;
    };
};
// ... all the above is stored in memory directly     


// Requires to be constructed
var dogObj = new Dog();
console.log(dogObj.getName()); // Fido

delete Dog.name // false
typeof Dog.name // "string"
delete dogObj.name // true
typeof dogObj.name // "undefined"
typeof Dog.name // "string" (still there)

// Will be available in the dogObj (after you call it)
dog.prototype.first = "first";

// Will be available in the dogObj (after you call it)
dog.prototype.second = function() {
    return "second";
}

// Will not be available in dogObj
dog.third = "third";

答案 1 :(得分:0)

首先,您不需要使用原型编写模块。想想如果你写一个像类的东西你应该使用原型。而且定义你的方法也很重要。在原型对象上定义方法并在构造函数中定义它们是完全不同的事情!

让我们看一下使用构造函数中定义的方法的示例类定义:

var Dog = (function () {
    var Dog = function (age, name) {
        var that = this;

        this.age = age;
        this.name = name;

        this.sayHi = function () {
            console.log('Warf! Im ' + that.name); // meaning of "this" changed!!!
        };

        this.anotherMethod = function () {};
    };

    return Dog;
}());

var puppy = new Dog(1, 'puppy');   // sayHi and anotherMethod created
var sirius = new Dog(1, 'sirius'); // sayHi and anotherMethod recreated 

sirius.sayHi = function () { console.log('Yohalolop!'); };

puppy.sayHi();  // -> 'Warf! Im puppy'
sirius.sayHi(); // -> 'Yohalolop!'

因此上述示例存在一些问题,首先定义方法与任何其他实例变量一样。实际上是的,你将它们定义为实例变量,这意味着为你创建的每个实例对象重新创建这些函数。我想你已经提到过你不能在方法定义中使用这个关键字。这很容易出错,并且有可能忘记这一点并错误地使用这个关键字。有时候你可以使用方法作为实例变量,比如变量回调。

让我们看一下带有原型对象的示例类定义:

var Dog = (function () {
    var Dog = function (age, name) {
        this.age = age;
        this.name = name;
    };

    // sayHi method defined only once in prototype
    Dog.prototype.sayHi = function () {
        console.log('Warf! Im ' + this.name; // we can use this keyword
    };

    // anotherMethod defined only once in protoype
    Dog.prototype.anotherMethod() {
    };

    return Dog;
}());

var puppy = new Dog(1, 'puppy');   
var sirius = new Dog(1, 'sirius');  // sirius and puppy sharing same prototype object

puppy.sayHi();  // -> 'Warf! Im puppy'
sirius.sayHi(); // -> 'Warf! Im sirius'

// remember puppy and sirius sharing same prototype object
Dog.prototype.sayHi = function () {
    console.log('Yohalolop');
};

puppy.sayHi();  // -> 'Yohalolop'
sirius.sayHi(); // -> 'Yohalolop'

作为关于私人功能的问题的答案,它更复杂。是的,即使您在原型上定义方法,也可以使用私有函数,但是有一些关于测试的问题。使用它们取决于您。我更喜欢不使用。让我举几个例子。

var Calculator = (function () {
    var Calculator = function () {
        this.importantNumber = 2;
    };

    // There is unfortunately no native implementation
    // for private methods but you can mimic them with
    // unaccessible functions and binding.
    var someExtremeComputations = function () {
        return 40 + this.importantNumber; // this keyword points to instance because of binding
    };

    Calculator.prototype.getMeaningOfLife = function () {
        var result = someExtremeComputations.call(this); // we bind function to instance
        return result;
    };

    return Calculator;
}());

这是如何在javascript中定义私有方法的示例之一。私有功能的问题,无法测试。没有办法测试someExtremeComputations方法。

有些人(包括我)对私有方法使用带前缀的下划线命名约定。所以它们实际上是公共方法,但如果有人调用它们或覆盖它们,则会被前缀下划线警告。毕竟我们可以测试私有方法,因为它们是公开的。

var Calculator = (function () {
    var Calculator = function () {
        this.importantNumber = 2;
    };

    // private method's name prefixed by an underscore to warn
    // other developers to be careful about that or not to use.
    Calculator.prototype._someExtremeComputations = function () {
        return 40 + this.importantNumber; 
    };

    Calculator.prototype.getMeaningOfLife = function () {
        var result = this.someExtremeComputations(); // no need to bind
        return result;
    };

    return Calculator;
}());