Javascript 在何处/何时设置功能原型?
我不熟悉javascript原型 在示例中,原型是按照主程序定义分配的,但这样做会产生启动序列的影响 下面显示了我当前如何将原型应用于一组单例。为了清晰起见,最好将原型分配到后代类中,或者更明显地“绑定”到它的某个地方。(注意,面板在控制器内实例化以强制分离。) 是否有其他的地点/方法来完成这一点,我忽略了?此外,我是否违反了当前方法的任何著名风格Javascript 在何处/何时设置功能原型?,javascript,prototype,Javascript,Prototype,我不熟悉javascript原型 在示例中,原型是按照主程序定义分配的,但这样做会产生启动序列的影响 下面显示了我当前如何将原型应用于一组单例。为了清晰起见,最好将原型分配到后代类中,或者更明显地“绑定”到它的某个地方。(注意,面板在控制器内实例化以强制分离。) 是否有其他的地点/方法来完成这一点,我忽略了?此外,我是否违反了当前方法的任何著名风格 var controller = new Controller(); function Controller() { var panels
var controller = new Controller();
function Controller() {
var panels = {
search: SearchPanel,
results: ResultsPanel,
details: DetailsPanel,
action: ActionPanel,
};
$.each(panels, function (i, v) {
// THE QUESTION REFERS TO THIS FOLLOWING STATEMENT:
v.prototype = new PanelCommon();
panels[i] = new v();
});
this.publish = function (site, message) {
$.each(panels, function (i, v) {
if (v[site]) v[site](message);
});
}
/*...*/
}
function PanelCommon() { /*...*/ }
function SearchPanel() { /*...*/ }
function ResultsPanel() { /*...*/ }
function DetailsPanel() { /*...*/ }
function ActionPanel() { /*...*/ }
通常在构造函数声明之后立即分配原型。另外,不要忘记修改新实例化原型的
构造函数
属性
var mixinPanelTo = (function() {
var render = function() {
// a render function that all panels share
console.log("rendering!")
}
// Augment
return function(cls) {
cls.prototype.render = render;
}
})();
Sean还对使用Object.create提出了一个有趣的观点,但您是否希望这样做实际上取决于PanelCommon构造函数的内容。您可能还必须在旧浏览器中填充Object.create
function PanelCommon() {}
function SearchPanel() {}
SearchPanel.prototype = new PanelCommon();
SearchPanel.prototype.constructor = SearchPanel;
function ResultsPanel() {}
ResultsPanel.prototype = new PanelCommon();
ResultsPanel.prototype.constructor = ResultsPanel;
function DetailsPanel() {}
DetailsPanel.prototype = new PanelCommon();
DetailsPanel.prototype.constructor = DetailsPanel;
function ActionPanel() {}
ActionPanel.prototype = new PanelCommon();
ActionPanel.prototype.constructor = ActionPanel;
通常在构造函数声明之后立即分配原型。另外,不要忘记修改新实例化原型的
构造函数
属性
var mixinPanelTo = (function() {
var render = function() {
// a render function that all panels share
console.log("rendering!")
}
// Augment
return function(cls) {
cls.prototype.render = render;
}
})();
Sean还对使用Object.create提出了一个有趣的观点,但您是否希望这样做实际上取决于PanelCommon构造函数的内容。您可能还必须在旧浏览器中填充Object.create
function PanelCommon() {}
function SearchPanel() {}
SearchPanel.prototype = new PanelCommon();
SearchPanel.prototype.constructor = SearchPanel;
function ResultsPanel() {}
ResultsPanel.prototype = new PanelCommon();
ResultsPanel.prototype.constructor = ResultsPanel;
function DetailsPanel() {}
DetailsPanel.prototype = new PanelCommon();
DetailsPanel.prototype.constructor = DetailsPanel;
function ActionPanel() {}
ActionPanel.prototype = new PanelCommon();
ActionPanel.prototype.constructor = ActionPanel;
您可以使用-这将避免ES3解决方案的新超类
怪异之处:
> SearchPanel.prototype = Object.create(PanelCommon.prototype)
> SearchPanel.prototype.constructor = SearchPanel
> new SearchPanel instanceof PanelCommon
true
这可以提取到一个非常简单的extends
函数中:
function extends(cls, superClass) {
cls.prototype = Object.create(superClass.prototype);
cls.prototype.constructor = cls;
return cls;
}
然后可以这样使用:
var SpecialPanel = extends(function SpecialPanel() {}, PanelCommon);
您可以使用-这将避免ES3解决方案的新超类
怪异之处:
> SearchPanel.prototype = Object.create(PanelCommon.prototype)
> SearchPanel.prototype.constructor = SearchPanel
> new SearchPanel instanceof PanelCommon
true
这可以提取到一个非常简单的extends
函数中:
function extends(cls, superClass) {
cls.prototype = Object.create(superClass.prototype);
cls.prototype.constructor = cls;
return cls;
}
然后可以这样使用:
var SpecialPanel = extends(function SpecialPanel() {}, PanelCommon);
另一个适合JavaScript动态特性的概念是
Mixins
或Augmentation
,它们有时比原型继承更自然
我说的混血是什么意思?
一个“mixin”,它接受一个对象,并注入更多的功能。基本上,我们的想法是,我们将获取一个对象,并开始向其添加行为
考虑以下mixinPanelTo()
函数。它将是一个接受构造函数并向其原型添加公共render()
函数的函数
var mixinPanelTo = (function() {
var render = function() {
// a render function that all panels share
console.log("rendering!")
}
// Augment
return function(cls) {
cls.prototype.render = render;
}
})();
现在我们有了它,我们可以将该功能混合到我们想要的任何构造函数中:
var SearchPanel = function() {}
SearchPanel.prototype.search = function(query) {
/* search stuff */
this.render();
}
mixinPanelTo(SearchPanel)
那么,我们应该能够
var panel = new SearchPanel()
panel.search("foo"); // "rendering!" on the console
多重混合
与继承相比,mixin的一个优点是对应用的功能进行更精细的控制,并且能够从多个父级借用功能
var mixinRender = function(cls) { /* inject render */ }
var mixinSearch = function(cls) { /* inject search */ }
var mixinInfiniteScroll = function(cls) { /* inject infinite scroll */ }
var customPanel = function() {}
mixinRender(customPanel);
mixinSearch(customPanel);
mixinInfiniteScroll(customPanel)
使用原型继承很难做到这一点。而不是试图建立一个奇怪的类层次结构
借用功能
您还可以从目标类获得mixin所需的功能/配置。例如,让我们使用mixinInfinitScroll
var mixinInfiniteScroll = function(cls, fetch) {
var page = 0;
cls.prototype.more = function() {
var data
// get more results
if(typeof fetch == "function")
data = fetch.call(this, ++page)
else
// assume a key in this
data = this[fetch](++page)
/* do work with data */
}
}
然后在混合使用此功能时,我们可以注入特定的功能:
// by key
var Panel1 = function() { }
Panel1.prototype.fetch = function() { /* go get more results */ }
mixinInifiniteScroll(Panel1, "fetch")
// or even with a direct reference
var Panel1 = function() { }
Panel1.prototype.fetch = function() { /* go get more results */ }
mixinInifiniteScroll(Panel1, Panel1.prototype.fetch)
// or even an anonymous function
var Panel1 = function() { }
mixinInifiniteScroll(Panel1, function() { /* go get more results */ })
重载方法
您还可以覆盖mixin中的原型方法,这使得它们非常强大
var augmentRender = function(cls, renderFn) {
var oldRender = cls.prototype[renderFn];
cls.prototype[renderFn] = function() {
/* prep */
oldRender.apply(this, arguments);
/* make some more changes */
}
}
然后我们可以说:
var Panel = function() { }
Panel.prototype.render = function() { /* my render */ }
augmentRender(Panel, "render")
无论如何,这并不是说原型继承有什么问题,但这可能会让您对以不同方式解决问题的不同方法有更多的了解。另一个适合JavaScript动态特性的概念是
混合
或增强
,有时比原型遗传更自然
我说的混血是什么意思?
一个“mixin”,它接受一个对象,并注入更多的功能。基本上,我们的想法是,我们将获取一个对象,并开始向其添加行为
考虑以下mixinPanelTo()
函数。它将是一个接受构造函数并向其原型添加公共render()
函数的函数
var mixinPanelTo = (function() {
var render = function() {
// a render function that all panels share
console.log("rendering!")
}
// Augment
return function(cls) {
cls.prototype.render = render;
}
})();
现在我们有了它,我们可以将该功能混合到我们想要的任何构造函数中:
var SearchPanel = function() {}
SearchPanel.prototype.search = function(query) {
/* search stuff */
this.render();
}
mixinPanelTo(SearchPanel)
那么,我们应该能够
var panel = new SearchPanel()
panel.search("foo"); // "rendering!" on the console
多重混合
与继承相比,mixin的一个优点是对应用的功能进行更精细的控制,并且能够从多个父级借用功能
var mixinRender = function(cls) { /* inject render */ }
var mixinSearch = function(cls) { /* inject search */ }
var mixinInfiniteScroll = function(cls) { /* inject infinite scroll */ }
var customPanel = function() {}
mixinRender(customPanel);
mixinSearch(customPanel);
mixinInfiniteScroll(customPanel)
使用原型继承很难做到这一点。而不是试图建立一个奇怪的类层次结构
借用功能
您还可以从目标类获得mixin所需的功能/配置。例如,让我们使用mixinInfinitScroll
var mixinInfiniteScroll = function(cls, fetch) {
var page = 0;
cls.prototype.more = function() {
var data
// get more results
if(typeof fetch == "function")
data = fetch.call(this, ++page)
else
// assume a key in this
data = this[fetch](++page)
/* do work with data */
}
}
然后在混合使用此功能时,我们可以注入特定的功能:
// by key
var Panel1 = function() { }
Panel1.prototype.fetch = function() { /* go get more results */ }
mixinInifiniteScroll(Panel1, "fetch")
// or even with a direct reference
var Panel1 = function() { }
Panel1.prototype.fetch = function() { /* go get more results */ }
mixinInifiniteScroll(Panel1, Panel1.prototype.fetch)
// or even an anonymous function
var Panel1 = function() { }
mixinInifiniteScroll(Panel1, function() { /* go get more results */ })
重载方法
您还可以覆盖mixin中的原型方法,这使得它们非常强大
var augmentRender = function(cls, renderFn) {
var oldRender = cls.prototype[renderFn];
cls.prototype[renderFn] = function() {
/* prep */
oldRender.apply(this, arguments);
/* make some more changes */
}
}
然后我们可以说:
var Panel = function() { }
Panel.prototype.render = function() { /* my render */ }
augmentRender(Panel, "render")
无论如何,这并不是说原型继承有什么问题,但这可能会给你更多的想法,让你以不同的方式解决问题。迈克,众所周知的做法就是这样做,但是,通过将我的依赖实例化移动到代码的末尾来尊重结果序列依赖性?即,可能声明
var控制器代码>在头部,但不考虑位置控制器=新控制器()代码>在尾部?嗯。是的,Javascript有时依赖顺序,有时不依赖顺序。一般来说,你应该在使用它们之前声明它们,即使这不是严格必要的。函数声明和函数定义之间有区别<代码>函数foo(){}
是一个声明,无论它出现在何处,都将从文件顶部可见var foo=function(){}
是一个函数表达式,foo
的值将是