似乎有相当多的技术可以用于创建客户端对象。我发现真正令人困惑的是确定每种技术的名称。我以前用过原型
MyObject.prototype.someMethod = function (e, a) {
.....
};
但我也看到过像这样创建的不同对象
MyObject.someMethod = function () {
....
}
第二种技术叫什么,为什么要使用一种而不是另一种?
似乎有相当多的技术可以用于创建客户端对象。我发现真正令人困惑的是确定每种技术的名称。我以前用过原型
MyObject.prototype.someMethod = function (e, a) {
.....
};
但我也看到过像这样创建的不同对象
MyObject.someMethod = function () {
....
}
第二种技术叫什么,为什么要使用一种而不是另一种?
第一个示例类似于在类上定义方法。该类的每个实例都使用相同的代码;this
in 这样的方法指向调用该方法的实例。
第二个类似于在类上定义静态方法。您调用该方法,例如
MyObject.someMethod();
在实例上调用该方法没有意义。
我想您可以调用第一个“原型方法”和第二个“构造函数/类方法”。
如果您在谈论 javascript 时习惯使用经典的 OO 术语,这有点尴尬,因为 Javascript 使用原型继承,您可以调用第一个“实例方法”和第二个“静态方法”。
最简单的答案是,使用原型关键字在对象上定义方法将允许该方法用于从它继承的所有对象。
JavaScript 中没有类,但您可以通过使用原型对象(属性)来模拟继承。
myObject.prototype.method 将为从 myObject 派生的所有对象添加一个“方法”(您可以在 jQuery 加载后对 jQuery 执行此操作 - $.prototype.method [$.fn.method] 将为所有 jQuery 对象添加一个方法无论它们是何时创建的)。
myObject.method 只会向 myObject 添加一个“方法”,就像执行那行代码时一样(静态方法)。在此行执行之前调用的任何 myObject 都无法访问“方法”。
Javascript 使用所谓的原型继承来实现特征的继承。考虑以下示例:
Superclass = function() {
//constructor code
}
Superclass.prototype.toString=function() {
return "Derp!";
}
Superclass.derp= function(){return 'herp!'}
var instance = new Superclass();
instance.toString();//valid
instance.derp();//fails
这里发生了几件事。首先,在担心定义对象的方法之前,先考虑对象的创建。
因此,有几种创建对象的方法。首先,您可以突然创建一个内联对象:
var obj = { property : "myProperty", func : function () {} };
您现在有了一个全新的对象。事后,您可以通过添加该对象来扩展该对象。
obj.property02 = "myOtherProperty";
obj.otherFunc = function () { return this.property02; };
但是构造内联对象的缺点是所有的属性和方法都是 100% 公开的。
为了解决这个问题,您可以使用一个构造函数来创建并返回一个对象。
var MakeWallet = function (starting_amount, pin) {
var balance = 0,
wallet = {};
wallet.add = add_balance;
wallet.deduct = deduct_amount;
wallet.amount = check_balance;
return wallet;
function check_balance (pin) { /*...*/ }
function validate_pin (user_pin) { /*...*/ }
function add_balance (amount, pin) { /*...*/ }
function deduct_amount (amount, pin) { /*...*/ }
};
var myWallet = MakeWallet(1, 9274);
我得到什么来解决我的麻烦?所有数据都是防篡改的。
用户可能仍然可以重写wallet.deduct
,但他们实际上不会获得 pin 的实际价值,或获得钱包中的金额,或获得我不希望他们拥有的任何内部功能,包括任何我想授予的内部安全号码或实体/序列号来跟踪钱包。
这就是以这种方式构建的好处。
同样,我可以在钱包中添加方法和属性,之后:
myWallet.breakItOpen = function () { return this.balance; };
myWallet.stuffIt = function () { balance = 400000000; };
但是这些东西实际上都不能访问原始 myWallet 中的变量或函数。
只有在创建时存在的功能才能访问。
在其他更传统的创建方法中,您可以使用类似类的构造函数,使用this
.
function MakeWalletClass (starting_amount, pin) {
var balance = 0,
serial_and_pin = generate_serial() + "_" + pin;
this.balance = balance;
this.checkBalance = function () { return this.balance; };
}
var myWalletInstance = new MakeWalletClass(1, 1234);
但是有一个问题:
myWalletInstance.balance
是公开的。
任何人都可以看到或更改它。
不好。
我们可以通过这样做来解决这个问题:
function MakeWalletClass (starting_amount, pin) {
var balance = 0,
serial_and_pin = generate_serial() + "_" + pin;
this.checkBalance = function () { return balance; };
}
var myWalletInstance = new MakeWalletClass(1, 1234);
现在,this.checkBalance
正在读取隐藏balance
变量,而不是公开可编辑的属性。
现在,MakeWalletClass.prototype
.
当您使用构造函数模式时(即:添加属性this
并返回的函数this
,或者不返回任何内容 - 它this
在后台返回 - 并使用new
关键字调用),添加prototype
属性和方法将添加属性和方法它们可用于您创建的对象的每个实例。
因此,如果您的银行被称为“鲍勃银行”,您可以添加:
MakeWalletClass.prototype.bankName = "The Bank of Bob";
现在每个实例new MakeWalletClass();
都有一个bankName
属性,每个实例都将是完全相同的值,并且每个实例都将是公开可用的。
var yourWalletInstance = new MakeWalletClass(500, 2341);
yourWalletInstance.bankName; // "The Bank of Bob";
在将属性添加到构造函数的原型之前,这些prototype
属性甚至可以在您创建的对象上使用。
您可以prototype
以相同的方式添加方法。
var myWalletInstance = new MakeWalletClass(1, 1234);
MakeWalletClass.prototype.getBalance = function () { return balance; };
myWalletInstance.getBalance(); // undefined;
哎呀!
它不起作用。
原型函数只能访问公共属性(它们可以调用的任何东西this.XXX
)。
所以添加prototype
属性的好处是可以节省大量内存。如果您的程序需要 3000 个钱包,并且您将 a 添加prototype function
到构造函数中,则该函数仅在内存中存在 1 次。
添加原型的缺点是它只能做公共的事情,所以除非你想平衡或固定公共属性(提示:不要),原型对私人工作毫无用处。
因此,对于这 3000 个钱包,您需要 3000 个处理余额或密码的任何方法的副本。
既然您已经了解了所有这些,以及它们prototype
的用途......之间的真正区别:
MakeWalletClass.prototype.say_bankName = function () { /*...*/ };
和
MakeWalletClass.say_bankName = function () { /*...*/ };
是prototype
适用于实例 ( wallet = new MakeWalletClass
),而 的方法MakeWalletClass
不适用——它仅在您希望将函数附加到MakeWalletClass
.
也许你想要一个返回钱包数量的函数......