[英]Crockford's module for secure objects
I understand there's loads of questions and documentation around "Javascript: The Good Parts" but I'm trying to understand the meaning of a sentence in the book and can't quite get it. 我了解“ Javascript:The Good Parts”周围有很多问题和文档,但是我试图理解这本书中句子的含义,但还不太了解。 In the pages 41-42 he defines the serial_maker function:
在第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"
And then he says: 然后他说:
The methods do not make use of this and that .
该方法不使用this和that 。 As a result, there is no way to compromise the sequer .
结果,没有办法折衷续集 。 It isn't posible to get or change the prefix or seq except as permitted by the methods
除非方法允许,否则获取或更改前缀或seq是不可能的
How should I use this and/or that to break that encapsulation? 我应该如何使用这个和/或那个来破坏封装? I can't see it
我看不到
Thanks 谢谢
Consider the variation below: 考虑以下变化:
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;
}
};
};
Now, the intended use of the sequer is the following: 现在,续集的预期用途如下:
var sequer = serial_maker();
sequer.set_prefix('right');
sequer.set_seq(1000);
However, in the version I posted above, you could also do this: 但是,在我上面发布的版本中,您也可以这样做:
var sequer = serial_maker();
sequer.prefix = 'wrong';
sequer.seq = -500;
Or even this: 甚至这个:
delete sequer.prefix;
Since both prefix
and seq
are exposed as properties of the sequer object, and properties in JavaScript are always public. 由于
prefix
和seq
都作为sequer对象的属性公开,因此JavaScript中的属性始终是公共的。 Any code that has access to the object can at least read its properties, and usually modify them as well (unless you use some of the features provided by Object.defineProperty()
). 任何有权访问该对象的代码都至少可以读取其属性,并且通常也可以对其进行修改(除非您使用
Object.defineProperty()
提供的某些功能)。
As for that
: before arrow functions were introduced, it was a very common problem that functions defined as methods weren't able to access the context where they were created. 至于
that
:引入箭头的功能之前,它是定义为方法的功能无法访问他们在那里创建的上下文非常普遍的问题。
Consider the following example: 考虑以下示例:
var ButtonInitializer = {
message: 'Hello!'
init: function() {
for (let button of document.querySelectorAll('button')) {
button.onclick = function() {
alert(this.message);
}
}
}
};
ButtonInitializer.init();
The object ButtonInitializer
searches the document for <button>
elements and sets their onclick
event listener to display an alert; ButtonInitializer
对象在文档中搜索<button>
元素,并将其onclick
事件侦听器设置为显示警报。 our intention is to show the message defined in ButtonInitializer.message
. 我们的意图是显示
ButtonInitializer.message
定义的消息。 However, if you run the above code, you'll find that the alert is " undefined
". 但是,如果运行上面的代码,则会发现警报为“
undefined
”。 This is because the function we assign to button.onclick
becomes a method of the button, so the this
keyword inside the function will now refer to the button, and not the ButtonInitializer
. 这是因为我们分配给
button.onclick
的函数成为该按钮的方法,因此该函数内部的this
关键字现在将引用该按钮,而不是ButtonInitializer
。
Today, we can solve this with an arrow function: 今天,我们可以使用箭头功能解决此问题:
button.onclick = () => {
alert(this.message);
}
Arrow functions don't have their own this
scope, so the alert will display ButtonInitializer.message
, as we meant. 箭函数没有自己的
this
范围,因此警报显示ButtonInitializer.message
,因为我们的意思。 Before arrow functions were introduced, this was a common workaround: 在引入箭头功能之前,这是一种常见的解决方法:
var that = this;
button.onclick = function() {
alert(that.message);
}
This technique was used very commonly together with closures, and allowed a limited implementation of "private" members that the object's methods could access, but weren't directly visible from outside code. 该技术与闭包一起非常普遍地使用,并允许对象方法可以访问的“私有”成员的有限实现,但不能从外部代码直接看到。
There are two popular ways of creating objects from a function in JavaScript: 有两种从JavaScript中的函数创建对象的流行方法:
factory
pattern factory
模式 constructor
pattern (Better illustrated using ES6 class
) constructor
模式(使用ES6 class
更好地说明) The factory
Pattern factory
模式
In this example, he is using and referring to the factory
pattern, which does not make use of the new
keyword and also does not create a this
binding on the newly created object. 在此示例中,他正在使用并引用
factory
模式,该factory
模式未使用new
关键字,也未在新创建的对象上创建this
绑定。 It only creates a new object and returns it as a value of the function expression, thus why it is called a factory. 它仅创建一个新对象并将其作为函数表达式的值返回,因此将其称为工厂。
Factory functions are the best way to create true object private attributes in JavaScript, thus encapsulation using closure. 工厂函数是在JavaScript中创建真正的对象私有属性的最佳方法,因此可以使用闭包进行封装。 Because there is no
this
binding, you cannot access the variables prefix
and seq
that are encapsulated within the factory function. 由于没有
this
绑定,因此无法访问封装在工厂函数中的变量prefix
和seq
。 Using this pattern is the only way to create fully-private encapsulated object "property" in JavaScript (in comparison to Java's use of private
.) 使用这种模式是在JavaScript中创建完全私有的封装对象“属性”的唯一方法(与Java使用
private
。
How should I use this and/or that to break that encapsulation?
我应该如何使用这个和/或那个来破坏封装?
You would re-factor that code using the Constructor
Pattern (Make it into a constructor) which would look like this (using ES6): 您可以使用
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;
};
}
Now, you can create new object using the new
operator 现在,您可以使用
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"
Same thing up to this point, but the problem is... 到目前为止,还是一样,但是问题是...
sequer.__prefix__ // => 'Q' // What??? This was supposed to be private!
sequer.__seq__ = 2000 // Works with no error
... the encapsulation is completely broken . ... 封装被完全破坏了 。 The seqer is compromised.
续集被破坏。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.