Javascript 创建自定义JS方法的正确方法
只是一个小的原型继承问题Javascript 创建自定义JS方法的正确方法,javascript,oop,object,methods,prototype,Javascript,Oop,Object,Methods,Prototype,只是一个小的原型继承问题 最近我尝试创建一个自定义方法,例如:JS的.toUpperCase()和其他方法。。。使用前缀对象的此引用的 而且效果很好(愚蠢的usless示例): 并且可以像这样使用: // access some object and get a key value member.name; // JOHN // use custom Method member.name.customMethod(); // john 问题在于,方法.customMethod()似乎全局继承了
最近我尝试创建一个自定义方法,例如:JS的
.toUpperCase()
和其他方法。。。使用前缀对象的此
引用的
而且效果很好(愚蠢的usless示例):
并且可以像这样使用:
// access some object and get a key value
member.name; // JOHN
// use custom Method
member.name.customMethod(); // john
问题在于,方法.customMethod()
似乎全局继承了每个对象
如何使其侵入性降低,并仅引用前缀对象?或者根本就没有?
下面是一个例子:
// 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上也读到了这篇文章和许多其他类似的文章,但其中大部分都集中在创建使用特定参数的新F(参数)
的使用上,这不是我的情况。感谢您的解释您也应该使用新的F()。您只需要定义F。尽管如此,还是让我们调用F‘Name’,这样更容易识别
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!
您不必将方法添加到每个对象——只需添加您正在使用的对象类型。如果它是字符串方法,则可以将其添加到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
循环中
Object.defineProperty
如果您从2010年起就只关心支持浏览器(没有IE8),那么我强烈建议使用来定义属性,这样它们就不会是可枚举的:
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”等也不会出现。这是因为它们也被定义为不可枚举
通过这种方式,其他脚本将被允许在
中自由地为..使用,并且一切都应按预期工作
返回到特定的内置程序
我们可以使用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
调用包含上的参数
可以在上面工作,尽管参数
不是真正的数组
简化样板
使用Object.defineProperty
提供了很多功能,但它也需要很多额外的代码,而大多数人不希望一直键入这些代码。ECMAScript委员会在定义函数时就理解了这一点,但他们认为人们可以编写帮助函数,使代码更简洁。记住这一点。例如,您始终可以执行以下操作:
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);
}
})();
然后你可以做:
define(String, 'addText', function() {
return this + ' there!';
});
console.log('Hi'.addText()); // => "Hi there!"
甚至有一些小型的图书馆已经被开发出来来帮助这些东西。以退房为例
小心
这里唯一值得注意的是,如果您将自己的方法添加到内置程序中,可能会与(a)未来版本的JavaScript或(b)其他脚本发生名称冲突。(名称冲突问题将在下一版本的JavaScript中用符号解决)许多人会认为这是一个足够大的问题,你不应该修改内置程序,而应该坚持只修改你“拥有”的东西——你用自己的构造函数创建的东西。在某些(或许多)情况下,我倾向于同意,但我认为对于您个人的使用和学习来说,使用内置原型是一件非常有帮助和有趣的事情
查看这篇关于权衡修改内置部分成本的文章,了解可能存在的缺点的更详细描述:请注意,这篇文章有点过时(1 1/2年),他的主要抱怨之一是可枚举性问题,这在所有现代浏览器中都可以通过Object.defineProperty
克服。正如我所说,另一个主要问题(名称冲突)将在下一个版本的JavaScript中解决。情况正在好转 对不起jQuery标签,它只是为了吸引更多的大师:)玩火篡改对象。如果将来添加了与您的属性冲突的新属性,该怎么办?您将使用构造函数模式。您提到的不是您的案例的new F()
实际上就是您的确切用例。它创建一个新的实例化对象,该对象继承了F
的原型。为了在ES5兼容的浏览器上简单起见,您也可以使用Object.create
@charlietfl我知道这一点,但我无法理解Fabricio说了些什么,如何做到这一点。@Fabricio Matté我对这件事很迷茫,我知道你说的话会带来成功,但是我无法为我使用的每一个对象创建一个不调用addText
的工作示例谢谢,好吧,假设您有一个类似member.name
的对象。如何使用您的示例,例如:member.name.text()
您必须创建一个包含name对象的成员对象。我更新了示例以显示this@Ginnaniname
是一个文本字符串吗?在不影响字符串原型的情况下,给它分配一个方法是不容易的。不过,您可以将其作为参数传递给泛型方法。@Ginnani我再次更新了我的示例,以使用customMethod()对名称进行操作。@Ginnani我已将其删除,它根本没有回答您的问题。考虑发布另一个更直接的答案,但我今天有点慢,目前的答案基本上说明了一切。内森的回答是肯定的
define(String, 'addText', function() {
return this + ' there!';
});
console.log('Hi'.addText()); // => "Hi there!"