如何最好地继承本机JavaScript对象? (特别是字符串) [英] How best to inherit from native JavaScript object? (Especially String)

查看:66
本文介绍了如何最好地继承本机JavaScript对象? (特别是字符串)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是一个长期浏览器,但是第一次参与。如果我遗漏任何礼仪细节,请告诉我!

I'm a long-time browser but a first time participator. If I'm missing any etiquette details, please just let me know!

此外,我搜索了高低,包括这个网站,但我还没有找到清楚简洁地解释我正在做什么。如果我错过了它,请指出我正确的方向!

Also, I've searched high and low, including this site, but I haven't found a clear and succinct explanation of exactly what I'm looking to do. If I just missed it, please point me in the right direction!

好吧,我想扩展一些原生的JavaScript对象,比如Array和String。但是,我不想实际扩展它们,而是创建从它们继承的新对象,然后修改它们。

Alright, I want to extend some native JavaScript objects, such as Array and String. However, I do not want to actually extend them, but create new objects that inherit from them, then modify those.

对于Array,这可行:

For Array, this works:

var myArray = function (n){
    this.push(n);

    this.a = function (){
        alert(this[0]);
    };
}

myArray.prototype = Array.prototype;

var x = new myArray("foo");
x.a();

但是,对于String,同样不起作用:

However, for String, the same doesn't work:

var myString = function (n){
    this = n;

    this.a = function (){
        alert(this);
    };
}

myString.prototype = String.prototype;

var x = new myString("foo");
x.a();

我也试过:

myString.prototype = new String();

现在,在尝试研究这个问题时,我发现这确实有效:

Now, in trying to research this, I've found that this does work:

var myString = function (n){
    var s = new String(n);

    s.a = function (){
        alert(this);
    };

    return s;
}

var x = myString("foo");
x.a();

然而,这几乎就像是在欺骗我。比如,我应该使用真正的继承模型,而不是这个快捷方式。

However, this almost feels like 'cheating' to me. Like, I should be using the "real" inheritance model, and not this shortcut.

所以,我的问题:

1)你能否告诉我在继承String方面我做错了什么? (最好带有一个工作示例......)

1) Can you tell me what I'm doing wrong as regards inheriting from String? (Preferably with a working example...)

2)在真实继承示例和快捷方式示例之间,您能说出任何明显的好处或损害吗?一个方式超过另一个?或者也许只是在一个人如何在功能上运作的一些差异? (因为他们看起来最终对我来说......)

2) Between the "real" inheritance example and the "shortcut" example, can you name any clear benefits or detriments to one way over the other? Or perhaps just some differences in how one would operate over the other functionally? (Because they look ultimately the same to me...)

全部谢谢!

编辑:

感谢所有评论/回答的人。我认为@ CMS的信息是最好的,因为:

Thank you to everyone who commented/answered. I think @CMS's information is the best because:

1)他回答了我的String继承问题,指出通过在我自己的字符串对象中部分重新定义String我可以制作这行得通。 (例如,重写toString和toValue)
2)创建一个从Array继承的新对象具有自己的局限性,这些局限不是立即可见的,并且无法解决,即使通过部分重新定义Array也是如此。

1) He answered my String inheritance issue by pointing out that by partially redefining a String in my own string object I could make it work. (e.g. overriding toString and toValue) 2) That creating a new object that inherits from Array has limitations of its own that weren't immediately visible and can't be worked around, even by partially redefining Array.

从上述两件事中,我得出结论,JavaScript的继承性声明仅扩展到您自己创建的对象,并且当涉及到本机对象时,整个模型都会崩溃。 (这可能就是为什么你找到90%的例子是Pet-> Dog或Human-> Student,而不是String-> SuperString)。这可以解释为@ chjj的答案,这些对象实际上是原始值,即使JS中的所有内容似乎都是一个对象,因此应该是100%可继承的。

From the above 2 things, I conclude that JavaScript's claim of inheritablity extends only to objects you create yourself, and that when it comes to native objects the whole model breaks down. (Which is probably why 90% of the examples you find are Pet->Dog or Human->Student, and not String->SuperString). Which could be explained by @chjj's answer that these objects are really meant to be primitive values, even though everything in JS seems to be an object, and should therefore be 100% inheritable.

如果结论完全没有,请纠正我。如果它是准确的,那么我确信除了我自己之外,这对任何人都不是新闻 - 但是再次感谢大家的评论。我想我现在可以做出选择:

If that conclusion is totally off, please correct me. And if it's accurate, then I'm sure this isn't news to anyone but myself - but thank you all again for commenting. I suppose I now have a choice to make:

要么继续寄生继承(我的第二个例子,我现在知道它的名字)并尝试减少其记忆 - 如果可能的话,使用影响,或者像@ davin,@ Jeff或@chjj那样建议使用psudo-redefine或者为自己重新定义这些对象(这似乎是浪费)。

Either go forward with parasitic inheritance (my second example that I now know the name for) and try to reduce its memory-usage impact if possible, or do something like @davin, @Jeff or @chjj suggested and either psudo-redefine or totally redefine these objects for myself (which seems a waste).

