Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 创建自定义JS方法的正确方法_Javascript_Oop_Object_Methods_Prototype - Fatal编程技术网

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@Ginnani
name
是一个文本字符串吗?在不影响字符串原型的情况下,给它分配一个方法是不容易的。不过,您可以将其作为参数传递给泛型方法。@Ginnani我再次更新了我的示例,以使用customMethod()对名称进行操作。@Ginnani我已将其删除,它根本没有回答您的问题。考虑发布另一个更直接的答案,但我今天有点慢,目前的答案基本上说明了一切。内森的回答是肯定的
define(String, 'addText', function() {
    return this + ' there!';
});

console.log('Hi'.addText()); // => "Hi there!"