在JavaScript中继承,我做得对吗?

Jef*_*eff 3 javascript inheritance prototypal-inheritance

我有一个BaseService,可以轻松地与我的服务器端API进行交互,并且我希望将其"子类化"以获取特定的API资源.还有什么比直接从BaseService继承更好的方法呢?

所以,我已经设置了它,并且它可以工作,但是我并不完全确定我正在以正确的方式进行,因为我已经读过JS中存在多种类型的继承.这是我发现的一些代码的链接,它以不同的方式:https://github.com/roblevintennis/Testing-and-Debugging-JavaScript/blob/master/code/objects/lib/js_inheritance.js

这就是我这样做的方式.为简洁起见,我已经离开了功能体.

BaseService,我的实现将继承.

BaseService.prototype.get = function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
};

BaseService.prototype.post = function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
};

BaseService.prototype.put = function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
};

BaseService.prototype.destroy = function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
};

function BaseService(resource) {
    this.apiEndpoint = "/api/" + resource + "/";
}
Run Code Online (Sandbox Code Playgroud)

这是一个可以直接使用的实现BaseService,将API资源传递给构造函数.

AccountService.prototype = new BaseService("Accounts");
AccountService.prototype.getAll = function(searchString) {
    // Uses the BaseService method. Lovely!
    return this.get(null, {
        searchString: searchString || ""
    });
};

function AccountService() {

}
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是(并且希望它不会因为过于本地化而关闭):这是在JavaScript中进行继承的好方法吗?它是否有任何可以大幅改善的性能影响?

顺便说一句:如果我想直接覆盖基类中的方法,例如.get,是否可以这样做,同时仍然能够调用基类的实现?

PS:我知道技术上没有JavaScript中的类,但请耐心等待.

Eri*_*ott 6

虽然你很有可能按照你所写的和打算的方式去做,但是有很多理由可以避免经典继承(参见Classical Vs原型继承),并且有很多理由支持组合.让我们来看看原型继承可能带来什么:

var base = {
  get: function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
  },

  post: function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
  },

  put: function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
  },

  destroy: function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
  }
};

// Use a factory to instantiate instances:
function baseService(resource) {
  var instance = Object.create(base);
  instance.apiEndpoint = "/api/" + resource + "/";
  return instance;
}

var withAccount = {
  getAll: function(searchString) {
    // Uses the BaseService method. Lovely!
    return this.get(null, {
        searchString: searchString || ""
    });
  }
};

function accountService(resource) {
  var instance = mixIn({}, base, withAccount);
  instance.apiEndpoint = "/api/" + resource + "/";
  return instance;
}
Run Code Online (Sandbox Code Playgroud)

这样做可以在未来实现更大的灵活性.如果您使用Stampit库,它会变得更加容易:

var base = stampit().methods({
  get: function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
  },

  post: function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
  },

  put: function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
  },

  destroy: function (resource, data, parameterOverrides) {
    return aPromisedLandOfDragons();
  }
}).enclose(function () {
  this.apiEndpoint = '/api/' + this.resource + '/';
  delete this.resource;
});

var withAccount = stampit().methods({
  getAll: function(searchString) {
    // Uses the BaseService method. Lovely!
    return this.get(null, {
        searchString: searchString || ""
    });
  }
});

var accountService = stampit.compose(base, withAccount);

// Watch it work:

var myAccountService = accountService({resource: 'foo'});
// { apiEndpoint: '/api/foo/' }
Run Code Online (Sandbox Code Playgroud)

  • 如果你想模仿C#继承,你就是在正确的轨道上,虽然它可能没有你想象的那样(毕竟它仍然是原型).请注意,当您偏爱合成和委托而不是类继承时,您会错过免费获得的额外灵活性,表现力和力量.BTW,super是一种代码气味:http://en.wikipedia.org/wiki/Call_super (2认同)