【问题标题】:JavaScript prototypal inheritance: succinct syntax?JavaScript 原型继承:简洁的语法?
【发布时间】:2011-12-21 21:06:28
【问题描述】:

有没有比三个不同的程序操作更简洁的方式来表达这一点?更像对象符号的东西,或者至少都在 Name 函数的主体中?

问题:

function Name(first, last) {
    this.first = first;
    this.last = last;
}

Name.prototype = new String;

Name.prototype.toString = function() {
   return this.last + ', ' + this.first;
};

测试:

console.log(new Name("jimmy", "dean").toString())
console.log(new Name() instanceof Name);
console.log(new Name() instanceof String);
console.log(new Name() instanceof Object);
console.log(Name.prototype.toString.call(new Name('jimmy', 'dean')));
console.log(Name.prototype.toString.call({
    first: 'jimmy',
    last: 'dean'
}));

预期输出:

< "dean, jimmy"
< true
< true
< true
< "dean, jimmy"
< "dean, jimmy"

【问题讨论】:

  • 吹毛求疵;你的意思是partFirst吗?
  • @pimvdb — 有时最好只编辑小错字的问题。
  • 我不明白您为什么希望原型成为 String 的实例。只要 toString 返回一个字符串(这似乎是明智的),那么您可以调用任何将从 String 继承的方法,而无需将字符串分配给构造函数的原型。

标签: javascript inheritance prototypal-inheritance


【解决方案1】:

Example

function Name(first, last) {
    this.partFirst = first;
    this.partLast = last;
    this.valueOf = this.toString = function() {
        return this.partLast + ', ' + this.partFirst;
    }
}
Name.prototype = new String();

【讨论】:

  • 您的方法不再从String 构造函数继承其原型。旁注:必须定义 valueOf 方法,以防止出现以下错误:String.prototype.valueOf called on incompatible Object(FF 8.0,使用 ""+(new Name()) 作为测试用例)。
  • 注意到,但明确调用.toString(),因为 OP 打算正常工作。对Name 的无参数构造函数调用不会是程序员错误吗?更新了上面的链接以显示 (new Name("first", "last") + "")
  • new Namenew Name()new Name(void 0, void 0) 是等效且有效的(顺便说一句,void 0 === undefined。至于报错,是在使用OP的继承概念时出现的:jsfiddle.net/wKvqQ/4
  • @RobW 发现String.toString() 使用valueOf,所以您所要做的就是定义valueOf。再次检查上面的链接。
  • 只要定义这两个方法,如果你喜欢当前的方式:this.valueOf = this.toString = ..,也可以考虑explicit.toString() 调用。但是,设置原型而不是使用this.____ = efficient 和可读性。
【解决方案2】:

我是这样做的:

function subclass(constructor, superConstructor) {
    function surrogateConstructor() { }

    surrogateConstructor.prototype = superConstructor.prototype;

    var prototypeObject = new surrogateConstructor();
    prototypeObject.constructor = constructor;

    constructor.prototype = prototypeObject;
}



/* Base object */
function BaseItem() {
    this.type = 'baseitem';
    this.obj = null;
}
BaseItem.prototype.render = function() {
    return "foo";
}



/* Sub class */
function InteractionArea() {
    BaseItem.call(this);
    this.type = 'interactionarea'
    this.obj = document.createElement('div')
}
subclass(InteractionArea, BaseItem);

//here come the overrides
InteractionArea.prototype.render = function() {
    return "foobar";
}
InteractionArea.prototype.render2 = function() {
    return "foobar";
}



/* Sub-sub class */
function InteractionArea2() {
    InteractionArea.call(this);
    this.type = 'interactionarea2';
    this.obj = false;
}
subclass(InteractionArea2, InteractionArea);

InteractionArea2.prototype.render = function() {
    return "bar";
}

【讨论】:

    【解决方案3】:

    当然。使用Object.create

    var Name = Object.create(String.prototype, {
      toString: { value: function _toString() {
        return this.partLast + ', ' + this.partFirst;
      } },
      constructor: { value: function _constructor(first, last) {
        this.partFirst = first;
        this.partLast = last;
        return this;
      } }
    });
    
    var name = Object.create(Name).constructor("foo", "bar");
    

    现在ES5有点丑,可以用some mechanism for ES5 OO sugar,我们以pd为例:

    var Name = pd.make(String.prototype, {
      toString: function _toString() {
        return this.partLast + ', ' + this.partFirst;
      },
      constructor: function (first, last) {
        this.partFirst = first;
        this.partLast = last;
      },
      beget: pd.Base.beget 
    });
    
    console.log(Name.beget("jimmy", "dean").toString())
    console.log(Name.isPrototypeOf(Name.beget()));
    console.log(String.prototype.isPrototypeOf(Name.beget()));
    console.log(Object.prototype.isPrototypeOf(Name.beget()));
    console.log(Name.toString.call(Name.beget('jimmy', 'dean')));
    console.log(Name.toString.call({
        partFirst: 'jimmy',
        partLast: 'dean'
    }));
    

    当然输出如预期Live Example

    【讨论】:

    • 这比 OP 自己的解决方案更加丑陋和冗长,更不用说需要 polyfill 来解决任何 IE developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
    • @jondavidjohn 它可以在 IE6+ 和所有其他主要浏览器中工作
    • +1 用于发布明显的替代方案。但我同意原来的更优雅(假设字符串到 Name.prototype 的分配被删除)。我从不理解Object.create 的必要性,这是一种克罗克福德主义。
    • @RobG 我宁愿不考虑构造函数。构造函数很丑陋,你所需要的只是一个原型对象。 Object.create 解决方案唯一难看的是实例化和初始化是两步的事情
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-28
    • 2018-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多