>  기사  >  웹 프론트엔드  >  ES6의 개인 변수 구현 요약(코드 예)

ES6의 개인 변수 구현 요약(코드 예)

不言
不言앞으로
2018-11-21 11:25:491646검색

이 글은 ES6의 비공개 변수 구현에 대한 요약(코드 예제)을 제공합니다. 이는 특정 참조 값을 가지고 있으므로 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.

"ECMAScript 6 소개"를 읽으면서 프라이빗 변수의 구현이 흩어져 있는 것을 보았으므로 여기에 요약하겠습니다.

1. 컨벤션

구현

class Example {
    constructor() {
        this._private = 'private';
    }
    getName() {
        return this._private
    }
}

var ex = new Example();

console.log(ex.getName()); // private
console.log(ex._private); // private

장점

  1. 간단한 작성 방법

  2. 쉬운 디버깅

  3. 호환성

단점

  1. 외부인이

  2. 언어에 액세스하고 수정할 수 있습니다. 모든 속성을 열거하는 in in 문과 같은 일치하는 메커니즘은 없다 접근 및 수정 불가

  3. 단점

생성자의 로직이 복잡해집니다. 생성자는 객체 초기화만 수행해야 합니다. 이제 개인 변수를 구현하려면 일부 메서드의 구현을 포함해야 하며 코드 구성이 약간 불분명합니다.

메서드는 프로토타입이 아닌 인스턴스에 존재하며 하위 클래스는 슈퍼 호출을 사용할 수 없습니다.

  1. 구성으로 인해 약간의 오버헤드가 추가됩니다.

  2. 구현 2

    /**
     * 实现一
     */
    class Example {
      constructor() {
        var _private = '';
        _private = 'private';
        this.getName = function() {return _private}
      }
    }
    
    var ex = new Example();
    
    console.log(ex.getName()); // private
    console.log(ex._private); // undefined
  3. 장점

    이름 충돌 없음
  1. 못해 외부에서 액세스하고 수정할 수 있습니다
  2. 단점
  3. 작성 방법이 약간 복잡합니다

구성으로 인해 약간의 오버헤드가 추가됩니다

  1. 3. 기호

  2. 구현
  3. /**
     * 实现二
     */
    const Example = (function() {
      var _private = '';
    
      class Example {
        constructor() {
          _private = 'private';
        }
        getName() {
          return _private;
        }
      }
    
      return Example;
    
    })();
    
    var ex = new Example();
    
    console.log(ex.getName()); // private
    console.log(ex._private); // undefined

    장점

아니요 네이밍 충돌

  1. 외부 접근 및 수정 불가

  2. 성능 손실 없음

단점

작성 방법이 살짝 복잡함

  1. 호환성도 좋음

  2. 4.약한 지도

  3. realize
  4. const Example = (function() {
        var _private = Symbol('private');
    
        class Example {
            constructor() {
              this[_private] = 'private';
            }
            getName() {
              return this[_private];
            }
        }
    
        return Example;
    })();
    
    var ex = new Example();
    
    console.log(ex.getName()); // private
    console.log(ex.name); // undefined

    이렇게 쓰면 캡슐화가 부족하다고 느낄 수도 있으니 이렇게 써도 됩니다:

    /**
     * 实现一
     */
    const _private = new WeakMap();
    
    class Example {
      constructor() {
        _private.set(this, 'private');
      }
      getName() {
          return _private.get(this);
      }
    }
    
    var ex = new Example();
    
    console.log(ex.getName()); // private
    console.log(ex.name); // undefined
  5. Advantages

    Nonaming conflict
  1. 접근 및 수정 불가 외부적으로
  2. 단점

글쓰기가 더 귀찮음

일부 호환성 문제가 있음

  1. 일정한 성능 비용이 있음

  2. 5. 최신 제안은

    /**
     * 实现二
     */
    const Example = (function() {
      var _private = new WeakMap(); // 私有成员存储容器
    
      class Example {
        constructor() {
          _private.set(this, 'private');
        }
        getName() {
            return _private.get(this);
        }
      }
    
      return Example;
    })();
    
    var ex = new Example();
    
    console.log(ex.getName()); // private
    console.log(ex.name); // undefined
  3. 5. 왜 비공개를 사용하지 않습니까? 필드를 직접적으로? 예를 들면:
class Point {
  #x;
  #y;

  constructor(x, y) {
    this.#x = x;
    this.#y = y;
  }

  equals(point) {
    return this.#x === point.#x && this.#y === point.#y;
  }
}

