Javascript继承最佳策略
Javascript Inheritance Best Strategy
目前我们已经构建了自己的Javascript框架,用于为我们复杂的web应用程序构建小部件、div、面板和表单。我们所有的小部件(又名。组件)继承自一个名为Viewable的超对象,它主要定义了一个视图,该视图是 htmlelement 。
Viewable = {
getView: function() {
if (!this.view)
this.view = this.createView();
return this.view;
}
createView: function() {
alert(‘You have not implemented createView. You are a very naughty boy!);
}
}
然后使用Object.create(Viewable)来创建我们自己的组件,这些组件都需要实现createView在Viewable中定义。
Header = Object.create(Viewable);
Header.createView = function() {
var div = document.createElement('div');
div.id = 'Header';
}
Header.foobar = function() {
}
我想摆脱这种类型的继承,这种即时创建对象,只是根据我的心情添加方法。
我已经使用$研究了另一种方法。从jQuery中扩展。然后我可以创建我的对象(或者更好地说"定义我的函数"?'定义我的类' ?)function Header() {
$.extend(true, this, Viewable);
this.createView = function() {
var div = document.createElement('div');
div.id = 'Header';
}
this.foobar = function() {
}
}
我想用第二种方法重构我的代码,因为对我来说好处是:
- 你得到一个构造函数
- 有一定程度的封装
- 它类似于Java之类的OO语言(我来自这个世界…)
- 我的IDE (Webstorm)更喜欢这个智能感知和重构。
但是我不确定。有什么缺点吗?我必须重构50多个文件,所以我对这样做有点紧张。我对Javascript还是个新手。
同时,一个快速的子问题。如果我把可视重构成这样:
function Viewable() {
this.getView = function() {
if (!this.view)
this.view = this.createView();
return this.view;
},
createView:function() {
alert(‘You have not implemented createView. You are a very naughty boy!);
}
}
这样会更有益吗?我喜欢它,因为对我来说,它使代码看起来一致。
JavaScript还没有类定义,没有接口。添加方法取决于我的心情是原型继承的工作原理。
使用Object.create
或$.extend
不会改变这个
请记住,$.extend
并没有给你一个继承树。Header instanceof Viewable
是false
,你只是复制在Viewable
上定义的属性。$.extend
类似于修改输入参数的对象合并。
如果instanceof
对你来说不重要,那么你可以使用任何一种方法。
ES6在如何在JavaScript中获得类定义方面有一些很好的新想法。ES6还没有实现,但是如果你想要一个可行的预览,你可以看看微软的TypeScript。TypeScript与ES6并不是100%兼容,但它在重要的地方是兼容的。
TypeScript添加了类和接口等等。这为您提供了所需的类型提示,但在编译回JavaScript时将被删除。实现类类型代码结构至少有两种不同且有用的策略。一个是原型继承,另一个是工厂风格继承。
原型继承
JavaScript的原型继承是经典而有效的。
// A viewable device.
function Device() {
var _element = null,
_type = 'div';
// Get or set the element type.
this.type = function type(type_) {
if (!arguments.length)
return _type;
_type = type_;
return this;
};
// Lazy creation of the element, or set it explicitly.
this.element = function element(element_) {
if (!arguments.length)
return _element || (_element = $('<' + _type + '>').get(0));
_element = element_;
return this;
};
// Allow constructor chaining on subclasses.
return this;
}
Device.prototype = Object.create(null);
Device.prototype.constructor = Device;
// Get/set. Hide or show this device.
Device.prototype.visible = function visible(show) {
if (!arguments.length)
return $(this.element()).css('display') !== 'none';
$(this.element()).css('display', show ? '' : 'none');
return this;
};
// Add or remove a css class, or check for its presence.
Device.prototype.classed = function classed(css_class, classed_) {
if(arguments.length === 1)
return $(this.element()).hasClass(css_class);
if (classed_)
$(this.element()).addClass(css_class);
else
$(this.element()).removeClass(css_class);
return this;
};
虽然Device
是一个基类,但它可以像这样实例化和配置:
// Create a list item device.
var ul = new Device()
.type('ul')
.classed('list-items', true)
.visible(false);
// Check for the class.
ul.classed('list-items'); // => true
// Is the device visible?
ul.visible() // => false
// Show the device.
ul.visible(true);
ul.visible(); // => true
使list-items
设备成为子类:
function ListItems() {
Device.call(this)
.classed('list-items', true)
.visible(false);
return this;
}
ListItems.prototype = Object.create(Device.prototype);
ListItems.prototype.constructor = ListItems;
ListItems.prototype.addItem = function addItem(content, css_class) {
$(this.element()).append($('<li>')
.addClass(css_class || 'list-item')
.html(content));
return this;
};
实例化子类:
var ul = new ListItems()
.addItem('Item 1')
.addItem('Item 2')
.addItem('Item 3')
.visible(true);
ul.element();
/*
<ul class="list-items">
<li class="list-item">Item 1</li>
<li class="list-item">Item 2</li>
<li class="list-item">Item 3</li>
</ul>
*/
工厂继承
工厂继承是优雅的,避免了new
关键字的麻烦。
function device() {
var self = {},
_type = 'div',
_element = null;
self.type = function type(type_) {
if (!arguments.length)
return _type;
_type = type_;
return this;
};
self.element = function element(element_) {
if (!arguments.length)
return _element || (_element = $('<' + _type + '>').get(0));
_element = element_;
return this;
};
self.visible = function visible(show) {
if (!arguments.length)
return $(this.element()).css('display') !== 'none';
$(this.element()).css('display', show ? '' : 'none');
return this;
};
self.classed = function classed(css_class, classed_) {
if(arguments.length === 1)
return $(this.element()).hasClass(css_class);
if (classed_)
$(this.element()).addClass(css_class);
else
$(this.element()).removeClass(css_class);
return this;
};
return self;
}
实例化一个设备:
var ul = device()
.type('ul')
.classed('list-items', true)
.visible(false);
从device继承:
function listItems() {
var _super = device()
.type('ul')
.classed('list-items', true)
.visible(false),
self = Object.create(_super);
self.addItem = function addItem(content, css_class) {
$(this.element()).append($('<li>')
.addClass(css_class || 'list-item')
.html(content);
return this;
};
return self;
}
实例化listtitem:
var ul = listItems()
.addItem('Item 1')
.addItem('Item 2')
.addItem('Item 3')
.visible(true);
ul.element();
/*
<ul class="list-items">
<li class="list-item">Item 1</li>
<li class="list-item">Item 2</li>
<li class="list-item">Item 3</li>
</ul>
*/
使用哪种模式在很大程度上是一个偏好问题,尽管原型继承类在调试器中具有不同的标识,因此可能更适合调试和分析情况。
原型继承也适用于instanceof
,所以这是另一个需要考虑的问题。一个instanceOf
类型的机制可以通过一些努力添加到工厂继承中。
我在一个基于java脚本的项目中也有类似的需求。它是Java实现的JS移植,其中一个要求是代码结构和逻辑应该与Java一样相似。这是我想出来的。
免责声明:我对Java Script有点陌生。下面的解决方案是基于就我目前对语言的理解,我希望是这样在公认的指导方针和最佳实践范围内。
下面的代码演示了如何在JS中模仿Java中的"extends"关键字。
Function.prototype.extends = function (parent) {
var child = this;
child.prototype.inherit = function () {
var parentProto = parent;
var childProto = child;
var parentObj = new parentProto();
childProto.prototype = parentObj;
childProto.prototype.$super = parentObj;
var newObj;
if(child.arguments.length >0) newObj = new childProto(child.arguments[0]);
else newObj = new childProto();
/*Restore the inherit function back in type prototype so that subsequent
creation of unique objects are possible*/
if(typeof this == "function") childProto.prototype.inherit = this;
return newObj;
};
} ;
下面是剩下的代码。
//Class A
var A = function(){
//some field
//some methods
}
//Class B
var B = function(){
//Check if inheritance needed
if(this.inherit){
var newInst = this.inherit.call(this.inherit);
return newInst;
}
//rest of class B specific code
}
//Here goes the inheritance statement like "Class B extends A"
B.extends(A);
到目前为止,这对我来说是有效的,只用于1级继承。
- 在localhost Dev Box上测试JSONP请求的最佳方式
- 有条件更新d3.js力图中节点的最佳方法
- 为react组件传递道具的最佳方式
- 与运行长作业(javascript,node.js)的第三方API同步的最佳实践
- 让Webpack管理Quirky AMD定义的最佳方式
- 在承诺链中处理早期回报的最佳方式
- 将jQuery.ech()方法转换为本地JavaScript抽象的最佳方法是什么
- Angularjs 1.5.x本地化最佳实践
- 处理浮点错误的最佳方法是什么
- 内容安全策略:页面's设置阻止加载资源
- javascript导入的最佳实践是什么
- 什么'这是在设计一个与MS Excel中所能做的基本相同的系统时采用的最佳策略
- 上传多个文件的最佳策略
- XLS内容从云端同步到iOS或Android应用内存的最佳策略
- 在特定子节点周围加载相邻子节点的最佳策略是什么?最好是使用一个查询
- Javascript继承最佳策略
- 什么'Angular.js和chrome应用程序的最佳缓存策略
- 使用 ajax 发送复杂数据的最佳策略是什么
- 使用AJAX发送数组的最佳策略
- Javascript策略/最佳实践