Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/389.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对象继承?(特别是弦)_Javascript_Inheritance - Fatal编程技术网

如何最好地从本机JavaScript对象继承?(特别是弦)

如何最好地从本机JavaScript对象继承?(特别是弦),javascript,inheritance,Javascript,Inheritance,我是一个长期的浏览器,但第一次参与。如果我遗漏了任何礼仪细节,请告诉我 此外,我到处都在搜索,包括这个网站,但我还没有找到一个清晰简洁的解释,确切地说明我想做什么。如果我错过了,请给我指出正确的方向 好的,我想扩展一些本机JavaScript对象,比如数组和字符串。但是,我不想实际扩展它们,而是创建从它们继承的新对象,然后修改它们 对于阵列,这是有效的: var myArray = function (n){ this.push(n); this.a = function ()

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

此外,我到处都在搜索,包括这个网站,但我还没有找到一个清晰简洁的解释,确切地说明我想做什么。如果我错过了,请给我指出正确的方向

好的,我想扩展一些本机JavaScript对象,比如数组和字符串。但是,我不想实际扩展它们,而是创建从它们继承的新对象,然后修改它们

对于阵列,这是有效的:

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

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

myArray.prototype = Array.prototype;

var x = new myArray("foo");
x.a();
但是,对于字符串,同样的方法不起作用:

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();
现在,在尝试研究这一点时,我发现这确实有效:

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

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

    return s;
}

var x = myString("foo");
x.a();
然而,这对我来说几乎像是“欺骗”。比如,我应该使用“真正的”继承模型,而不是这个快捷方式

所以,我的问题是:

1) 你能告诉我在继承字符串方面我做错了什么吗?(最好有一个工作示例…)

2) 在“真正的”继承示例和“快捷方式”示例之间,您能说出其中一种方法的明显优点或缺点吗?或者可能只是一个在功能上与另一个有所不同?(因为它们在我看来最终都是一样的…)

谢谢大家

编辑:

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

1) 他回答了我的字符串继承问题,指出通过在我自己的字符串对象中部分重新定义字符串,我可以使它工作。(例如,覆盖toString和toValue) 2) 创建从数组继承的新对象有其自身的局限性,这些局限性不是立即可见的,甚至通过部分重新定义数组也无法解决

通过以上两件事,我得出结论,JavaScript的可继承性声明只适用于您自己创建的对象,而当涉及到本机对象时,整个模型就会崩溃。(这可能就是为什么90%的例子是宠物->狗或人类->学生,而不是字符串->超级字符串)。这可以用@chjj的回答来解释,这些对象实际上是原语值,尽管JS中的所有东西似乎都是对象,因此应该是100%可继承的

如果这个结论完全错误,请纠正我。如果它是准确的,那么我相信这对任何人来说都不是新闻,除了我自己——但再次感谢大家的评论。我想我现在有一个选择:

要么继续使用寄生继承(我现在知道它的名称的第二个示例),并尽可能减少其对内存使用的影响,要么像@davin、@Jeff或@chjj建议的那样执行操作,或者psudo为自己重新定义或完全重新定义这些对象(这似乎是一种浪费)


@CMS-将您的信息编译成一个答案,我会选择它。

您不能在构造函数中分配这个

这是一个错误


myarray只是本机数组的别名-对myarray.prototype所做的任何更改都是对Array.prototype的更改。

此行无效:

this = n;
不是有效的左值。也就是说,您不能将此引用的值赋值。曾经它只是不是有效的javascript。如果您执行以下操作,您的示例将起作用:

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

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

myString.prototype = new String; // or String.prototype;

var x = new myString("foo");
x.a();
关于解决方法,您应该意识到,您所做的只是创建一个字符串对象,扩充一个函数属性,然后调用它。没有继承发生


例如,如果在我上面的示例中执行myString的
x instanceof
,它的计算结果为
true
,但在您的示例中它不是,因为函数
myString
不是类型,它只是一个常规函数。

我会考虑创建一个新对象,将本机对象用作支持字段,并手动重新创建本机对象的函数。对于一些非常粗糙、未经测试的示例代码

var myString = {
    _value = ''
    ,substring:_value.substring
    ,indexOf:_value.indexOf
}

现在,我确信这不会像预期的那样起作用。但我认为通过一些调整,它可能类似于从字符串继承的对象。

这样做非常简单但有缺陷的方法是:

var MyString = function() {};

MyString.prototype = new String();
MyString.prototype = Object.create(String.prototype, {
  constructor: { value: MyString }
});
不过,您所要求的是奇怪的,因为通常在JS中,您不会将它们视为字符串对象,而是将它们视为“字符串”类型,视为基本值。而且,字符串是不可变的。通过指定
.toString
方法,可以让任何对象充当字符串:

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

console.log(obj + ' world!');
但是很明显,它没有任何字符串方法。您可以通过几种方式进行继承。其中之一是javascript应该使用的“原始”方法,您和我在上面发布了该方法,或者:

var MyString = function() {};
var fn = function() {};
fn.prototype = String.prototype;
MyString.prototype = new fn();
这允许在不调用构造函数的情况下添加到原型链

ES5的方法是:

var MyString = function() {};

MyString.prototype = new String();
MyString.prototype = Object.create(String.prototype, {
  constructor: { value: MyString }
});
非标准但最方便的方式是:

MyString.prototype.__proto__ = String.prototype;
最后,你能做的是:

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引擎如何在内部实现它们。但他们可能不会。你必须简单地定义你自己的。再一次,你的要求很奇怪

您还可以尝试直接调用父构造函数:

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

MyString.prototype.__proto__ = String.prototype;
但这也有点粗略

不管你想用这个做什么,可能都不值得。我敢打赌,无论你想用它做什么,都有更好的方法

如果您想要一种绝对可靠的方法:

// 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.\u value
。这会很有趣,因为您的字符串是可变的,不像真正的javascript字符串

您可以这样做:

    return this._value = func.apply(this._value, arguments);
这将增加一个有趣的动态。如果希望它返回一个字符串而不是本机字符串:

    return new MyString(func.apply(this._value, arguments));
或者简单地说:

    this._value = func.apply(this._value, arguments);
    return this;
有一个
function ExtendedNumber(value)
{
    if(!(this instanceof arguments.callee)) { return Number(value); }

    var self = new Number(value);

    self.add = function(argument)
    {
        return self + argument;
    };

    return self;
}
var str = "some text";
var proto = Object.getPrototypeOf(str);
proto.replaceAll = function(substring, newstring)
{
    return this.replace(new RegExp(substring, 'g'), newstring);
}

console.log(str.replaceAll('e', 'E')); // somE tExt
function ExtendedString(value)
{
    if(this instanceof arguments.callee) { throw new Error("Calling " + arguments.callee.name + " as a constructor function is not allowed."); }
    if(this.constructor != String) { value = value == undefined || value == null || value.constructor != String ? "" : value; arguments.callee.bind(Object.getPrototypeOf(value))(); return value; }

    this.replaceAll = function(substring, newstring)
    {
        return this.replace(new RegExp(substring, 'g'), newstring);
    }
}

console.log(!!ExtendedString("str").replaceAll); // true