简体   繁体   English

Crockford的安全对象模块

[英]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 . 该方法不使用thisthat 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. 由于prefixseq都作为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中的函数创建对象的流行方法:

  • The factory pattern factory模式
  • The 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绑定,因此无法访问封装在工厂函数中的变量prefixseq 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM