我正在寻找一种模式,它允许我创建一个我的函数原型可以访问的私有范围,我需要能够从该范围内访问该实例。
例如,这就是我目前正在实现“私有方法”的方式(忽略代码实际执行的操作,只需查看结构。)
function InfoPreview() {
this.element = document.createElement('div');
}
//Private Methods
InfoPreview.prototype.__newLine = function () {
this.element.appendChild(createElement({tagName:'br'}));
};
InfoPreview.prototype.__padLeft = function(level) {
var padding = createElement({tagName: 'span'});
this.element.appendChild(padding);
$(padding).width(level * 10);
};
InfoPreview.prototype.__print = function(string) {
var span = createElement({ tagName: 'span', textContent: string });
this.element.appendChild(span);
this.element.style["margin-right"]='10px';
};
InfoPreview.prototype.__puts = function(string) {
this.__print(string);
this.__newLine();
};
//Public Methods
InfoPreview.prototype.update = function(info) {
$(this.element).empty();
for (var record in info) {
this.__puts(record);
}
};
请注意,我根本不使用命名约定来创建私有方法。另请注意,我无法缓存链查找,例如this.element
。
我想通过利用一个揭示模块模式来创建一个私有范围,如下所示:
InfoPreview.prototype = (function() {
var self = this, //<- `this` is actually the global object now.
el = self.element;
var newLine = function () {
el.appendChild(createElement({tagName:'br'}));
};
var padLeft = function(level) {
var padding = createElement({tagName: 'span'});
el.appendChild(padding);
$(padding).width(level * 10);
};
var print = function(string) {
var span = createElement({ tagName: 'span', textContent: string });
el.appendChild(span);
el.style["margin-right"]='10px';
};
var puts = function(string) {
print(string);
newLine();
};
var update = function(info) {
$(el).empty();
for (var record in info) {
puts(record);
}
};
return {
update: update
};
})();
然而,上述方法不起作用,因为IIFE中this
的值是全局对象,而不是实例。我需要一种方法来访问实例。
答案 0 :(得分:1)
在每个函数中,您可以访问所需的this
值。
var Example = function() {};
Example.prototype = (function() {
var privateUpdate = function() {
document.getElementById('answer').innerHTML = this.foo;
}
return {
update: privateUpdate
}
})();
var e = new Example();
e.foo = 'bar';
e.update();
&#13;
<div id="answer"></div>
&#13;
答案 1 :(得分:1)
作为Pointy建议的变体,你可以尝试这种模式;
infoPreview.prototype = (function() {
var self = null;
var update = function(info) {
....
};
var firstUpdate = function(info) {
self = this;
functions.update = update;
update(info);
}
var functions = {
update: firstUpdate
};
return functions;
})();
答案 2 :(得分:1)
使用构造函数模式有什么缺点吗?
function Foo(constructorArg) {
/* private variables */
var privVar = 'I am private',
cArg = constructorArg;
/* public variables */
this.pubVar = 'I am public';
/* private function */
function privFunc() {
return 'I am a private function';
}
/* public function */
this.publicFunc = function() {
return 'I am a public function and I call privVar->"' + privVar + '" and privFunc->"' + privFunc() + '"';
}
}
var foo = new Foo('something');
console.log('foo.pubVar', foo.pubVar); //ok
console.log('foo.publicFunc()', foo.publicFunc()); // ok
console.log('foo.privVar', foo.privVar); // undefined
console.log('foo.privFunc', foo.privFunc()); //error
&#13;
简单地说,因为它是创建一个真正的私人范围&#34;的唯一(理智)方式,这是你的问题。
另一种方法是使用一种约定,告诉开发人员哪些属性和方法是私有的,通常是在前面添加一个你已经实现但不喜欢的下划线_
。
请注意,构造函数和原型是不同的东西,使您可以执行不同的操作。没有什么可以阻止你混合起来。
关于内存使用情况,在现代js引擎中,例如Google的V8 JavaScript引擎,the constructor pattern might actually be faster。
V8具有在运行时为对象内部创建的隐藏类型;具有相同隐藏类的对象可以使用相同的优化生成代码。
例如:
function Point(x, y) {
this.x = x;
this.y = y;
}
var p1 = new Point(11, 22);
var p2 = new Point(33, 44);
// At this point, p1 and p2 have a shared hidden class
p2.z = 55;
// warning! p1 and p2 now have different hidden classes!
原型链总是需要两次查找,因此它甚至可能是一个微小的inny LITTLE位慢。 注意:无法支持,jsperf.com已关闭!
表现是我的理由。我没有意识到这一点。然而它对我来说仍然感觉很脏
我不知道为什么你觉得构造函数模式很脏。也许是因为它有一些特定的&#34;,限制和潜在的陷阱你应该知道
this
可能意味着不同的事情然而,对于原型声明样式,1和2也是如此......
如果您认为这还不够,您可能需要查看模块模式。
答案 3 :(得分:0)
也许是这样的,没有原型设计:
var Fn = function(el) {
this.el = el;
var myMethod = function() {
console.log('do something in method with element', this.el);
}.bind(this);
return {
myPublicMethod: function() {
return myMethod();
}
}
}
var instancedFn = new Fn('first instance element')
.myPublicMethod()
;
var instancedFn2 = new Fn('second instance element')
.myPublicMethod()
;