Javascript 在闭包内声明的类与不带闭包的标准类
通常我使用基于原型的标准OOP方法,我的类如下所示Javascript 在闭包内声明的类与不带闭包的标准类,javascript,oop,closures,prototype,Javascript,Oop,Closures,Prototype,通常我使用基于原型的标准OOP方法,我的类如下所示 var std = function(){ this.log = function(msg){ console.log("want to be private. " + msg) }; }; std.prototype = { logInfo: function(msg){ this.log(msg); } }; 但在这种情况下,log是公共方法,任何人都可以使用它。但我想让它私有化,但在原型中声明的方
var std = function(){
this.log = function(msg){ console.log("want to be private. " + msg) };
};
std.prototype = {
logInfo: function(msg){
this.log(msg);
}
};
但在这种情况下,log
是公共方法,任何人都可以使用它。但我想让它私有化,但在原型中声明的方法中仍然可用。为此,我们需要关闭。代码将更改为此
var closureStd = (function(){
var std = function(){};
var log = function(msg){ console.log("I'm really private, youhooo!" + msg) };
std.prototype = {
logInfo: function(msg){
log(msg);
}
};
return std;
})();
所以我的问题是:std
和closureStd
之间有什么区别?我需要付出什么代价才能从原型调用私有方法
std和closureStd之间有什么区别
std
构造函数在每次调用时都会创建一个新方法,而closureStd
则不会。你应该来的
function std(){}
std.prototype = {
log: function(msg){ console.log("want to be private. " + msg) },
logInfo: function(msg){ this.log(msg); }
};
当然,(您已经知道,closureStd
中的log
函数存储在一个(私有)变量中,而在std
实例上,每个实例(或其原型)都可以从外部访问(和覆盖)。在闭包中,它是范围链中的变量查找(可以假定为静态),而对于方法,它是对象(及其原型链)上的属性查找,这可能是动态的,但在现代引擎中同样得到优化
我需要付出什么代价才能从原型调用私有方法
没有。模块模式是常见且廉价的,静态链中的变量查找非常快。我宁愿担心内存,因为在构造函数方法中创建了太多的方法实例。我还做了一些测试来衡量性能(结果将在控制台中),我发现将类放在闭包中比将方法放在构造函数中表现出更好的性能。您还有继承选项。所以现在我没有看到缺点,当我需要私有方法时,我总是在闭包中使用类 请注意,Bondye提供的模块模式不包含私有实例属性。它对函数属性非常有用,因为函数不会对每个实例进行更改,但对值属性却有点不可预测,如下代码所示:
var module = (function () {
// private variables and functions
var foo = 'bar';
// constructor
var module = function (name) {
// instance variables
this.name=name;
};
// prototype
module.prototype = {
constructor: module,
something: function () {
// notice we're not using this.foo
console.log("foo in "+this.name+" is:",foo);
foo="new value";
}
};
// return module
return module;
})();
var m1 = new module("m1");
var m2 = new module("m2");
m1.something();// foo in m1 is: bar
m1.something();// foo in m1 is: new value
m2.something();// foo in m2 is: new value
正如您在最后一行代码中看到的,m1和m2实例共享一个名为foo的私有变量(所有实例都指向相同的值)
我从发布的文章中可以看出,在JavaScript模拟私有性是很困难的,你可以考虑使用命名约定来指示属性是私有的。您可以使用类似于谷歌闭包编译器的东西,并注释您的JS代码以指示私密;但是使用闭包编译器有其自身的缺点(除非闭包编译器兼容,并且代码必须采用某种格式才能在高级模式下编译,否则无法编译使用过的库)
另一种选择是完全抛弃prototype(至少对于使用私有属性的所有内容),并将所有内容放在构造函数的主体中(或者使用返回对象的函数) 使用私有实例值时可能遇到的另一个问题是,它们只能在实例中访问。如果要克隆对象并在对象中定义克隆函数以创建新实例,则必须编写公共访问器函数来设置私有值,因为不能像中那样直接设置它们有关在此处使用构造函数的更多信息:为您提供帮助完整链接:感谢您提供有趣的文章。这让我明白了一些道理,但不要回答问题(很抱歉,没有注意到您添加了第二篇文章。还需要阅读。感谢您的回答。第一个示例非常有趣,我花了一些时间来理解为什么这样做。现在我看到闭包不是私有字段的完美变体,但最初的问题是关于方法。将所有内容放在构造函数中不是一个好方法实践我的观点主要是因为性能。@silent_coder你是对的,第一个例子对私有函数很好,它是来自Bondye提供的链接的代码。由于谷歌的分数很高,我认为最好提及私有实例值并不是那么容易。
// function returning an object
function makeObj(name){
// private vars:
var foo = "bar";
return {
name:name,
something:function(){
console.log("foo in "+this.name+" is:",foo);
foo="new value";
}
}
}
var m1=makeObj("m1");
var m2=makeObj("m2");
m1.something();// foo in m1 is: bar
m1.something();// foo in m1 is: new value
m2.something();// foo in m2 is: bar
// constructor with everything in the constructor's body:
function Obj(name){
// private vars:
var foo = "bar";
this.name=name;
this.something=function(){
console.log("foo in "+this.name+" is:",foo);
foo="new value";
}
}
Obj.prototype.someOtherFunction=function(){
// anything here can't access the "private" variables
}
var m1=new Obj("m1");
var m2=new Obj("m2");
m1.something();// foo in m1 is: bar
m1.something();// foo in m1 is: new value
m2.something();// foo in m2 is: bar