编写JS原型时,所有函数都应该使用原型对象

Writing JS Prototypes, should all functions use the Prototype object?

本文关键字:原型 对象 JS 编写 函数      更新时间:2024-06-04

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

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

但我看到很多开发人员在Prototype对象中创建他们所有的代码,我认为这些东西是"私有的"。这是一种糟糕的做法还是被认为是可以的?这只是意味着我可以做:

module.privateFn();

他们知道吗?这样可以吗?感谢您的帮助。我一直在查看GitHub上的源代码,试图建立最佳的前进道路,这里有一个脚本,它对所有事情都使用原型(例如attachEvent,他们显然希望私下保存):

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

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

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

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

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!'

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

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

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中定义私有方法的示例之一。私有函数的问题,它们无法测试。没有办法测试某些ExtremeComputations方法。

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

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;
}());

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

当谈到你的例子时,没有原型。

的简单示例

// 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";