只是一个小型的原型继承问题
最近我试图创建一个自定义方法jut,例如:JS的.toUpperCase()
和其他方法......使用前缀对象的this
引用。
它很好用(愚蠢无用的例子):
Object.prototype.customMethod = function(){
return this.toLowerCase() ;
};
可以像:
一样使用// access some object and get a key value
member.name; // JOHN
// use custom Method
member.name.customMethod(); // john
问题是,似乎方法.customMethod()
在每个Object
全局继承。
如何减少干扰并仅引用前缀对象?还是根本?
以下是一个示例: http://jsbin.com/evaneg/2/edit
// CREATE OBJECT
var obj = { "text" : "Hi" };
// TEST OBJECT KEY VALUE
alert( "OBJECT TEXT: "+ obj.text ); // Hi
// CREATE CUSTOM METHOD ( just like e.g. JS's .toUpperCase() method )
Object.prototype.addText = function(){
return this+' there!';
};
// USE CUSTOM .addText() METHOD
alert( "OBJECT TEXT+method: "+obj.text.addText() ); // Hi there! // wow, the method works!
for(var key in obj){
alert( 'obj KEYS: '+ key ); // text // addText
}
// hmm... addText method as obj Key ???
// ok let's try with a new one...
var foobee = { "foo" : "bee" };
for(var key in foobee){
alert( 'foobee KEYS: '+ key ); // foo // addText
}
// addText ...again... but why?
我在SOverflow上也阅读了这个http://javascript.crockford.com/prototypal.html和许多其他类似的东西,但是大多数都专注于使用创建使用特定参数的new F( arguments )
,这不是我的情况。谢谢你的任何解释
答案 0 :(得分:3)
您不必将方法添加到每个对象 - 只是您正在使用的对象类型。如果是字符串方法,您可以将其添加到String.prototype
并在所有字符串上定义。
var obj = { "text" : "Hi" };
// We only want to add this method to strings.
String.prototype.addText = function(){
return this+' there!';
};
alert("OBJECT TEXT+method: " + obj.text.addText());
请注意,这确实会使方法可枚举,这意味着它们会显示在for..in
循环中。
如果您自2010年以来只关心支持浏览器(没有IE8),那么我强烈建议您使用Object.defineProperty
来定义属性,以便它们不会被枚举:
var obj = { foo: 'bar' };
// Extending all objects this way is likely to break other scripts...
Object.prototype.methodA = function() { return 'A'; };
// Instead you can do extensions this way...
Object.defineProperty(Object.prototype, 'methodB', {
value: function() { return 'B'; },
// Prevent the method from showing up in for..in
enumerable: false,
// Allow overwriting this method.
writable: true,
// Allow reconfiguring this method.
configurable: true
});
for (var propertyName in obj) {
console.log(propertyName);
// Logs: "foo" and "methodA" but not "methodB"
}
上面的代码记录了“foo”属性和“methodA”属性,但它没有记录“methodB”属性,因为我们将其定义为不可枚举。您还会注意到诸如“toString”,“valueOf”,“hasOwnProperty”等内置方法也不会出现。这是因为它们也被定义为不可枚举。
这样,其他脚本将被允许自由使用for..in
,一切都应该按预期工作。
我们也可以使用Object.defineProperty
在特定类型的对象上定义非可枚举方法。例如,以下内容向所有数组添加contains
方法,如果数组包含值,则返回true
,如果不包含false
,则返回Object.defineProperty(Array.prototype, 'contains', {
value: (function() {
// We want to store the `indexOf` method so that we can call
// it as a function. This is called uncurrying `this`.
// It's useful for ensuring integrity, but I'm mainly using
// it here so that we can also call it on objects which aren't
// true Arrays.
var indexOf = Function.prototype.call.bind(Array.prototype.indexOf);
return function(value) {
if (this == null)
throw new TypeError('Cannot be called on null or undefined.');
return !!~indexOf(this, value);
}
})(),
enumerable: false,
writable: true,
configurable: true
});
var colors = [ 'red', 'green', 'blue', 'orange' ];
console.log(colors.contains('green')); // => true
console.log(colors.contains('purple')); // => false
:
Array.prototype
请注意,由于我们在function foo() {
Array.prototype.contains.call(arguments, 5);
}
console.log(foo(1, 2, 3, 4, 5)); // => true
console.log(foo(6, 7, 8, 9, 10)); // => false
上定义了此方法,因此它仅适用于数组。它不适用于其他对象。但是,根据其他数组方法的精神,它的编写具有足够的通用性,可以在类似数组的对象上调用它:
contains
在arguments
上拨打arguments
时,Object.defineProperty
不是真正的数组。
使用var define = (function() {
// Let's inherit from null so that we can protect against weird situations
// like Object.prototype.get = function() { };
// See: https://mail.mozilla.org/pipermail/es-discuss/2012-November/026705.html
var desc = Object.create(null);
desc.enumerable = false;
desc.writable = true;
desc.configurable = true;
return function define(constructor, name, value) {
if (typeof constructor != 'function'
|| !('prototype' in constructor))
throw new TypeError('Constructor expected.');
desc.value = value;
Object.defineProperty(constructor.prototype, name, desc);
}
})();
提供了很多功能,但它还需要大量额外的代码,大多数人不愿意一直输入。当ECMAScript委员会定义了这个函数时就明白了,但是他们假设人们可以编写帮助函数来使代码更清晰。记住这一点。例如,您可以始终执行以下操作:
define(String, 'addText', function() {
return this + ' there!';
});
console.log('Hi'.addText()); // => "Hi there!"
然后你可以这样做:
Object.defineProperty
甚至还开发了一些小型库来帮助解决这些问题。以Andrea Giammarchi's redefine.js为例。
唯一真正的警告是,如果您将自己的方法添加到内置插件中,则可能会与(a)未来版本的JavaScript或(b)其他脚本发生名称冲突。 (名称冲突问题正在使用符号的JavaScript的下一个版本中得到解决。)许多人认为这是一个足够大的问题,你不应该修改内置函数但应该坚持使用只修改你“拥有”的东西 - 你用你自己的构造函数创建的东西。我倾向于在某些(或许多)情况下达成一致,但我认为,对于您自己的个人使用和学习,使用内置原型可能是一件非常有帮助且有趣的事情。
查看这篇关于权衡修改内置插件的一些成本的文章,以便更详细地描述可能存在的缺陷:http://perfectionkills.com/extending-built-in-native-objects-evil-or-not/请注意,这篇文章有点过时(1年半),其中一个他的主要抱怨是可枚举性事项,在所有现代浏览器中都可以用{{1}}来克服。正如我所说,其他主要问题(名称冲突)将在下一版本的JavaScript中得到解决。情况正在好转!
答案 1 :(得分:0)
你也应该使用新的F()。你只需要定义F.让我们调用F'名称',但它更容易识别。
var Name = function(){
var newName = {
text: 'Hello',
customMethod: function(){
this.text = this.text.toUpperCase();
}
}
return newName;
}
var Member = function(){
var newMember = {
name = new Name(),
customMethod: function(){
this.name.customMethod(); // make a member invoke upperCase on name (or any number of vars)
}
}
return newMember;
}
var member = new Member(); //now when you run new Member, it runs the function above. and automatically makes your object with it's properties and methods.
console.log(member.name.text); //Hello!
member.customMethod();
// or
member.name.customMethod();
console.log(member.name.text); //HELLO!