ES6 class类中定义私有变量

ES6 class类中定义私有变量

class类的不足

看起来, es6 中 class 的出现拉近了 JS 和传统 OOP 语言的距离。但是,它仅仅是一个语法糖罢了,不能实现传统 OOP 语言一样的功能。在其中,比较大的一个痛点就是私有变量问题。

何为私有变量?私有变量就是只能在类内部访问的变量,外部无法访问的变量。在开发中,很多变量或方法你不想其他人访问,可以定义为私有变量,防止被其他人使用。在 Java 中,可以使用 private 实现私有变量,但是可惜的是, JS 中并没有该功能。

来看下下面这个代码:

class A {
    constructor(x) {
        this.x = x
    }

    // 想要通过该方法来暴露x
    showX () {
        return this.x
    }
}

let a = new A(1)

// 直接访问x成功
a.x // 1

可以看到,虽然本意是通过方法 showX 来暴露 x 的值,但是可以直接通过 a.x 来直接访问 x 的值。

很明显,这影响了代码的封装性。要知道,这些属性都是可以使用 for...in 来遍历出来的。

所以,实现 class 的私有变量功能是很有必要的。

实现 class 私有变量

虽然, class 本身没有提供私有变量的功能,但是,我们可以通过通过一些方式来实现类似于私有变量的功能。

  1. 约定命名

    首先,是目前使用最广的方式:约定命名。

    该方式很简单,就是团队自行约定一种代表着私有变量的命名方式,一般是在私有变量的名称前加上一个下划线。代码如下:

    class A {
        constructor(x) {
            // _x 是一个私有变量
            this._x = x
        }
    
     showX () {
         return this._x
     }
    
    }
    
    let a = new A(1)
    
    // _x 依然可以被使用
    a._x        // 1
    a.showX()   //1

    可以发现,该方法最大的优点是简单、方便,所以很多团队都采用了这种方式。

    但是,该方式并没有从本质上解决问题,如果使用 for...in 依然可以遍历出所谓的私有变量,可以说是治标不治本。

    不过,该方式有一点值得肯定,那就是通过约定规范来方便他人阅读代码。

  2. 闭包
    闭包在很多时候被拿来解决模块化问题,显而易见,私有变量本质上也是一种模块化问题,所以,我们也可以使用闭包来解决私有变量的问题。

    我们在构造函数中定义一个局部变量,然后通过方法引用,该变量就成为了真正的私有变量。

    class A {
        constructor (x) {
            let _x = x
            this.showX = function () {
                return _x
            }
        }
    }
    
    let a = new A(1)
    // 无法访问
    a._x        // undefined
    // 可以访问
    a.showX()   // 1

    该方法最大的优点就是从本质解决了私有变量的问题。

    但是有个很大的问题,在这种情况下,引用私有变量的方法不能定义在原型链上,只能定义在构造函数中,也就是实例上。这导致了两个缺点:

    • 增加了额外的性能开销
    • 构造函数中包含了方法,较为臃肿,对后续维护造成了一定的麻烦
  3. 进阶版闭包方式

    既然在构造函数内部定义闭包那么麻烦,那我放在 class 外面不就可以了吗?

    • 我们可以通过 IIFE (立即执行函数表达式) 建立一个闭包
    • 在其中建立一个变量以及 class ,通过 class 引用变量实现私有变量。

    代码如下:

    // 利用闭包生成IIFE,返回类A
    const A = (function() {
        // 定义私有变量_x
        let _x
    
     class A {
         constructor (x) {
             // 初始化私有变量_x
             _x = x
         }
    
         showX () {
             return _x
         }
     }
    
     return A
    
    })()
    
    let a = new A(1)
    
    // 无法访问
    a._x        // undefined
    // 可以访问
    a.showX()   //1

    可以发现,该方法完美解决了之前闭包的问题,只不过写法相对复杂一些,另外,还需要额外创建 IIFE ,有一点额外的性能开销。

    • 注:该方式也可以不使用 IIFE ,可以直接将私有变量置于全局,但是这不利于封装性。
  4. Symbol
    这种方式利用的是 Symbol 的唯一性—— 敌人最大的优势是知道我方key值,我把key值弄成唯一的,敌人不知道我的key值,不就无法访问了吗? (人质是这次任务的关键,当敌人不再拥有人质时,任务也就完成了)

    代码如下:

    class A {
        constructor (x) {
    
            // 定义symbol
         const _x = Symbol('x')
    
            // 利用symbol声明私有变量
            this[_x] = x
        }
    
        showX () {
            return this[_x]
        }
    }
    
    let a = new A(1)
    
    // 1. 第一种方式
    a[_x]    // 报错 Uncaught ReferenceError: _x is not defined
    
    // 2. 第二种方式
    // 自行定义一个相同的Symbol
    const x = Symbol('x')
    a[x]        // 无法访问,undefined
    
    // 3. 第三种方式,可以访问(正解)
    a.showX()   //1

    从结果来看,完美地实现了 class 私有变量。

