我理解有很多关于" Javascript:The Good Parts"但是我试图理解书中一个句子的含义并且不能完全理解它。在第41-42页中,他定义了serial_maker函数:
var serial_maker = function ( ) {
// Produce an object that produces unique strings. A
// unique string is made up of two parts: a prefix
// and a sequence number. The object comes with
// methods for setting the prefix and sequence
// number, and a gensym method that produces unique
// strings.
var prefix = '';
var seq = 0;
return {
set_prefix: function (p) {
prefix = String(p);
},
set_seq: function (s) {
seq = s;
},
gensym: function ( ) {
var result = prefix + seq;
seq += 1;
return result;
}
};
};
var seqer = serial_maker();
seqer.set_prefix('Q');
seqer.set_seq(1000);
var unique = seqer.gensym(); // unique is "Q1000"
然后他说:
这些方法不使用 this 和 。因此,没有办法妥协 sequer 。获取或更改前缀或 seq 是不可行的,除非方法允许
我应该如何使用这个和/或那个打破这种封装?我看不到它
由于
答案 0 :(得分:2)
考虑以下变化:
var serial_maker = function () {
return {
prefix: '',
seq: 0,
set_prefix: function (p) {
this.prefix = String(p);
},
set_seq: function (s) {
this.seq = s;
},
gensym: function ( ) {
var result = this.prefix + this.seq;
this.seq += 1;
return result;
}
};
};
现在,sequer的预期用途如下:
var sequer = serial_maker();
sequer.set_prefix('right');
sequer.set_seq(1000);
但是,在我上面发布的版本中,你也可以这样做:
var sequer = serial_maker();
sequer.prefix = 'wrong';
sequer.seq = -500;
甚至这个:
delete sequer.prefix;
由于prefix
和seq
都作为sequer对象的属性公开,因此JavaScript中的属性始终是公共的。任何有权访问该对象的代码都至少可以读取其属性,并且通常也会修改它们(除非您使用Object.defineProperty()
提供的某些功能)。
至于that
:在引入箭头函数之前,这是一个非常常见的问题,定义为方法的函数无法访问创建它们的上下文。
考虑以下示例:
var ButtonInitializer = {
message: 'Hello!'
init: function() {
for (let button of document.querySelectorAll('button')) {
button.onclick = function() {
alert(this.message);
}
}
}
};
ButtonInitializer.init();
对象ButtonInitializer
在文档中搜索<button>
元素,并设置其onclick
事件侦听器以显示警报;我们的目的是显示ButtonInitializer.message
中定义的消息。但是,如果您运行上述代码,则会发现警报为“undefined
”。这是因为我们分配给button.onclick
的函数成为按钮的方法,因此函数内的this
关键字现在将引用按钮,而不是ButtonInitializer
。
今天,我们可以通过箭头功能来解决这个问题:
button.onclick = () => {
alert(this.message);
}
箭头功能没有自己的this
范围,因此警报会显示ButtonInitializer.message
,正如我们所说。在引入箭头函数之前,这是一个常见的解决方法:
var that = this;
button.onclick = function() {
alert(that.message);
}
这种技术通常与闭包一起使用,并且允许对象的方法可以访问的“私有”成员的有限实现,但是不能从外部代码直接看到。
答案 1 :(得分:2)
有两种流行的方法可以在JavaScript中使用函数创建对象:
factory
模式constructor
模式(使用ES6 class
更好地说明) factory
模式
在此示例中,他正在使用并引用factory
模式,该模式不使用new
关键字,也不会对新创建的this
绑定宾语。它只创建一个新对象并将其作为函数表达式的值返回,从而将其称为工厂。
工厂函数是在JavaScript中创建真实对象私有属性的最佳方式,因此使用闭包进行封装。由于没有this
绑定,因此无法访问工厂函数中封装的变量prefix
和seq
。使用此模式是在JavaScript中创建完全私有的封装对象“property”的唯一方法(与Java使用private
相比。)
我应该如何使用这个和/或那个打破封装?
您可以使用 Constructor
模式(使其成为构造函数)重新考虑该代码,如下所示(使用ES6):
class SerialMaker {
// Creates a `this` binding to the instance of the class
// No actual encapsulation on the private properties
constructor () {
// PSEUDO-PRIVATE PROPERTIES
this.__prefix__ = '';
this.__seq__ = 0;
// METHODS
this.set_prefix: function (p) {
this.__prefix__ = String(p);
};
this.set_seq: function (s) {
this.__seq__ = s;
};
gensym: function ( ) {
var result = this.__prefix__ + this.__seq__;
this.__seq__ += 1;
return result;
};
}
现在,您可以使用new
运算符
var seqer = new SerialMaker(); // Calls the constructor and creates a new instance object
seqer.set_prefix('Q'); // Set on this instance only: this.__prefix__
seqer.set_seq(1000); // Set on this instance only: this.__seq__
var unique = seqer.gensym(); // unique is "Q1000"
到目前为止,问题是......
sequer.__prefix__ // => 'Q' // What??? This was supposed to be private!
sequer.__seq__ = 2000 // Works with no error
... 封装完全被破坏。 seqer受到了损害。