간단히 말하면 너무 번거롭습니다. 물론 성능적인 고려 사항도 있습니다...

    예를 들어 #을 사용하지 않고 비공개 키워드를 사용하는 경우:
  1. class Foo {
      private value;
    
      equals(foo) {
        return this.value === foo.value;
      }
    }

    여기서 create new 두 개의 인스턴스가 생성된 후 foo2가 foo1의 인스턴스 메소드에 매개변수로 전달됩니다.

  2. 그럼 foo2.value의 값을 얻을 수 있을까요? foo2.value를 직접 호출하면 당연히 값을 얻을 수 없겠죠. 결국 private 변수인데 Equals는 Foo의 클래스 메소드이므로 얻을 수 있을까요?
  3. 답은 그렇습니다.

  4. 사실 이는 Java 및 C++와 같은 다른 언어에서도 동일합니다. 클래스의 멤버 함수는 동일한 유형의 인스턴스의 비공개 변수에 액세스할 수 있습니다. "외부 액세스" 정보는 클래스 자체에 숨겨져 있습니다. 프라이빗 변수에 대한 액세스를 금지할 필요는 없습니다. 또한 프라이빗 변수에 대한 제한은 객체가 아닌 클래스를 기반으로 한다는 점도 이해할 수 있습니다. 사용자에게.
  5. 값을 가져오는 것이 괜찮으므로 인쇄된 결과는 true여야 하지만, 우리가 전달한 값이 Foo의 인스턴스가 아니라 다른 객체라면 어떻게 될까요?

    class Foo {
      private value = '1';
    
      equals(foo) {
        return this.value === foo.value;
      }
    }
    
    var foo1 = new Foo();
    var foo2 = new Foo();
    
    console.log(foo1.equals(foo2));
  6. 물론 여기 코드는 정상적으로 실행될 수 있지만 컴파일러 입장에서는 조금 번거롭습니다. 왜냐하면 컴파일러는 value가 foo의 일반 속성인지 비공개 속성인지 모르기 때문에 컴파일러가 판단을 해야 하기 때문입니다. 먼저 판단합니다. foo는 Foo의 인스턴스이고 그 다음 값을 얻습니다.

이것은 또한 모든 속성 액세스에 대해 그러한 판단이 이루어져야 한다는 것을 의미하며, 엔진은 속성 액세스를 중심으로 고도로 최적화되었으며 변경하기에는 너무 게으르고 속도도 감소합니다.

그러나 이 작업 외에도 고려해야 할 몇 가지 다른 사항이 있습니다.

개인 키를 각 어휘 환경에 인코딩해야 합니다.

이 속성을 통과할 수 있습니까? foo2.value 肯定是获取不到值的,毕竟是私有变量,可是 equals 是 Foo 的一个类方法,那么可以获取到的吗?

答案是可以的。

其实这点在其他语言,比如说 Java 和 C++ 中也是一样的,类的成员函数中可以访问同类型实例的私有变量,这是因为私有是为了实现“对外”的信息隐藏,在类自己内部,没有必要禁止私有变量的访问,你也可以理解为私有变量的限制是以类为单位,而不是以对象为单位,此外这样做也可以为使用者带来便利。

既然获取值是可以的,那么打印的结果应该为 true,但是如果我们传入的值不是 Foo 的实例,而是一个其他对象呢?

var foo1 = new Foo();

console.log(foo1.equals({
  value: 2
}));

当然这里代码也是可以正常运行的,但是对于编译器来说,就有一点麻烦了,因为编译器不知道 value 到底是 foo 的正常属性还是私有属性,所以编译器需要做判断,先判断 foo 是不是 Foo 的实例,然后再接着获取值。

这也意味着每次属性访问都需要做这样一个判断,而引擎已经围绕属性访问做了高度优化,懒得改,而且还降低速度。

不过除了这个工作之外,还会有一些其他的内容需要考虑,比如说:

  1. 你必须将私有的 key 编码进每个词法环境

  2. for in 可以遍历这些属性吗?

  3. 私有属性和正常属性同名的时候,谁会屏蔽谁?

  4. 怎么防止私有属性的名称不被探测出来。

关于使用 # 而不使用 private 更多的讨论可以参考这个 Issue。

当然这些问题都可以被解决啦,就是麻烦了点。

而如果你选择 #,实现的方式将跟 JavaScript 对象属性完全没有关系,将会使用 private slots

비공개 속성과 일반 속성의 이름이 같으면 누가 누구를 차단할까요? 🎜🎜🎜🎜개인 속성의 이름이 감지되지 않도록 방지하는 방법. 🎜🎜🎜🎜private 대신 #을 사용하는 방법에 대한 자세한 내용은 이 이슈를 참조하세요. 🎜🎜물론 이러한 문제는 해결될 수 있지만 조금 귀찮습니다. 🎜🎜그리고 #을 선택하면 구현 방법은 JavaScript 개체 속성과 관련이 없으며 비공개 슬롯 방법을 사용하고 간단히 말해서 더 좋습니다. 개인 구현보다 방법이 훨씬 간단합니다. 🎜🎜🎜

위 내용은 ES6의 개인 변수 구현 요약(코드 예)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제