javascript - 我如何做 JavaScript 原型(prototype)继承(原型(prototype)链)

标签 javascript inheritance prototype chain

这是 JavaScript 大师的问题。我正在尝试更优雅地使用 JavaScript 原型(prototype)模型。这是我的实用程序代码(它提供了真实的原型(prototype)链并正确使用 instanceof 运算符):

function Class(conf) {
  var init = conf.init || function () {};
  delete conf.init;

  var parent = conf.parent || function () {};
  delete conf.parent;

  var F = function () {};
  F.prototype = parent.prototype;
  var f = new F();
  for (var fn in conf) f[fn] = conf[fn];
  init.prototype = f;

  return init;
};

它允许我做这样的事:

var Class_1 = new Class({
  init: function (msg) { // constructor
    this.msg = msg;
  },

  method_1: function () {
    alert(this.msg + ' in Class_1::method_1');
  },

  method_2: function () {
    alert(this.msg + ' in Class_1::method_2');
  }
});

var Class_2 = new Class({
  parent: Class_1,

  init: function (msg) { // constructor
    this.msg = msg;
  },

  // method_1 will be taken from Class_1

  method_2: function () { // this method will overwrite the original one
    alert(this.msg + ' in Class_2::method_2');
  },

  method_3: function () { // just new method
    alert(this.msg + ' in Class_2::method_3');
  }
});

var c1 = new Class_1('msg');
c1.method_1(); // msg in Class_1::method_1
c1.method_2(); // msg in Class_1::method_2

var c2 = new Class_2('msg');
c2.method_1(); // msg in Class_1::method_1
c2.method_2(); // msg in Class_2::method_2
c2.method_3(); // msg in Class_2::method_3

alert('c1 < Class_1 - ' + (c1 instanceof Class_1 ? 'true' : 'false')); // true
alert('c1 < Class_2 - ' + (c1 instanceof Class_2 ? 'true' : 'false')); // false

alert('c2 < Class_1 - ' + (c2 instanceof Class_1 ? 'true' : 'false')); // true
alert('c2 < Class_2 - ' + (c2 instanceof Class_2 ? 'true' : 'false')); // true

我的问题是:有没有更简单的方法来做到这一点?

最佳答案

是的,有更好的方法来做到这一点。

var call = Function.prototype.call;

var classes = createStorage(),
    namespaces = createStorage(),
    instances = createStorage(createStorage);


function createStorage(creator){
  var storage = new WeakMap;
  creator = typeof creator === 'function' ? creator : Object.create.bind(null, null, {});
  return function store(o, v){
    if (v) {
      storage.set(o, v);
    } else {
      v = storage.get(o);
      if (!v) {
        storage.set(o, v = creator(o));
      }
    }
    return v;
  };
}

function Type(){
  var self = function(){}
  self.__proto__ = Type.prototype;
  return self;
}

Type.prototype = Object.create(Function, {
  constructor: { value: Type,
                 writable: true,
                 configurable: true },
  subclass: { value: function subclass(scope){ return new Class(this, scope) },
              configurable: true,
              writable: true }
});

function Class(Super, scope){
  if (!scope) {
    scope = Super;
    Super = new Type;
  }

  if (typeof Super !== 'function') {
    throw new TypeError('Superconstructor must be a function');
  } else if (typeof scope !== 'function') {
    throw new TypeError('A scope function was not provided');
  }

  this.super = Super;
  this.scope = scope;

  return this.instantiate();
}

Class.unwrap = function unwrap(Ctor){
  return classes(Ctor);
};

Class.prototype.instantiate = function instantiate(){
  function super_(){
    var name = super_.caller === Ctor ? 'constructor' : super_.caller.name;
    var method = Super.prototype[name];

    if (typeof method !== 'function') {
      throw new Error('Attempted to call non-existent supermethod');
    }

    return call.apply(method, arguments);
  }

  var Super = this.super,
      namespace = namespaces(Super),
      private = instances(namespace)

  var Ctor = this.scope.call(namespace, private, super_);
  Ctor.__proto__ = Super;
  Ctor.prototype.__proto__ = Super.prototype;
  namespaces(Ctor, namespace);
  classes(Ctor, this);
  return Ctor;
}

示例用法:

var Primary = new Class(function(_, super_){
  var namespace = this;
  namespace.instances = 0;

  function Primary(name, secret){
    this.name = name;
    _(this).secret = secret;
    namespace.instances++;
  }

  Primary.prototype.logSecret = function logSecret(label){
    label = label || 'secret';
    console.log(label + ': ' + _(this).secret);
  }

  return Primary;
});


var Derived = Primary.subclass(function(_, super_){

  function Derived(name, secret, size){
    super_(this, name, secret);
    this.size = size;
  }

  Derived.prototype.logSecret = function logSecret(){
    super_(this, 'derived secret');
  }

  Derived.prototype.exposeSecret = function exposeSecret(){
    return _(this).secret;
  }

  return Derived;
});

var Bob = new Derived('Bob', 'is dumb', 20);
Bob.logSecret();
console.log(Bob);
console.log(Bob.exposeSecret());

关于javascript - 我如何做 JavaScript 原型(prototype)继承(原型(prototype)链),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11770992/

相关文章:

javascript - 分配现有或空对象

javascript - 使用 javascript 添加总数

python - 运行子方法而不是父方法?

python - 在继承类中执行父方法

html - 将 CSS 类应用于文本

javascript - 在 JavaScript 中重写数组字面量

javascript - 在文本区域中输入时禁用 javascript 功能

javascript - 无法使用jquery获取表单中选择字段的值

javascript - 使 Bootstrap Dropdown 在 Magento 中工作/使用原型(prototype)

javascript - jQuery + 扩展 Object.prototype = "c.replace is not a function"