目前,我们已经构建了自己的Javascript框架,用于为复杂的Web应用程序构建窗口小部件,div,面板和表单。我们所有的小部件(也称为组件)都继承自名为可查看的超级对象,该对象主要定义一个 HTMLElememnt 的视图。
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 。
Header = Object.create(Viewable);
Header.createView = function() {
var div = document.createElement('div');
div.id = 'Header';
}
Header.foobar = function() {
}
我想摆脱这种类型的继承,即动态创建对象,并根据我的心情添加方法。
我已经从jQuery使用 $ .extended 查看了另一种方法。然后我可以创建我的对象(或者更好地说'定义我的函数'?'定义我的类'?)
function Header() {
$.extend(true, this, Viewable);
this.createView = function() {
var div = document.createElement('div');
div.id = 'Header';
}
this.foobar = function() {
}
}
我想将我的代码重构为第二种方法,因为对我而言,好处是:
但我不确定。有什么缺点吗?我将不得不重构50多个文件,所以我有点担心这样做。我仍然是Javascript的新手。
同样在我们处理它时,一个快速的子问题。如果我将 Viewable 重构为如下所示:
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!);
}
}
这会更有益吗?我喜欢它,因为对我来说它使代码看起来一致。
答案 0 :(得分:1)
JavaScript没有类定义(还没有),没有接口。 根据我的心情添加方法是原型继承的工作原理。
使用Object.create
或$.extend
不会改变这种情况。
请记住,$.extend
不会为您提供继承树。 Header instanceof Viewable
为false
,您只是复制Viewable
上定义的属性。 $.extend
就像一个修改输入参数的对象合并。
如果instanceof
对您不重要,那么您可以使用其中任何一种方法。
ES6对如何在JavaScript中获取类定义有一些很好的新想法。 ES6尚未实现,但如果您想要可行的预览,可以查看Microsoft's TypeScript。 TypeScript与ES6不是100%兼容,但在重要的地方它是兼容的。
TypeScript添加了类和接口以及所有爵士乐。这为您提供了所需的类型提示,但在编译回JavaScript时会被删除。
答案 1 :(得分:1)
至少两种截然不同且有用的策略用于实现类型代码结构。一个是典型的,另一个是工厂式的继承。
原型继承
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);
从设备继承:
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;
}
实例化listItems:
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
- 类型机制添加到工厂继承中。
答案 2 :(得分:1)
我在一个基于java脚本的项目中有类似的需求。它是Java实现的JS端口,一个要求是代码结构,逻辑应该与Java类似。这就是我想出的。
免责声明:我对Java Script有点新鲜。以下解决方案基于 根据我的理解,我到目前为止对语言有所了解,我希望它是 在公认的指南和最佳实践中。
以下代码演示了&#39;扩展&#39; Java中的关键词可以在JS中模仿。
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级继承。 希望这会有所帮助。