原文地址:https://www.cnblogs.com/guojbing/p/10990267.html

时间: 2024-10-16 17:30:10

ES6 class类中定义私有变量的相关文章

javascript在私有作用域中定义私有变量和私有函数 (1)

javascript没有私有成员,但是有私有变量,所有对戏那个属性都是公有的 任何在函数中定义的变量,都可以认为是私有变量,因为函数内部不能访问. 私有变量包括:函数的参数.局部变量.函数内部定义的其他函数 - 在私有作用域中定义私有变量和私有函数 function MyObject(){ //私有变量和私有函数 var privateVariable=10; function privateFunction(params) { return false } //特权方法----有权访问私有变量

spring-在切面类中定义私有方法解决重复编写execution函数

一.创建项目    项目名称:spring101002二.添加jar包    1.在项目中创建lib目录        /lib    2.在lib目录下添加相关spring jar包        --用于AspectJ        com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar        spring-aspects-3.2.0.RELEASE.jar        --用于切面编程        com.springsour

函数中的私有变量和特权方法

定义 [1][私有变量] 任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数外部访问这些变量.私有变量包括函数的参数.局部变量和在函数内部定义的其他函数 [2][特权方法] 如果在函数内部创建一个闭包,那么闭包通过自己的作用域链也可以访问这些变量.而利用这一点,就可以创建用于访问私有变量的公有方法.有权访问私有变量和私有函数的公有方法称为特权方法. 创建方式 [1][构造函数] 在构造函数内部定义所有私有变量和函数.然后,创建能够访问这些私有成员的特权方法.能够在构造函数中定义特权方法

php 类中定义全局变量|php类定义变量|php类定义常量

PHP 预定义超全局数组/变量 => http://www.q3060.com/list3/list117/23295.html PHP预定义变量 - PHP 超级全局变量 => http://www.q3060.com/list3/list117/23278.html php怎么定义全局变量 => http://www.q3060.com/list3/list117/22852.html php 的全局变量与局部变量 => http://www.q3060.com/list3/l

C++类中的静态成员变量与静态成员函数

最近一直看c++相关的项目,但总是会被c++类中的静态成员变量与静态成员函数的理解感觉很是模糊,不明白为什么类中要是用静态成员变量.于是在网上搜集了一些资料,自己再稍微总结下. 静态成员的概念: 静态类中的成员加入static修饰符,即是静态成员.可以直接使用类名+静态成员名访问此静态成员,因为静态成员先于类的声明而存在于内存,也可以根据类声明的对象来访问.而非静态成员必须实例化之后才会分配内存. 非静态成员的概念: 所有没有加static的成员都是非静态成员.而类被实例化后,可以通过实例化的类

C++ 类中的静态成员变量,静态成员函数

//类中的静态成员变量,静态成员函数 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; /* 静态成员函数是属于整个类, static修饰的变量,是属于类,,所有的对象都能共享用. 在类的静态数据成员函数中,是不能调用具体的对象的变量的属性, 这是因为static修饰的变量是整个类共享,在静态成员函数中使用一个对象的成员属性 c++编译器无法知道这个成员属性是哪个对象的 所以在静态成员函数中只能使用静

Java中主类中定义方法加static和不加static的区别

Java中主类中定义方法加static和不加static的区别(前者可以省略类名直接在主方法调用,后者必须先实例化后用实例调用) 知识点:1.Getter and Setter 的应用 2.局部变量与成员变量(也可叫做全局变量) 3.Static关键字的用法 a.成员变量被static修饰后的所有类的共享属性 b.方法被static修饰之后,在本类内调用的类名省略问题;以及不用Static,即使在本类内也必须先实例化 4.This关键字的用法 this:是当前类的对象引用.简单的记,它就代表当前

友元——友元可以访问与其有好友关系的类中的私有成员。 友元包括友元函数和友元类。

简介:友元可以访问与其有好友关系的类中的私有成员.    友元包括友元函数和友元类. [1]将普通函数声明为友元函数 #include<iostream> using namespace std; class Time { public: Time(int,int,int); friend void display(Time &);//定义友元函数 private: int hour; int minute; int sec; }; Time::Time(int h,int m,int

访问python中的私有变量

访问python中的私有变量 要给实习生培训python, 话说我自己都不怎么会用, 不能误人子弟, 再看看一些python中的概念吧. 看到类以及私有变量时, 想到以前看过文章, 说Python里面有私有函数也能被调用, 就顺手搜索了一下, stackoverflow有个问题就是问这个的. Why are Python's 'private' methods not actually private? HOW 类里面用两个下划线__打头的, 就是私有变量/函数 (后面会说到其实不是这样的) 照