@CMS - 将你的信息编译成答案我会选择它。

@CMS - compile your information into an answer and I'll choose it.

推荐答案

这种痛苦简单但有缺陷的方式这样做会是:

The painfully simple but flawed way of doing this would be:

var MyString = function() {};

MyString.prototype = new String();

你所要求的是奇怪的,因为通常在JS中,你不是把它们视为字符串对象,您将它们视为字符串类型,作为原始值。而且,字符串根本不可变。通过指定 .toString 方法,您可以让任何对象 ,就好像它是一个字符串一样:

What you're asking for is strange though because normally in JS, you aren't treating them as string objects, you're treating them as "string" types, as primitive values. Also, strings are not mutable at all. You can have any object act as though it were a string by specifying a .toString method:

var obj = {};
obj.toString = function() {
  return this.value;
};
obj.value = 'hello';

console.log(obj + ' world!');

但显然它没有任何字符串方法。你可以通过几种方式做到继承。其中一个是javascript应该使用的原始方法,以及你和我上面发布的,或者:

But obviously it wouldn't have any string methods. You can do inheritence a few ways. One of them is the "original" method javascript was supposed to use, and which you and I posted above, or:

var MyString = function() {};
var fn = function() {};
fn.prototype = String.prototype;
MyString.prototype = new fn();

这允许在不调用构造函数的情况下添加到原型链。

This allows adding to a prototype chain without invoking a constructor.

ES5的方式是:

MyString.prototype = Object.create(String.prototype, {
  constructor: { value: MyString }
});

非标准但最方便的方式是:

The non-standard, but most convenient way is:

MyString.prototype.__proto__ = String.prototype;

所以,最后,你可以做的是:

So, finally, what you could do is this:

var MyString = function(str) {
  this._value = str;
};

// non-standard, this is just an example
MyString.prototype.__proto__ = String.prototype;

MyString.prototype.toString = function() {
  return this._value;
};

继承的字符串方法可能使用该方法工作,我不是当然。我认为他们可能是因为有一个toString方法。这取决于它们如何在内部由任何特定的JS引擎实现。但他们可能不会。你只需要定义自己的。再一次,你所要求的是非常奇怪的。

The inherited string methods might work using that method, I'm not sure. I think they might because there's a toString method. It depends on how they're implemented internally by whatever particular JS engine. But they might not. You would have to simply define your own. Once again, what you're asking for is very strange.

你也可以尝试直接调用父构造函数:

You could also try invoking the parent constructor directly:

var MyString = function(str) {
  String.call(this, str);
};

MyString.prototype.__proto__ = String.prototype;

但这也略显粗略。

无论你想做什么,这可能都不值得。我打赌有更好的办法可以解决你想要使用它的任何问题。

Whatever you're trying to do with this probably isn't worth it. I'm betting there's a better way of going about whatever you're trying to use this for.

如果你想要一个绝对可靠的方式这样做:

If you want an absolutely reliable way of doing it:

// warning, not backwardly compatible with non-ES5 engines

var MyString = function(str) {
  this._value = str;
};

Object.getOwnPropertyNames(String.prototype).forEach(function(key) {
  var func = String.prototype[key];
  MyString.prototype[key] = function() {
    return func.apply(this._value, arguments);
  };
});

这将讨论 this._value to每个String方法。这将是有趣的,因为你的字符串将是可变的,不像真正的javascript字符串。

That will curry on this._value to every String method. It will be interesting because your string will be mutable, unlike real javascript strings.

你可以这样做:

    return this._value = func.apply(this._value, arguments);

这会增加一个有趣的动态。如果你想让它返回你的一个字符串而不是一个原生字符串:

Which would add an interesting dynamic. If you want it to return one of your strings instead of a native string:

    return new MyString(func.apply(this._value, arguments));

或者只是:

    this._value = func.apply(this._value, arguments);
    return this;

根据你想要的行为,有几种方法可以解决它。

There's a few ways to tackle it depending on the behavior you want.

另外,你的字符串不会有像javascript字符串那样的长度或索引,解决这个问题的方法就是放入构造函数:

Also, your string wont have length or indexes like javascript strings do, a way do solve this would be to put in the constructor:

var MyString = function(str) {
  this._value = str;
  this.length = str.length;
  // very rough to instantiate
  for (var i = 0, l = str.length; i < l; i++) {
    this[i] = str[i];
  }
};

非常hacky。根据实现,您可能只能在那里调用构造函数来添加索引和长度。如果你想使用ES5,你也可以使用一个吸气剂。

Very hacky. Depending on implementation, you might just be able to invoke the constructor there to add indexes and length. You could also use a getter for the length if you want to use ES5.

再一次,你想做什么在任何方面都不理想。这将是缓慢和不必要的。

Once again though, what you want to do here is not ideal by any means. It will be slow and unnecessary.

这篇关于如何最好地继承本机JavaScript对象? (特别是字符串)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