iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >JS私有属性的实现方式有哪些
  • 549
分享到

JS私有属性的实现方式有哪些

2023-06-29 18:06:39 549人浏览 八月长安
摘要

这篇文章主要为大家展示了“js私有属性的实现方式有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JS私有属性的实现方式有哪些”这篇文章吧。class 是创建对象的模版,由一系列属性和方法构成

这篇文章主要为大家展示了“js私有属性的实现方式有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JS私有属性的实现方式有哪些”这篇文章吧。

class 是创建对象的模版,由一系列属性和方法构成,用于表示对同一概念的数据和操作。

有的属性和方法是对外的,但也有的是只想内部用的,也就是私有的,那怎么实现私有属性和方法呢?

不知道大家会怎么实现,我梳理了下,我大概用过 6 种方式,我们分别来看一下:

_prop

区分私有和公有最简单的方式就是加个下划线 _,从命名上来区分。

比如:

class Dong {    constructor() {        this._name = 'dong';        this._age = 20;        this.friend = 'guang';    }    hello() {        return 'I\'m ' + this._name + ', '  + this._age + ' years old';    }}const dong = new Dong();console.log(dong.hello());

这里的 Dong 就有私有属性 _name、_age,公有属性 friend。

但是这种方式只是一种命名规范,告诉开发者这个属性、方法是私有的,不要调用,但终究不是强制的,如果别人要用也阻止不了。

JS私有属性的实现方式有哪些

不过这种方式用的还是挺多的,历史比较悠久。

那怎么能基于这种规范实现真正的私有呢?这就要用到 Proxy 了:

Proxy

Proxy 可以定义目标对象的 get、set、Object.keys 的逻辑,可以在这一层做一下判断,如果是下划线 _ 开头就不让访问,否则就可以访问。

比如还是这个 class:

class Dong {    constructor() {        this._name = 'dong';        this._age = 20;        this.friend = 'guang';    }    hello() {        return 'I\'m ' + this._name + ', '  + this._age + ' years old';    }}const dong = new Dong();

我们不直接调用它的对象的属性方法了,而是先用一层 Proxy 来约束下 get、set、geTKEys 的行为:

const dong = new Dong(); const handler = {    get(target, prop) {        if (prop.startsWith('_')) {            return;        }        return target[prop];   },   set(target, prop, value) {    if (prop.startsWith('_')) {        return;     }     target[prop] = value;   },   ownKeys(target, prop) {      return Object.keys(target).filter(key => !key.startsWith('_'))   }, } const proxy = new Proxy(dong, handler)

我们通过 new Proxy 来给 dong 定义了 get、set、ownKeys 的 handler:

  • get: 如果以下划线 _ 开头就返回空,否则返回目标对象的属性值 target[prop]

  • set: 如果以下划线 _ 开头就直接返回,否则设置目标对象的属性值

  • ownKeys: 访问 keys 时,过滤掉目标对象中下划线开头的属性再返回

这样就实现了下划线开头的属性的私有化:

我们测试下:

const proxy = new Proxy(dong, handler)for (const key of Object.keys(proxy)) {    console.log(key, proxy[key])}

JS私有属性的实现方式有哪些

确实,这里只打印了公有属性的方法,而下划线开头的那两个属性没有打印。

我们基于 _prop 这种命名规范实现了真正的私有属性!

再调用下方法试试:

JS私有属性的实现方式有哪些

咋是 undefined 了?

因为 proxy.hello 方法的 this 也是指向 proxy 的,也会受限制,所以要再做下处理:

JS私有属性的实现方式有哪些

如果用的是方法,那就给它绑定 this 为目标对象。

这样 hello 方法就可以访问到那些 _ 开头的私有属性了:

JS私有属性的实现方式有哪些

我们通过 Proxy 给下划线的命名规范实现了真正的私有属性,但是要定义一层 Proxy 比较麻烦,有没有不定义 Prxoy 的方式呢?

确实有,比如 Symbol:

Symbol

Symbol 是 es2015 添加的一个 api,用于创建唯一的值。基于这个唯一的特性,我们就可以实现私有属性。

比如这样:

const nameSymbol = Symbol('name');const ageSymbol = Symbol('age');class Dong {    constructor() {        this[nameSymbol] = 'dong';        this[ageSymbol] = 20;    }    hello() {        return 'I\'m ' + this[nameSymbol] + ', '  + this[ageSymbol] + ' years old';    }}const dong = new Dong();

我们不再用 name 和 age 作为私有属性名了,而是用 Symbol 生成唯一的值来作为名字。

这样外面因为拿不到属性名,就没法取到对应的属性值:

JS私有属性的实现方式有哪些

这种方式比 Proxy 的方式更简单一些,也是用的很多的一种实现私有属性的方式。

如果想暴露出去,可以定义个 get 方法:

JS私有属性的实现方式有哪些

但是这种私有属性是真的没法访问么?

不是的,有一个 api 叫做 Object.getOwnPropertySymbols,可以取到对象的所有 Symbols 属性,然后就可以拿到属性值了:

JS私有属性的实现方式有哪些

所以说这种方式只是 Object.keys 取不到对应的属性而已,不如 Proxy 那种方式完善。

那不用 Proxy 的方式,还比有没有 Symbol 更完善的呢?

那可以试试这种:

WeakMap

外面可以访问到属性和方法是因为我们把它挂到了 this 上,那不挂到 this 上外面不就访问不到了么?

比如用一个 Map 保存私有属性:

const privateFields = new Map();class Dong {    constructor() {        privateFields.set('name', 'dong');        privateFields.set('age', 20);    }    hello() {        return 'I\'m ' + privateFields.get('name') + ', '  + privateFields.get('name') + ' years old';    }}

我们测试下:

JS私有属性的实现方式有哪些

这样貌似可以,但不知道大家有没有发现其中的问题:

  • 所有对象都用同一个 Map,之间相互影响

  • 对象销毁了这个 Map 依然存在

怎么解决这个问题呢?

不知道大家用没用过 WeakMap,它的特性是只能用对象作为 key,对象销毁,这个键值对就销毁。

完美解决了上面两个问题:

  • 因为是用对象作为 key 的,那不同的对象是放在不同的键值对上的,相互没影响

  • 对象销毁的时候,对应的键值对就销毁,不需要手动管理

貌似是很完美,我们实现下:

const dongName = new WeakMap();const dongAge = new WeakMap();const classPrivateFieldSet = function(receiver, state, value) {    state.set(receiver, value);}const classPrivateFieldGet = function(receiver, state) {    return state.get(receiver);}class Dong {    constructor() {        dongName.set(this, void 0);        dongAge.set(this, void 0);        classPrivateFieldSet(this, dongName, 'dong');        classPrivateFieldSet(this, dongAge, 20);    }    hello() {        return 'I\'m ' + classPrivateFieldGet(this, dongName) + ', '  + classPrivateFieldGet(this, dongAge) + ' years old';    }}

每个属性定义了一个 WeakMap 来维护,key 为当前对象,值为属性值,get 和 set 使用 classPrivateFieldSet 和 classPrivateFieldGet 这两个方法,最终是通过从 WeakMap 中存取的。

在构造器里初始化下当前对象对应的属性值,也就是 dongName.set(this, void 0),这里的 void 0 的返回值是 undefined,一个意思。

测试下:

JS私有属性的实现方式有哪些

哇,通过 WeakMap 也能实现私有属性!

不过这里的 classPrivateFieldGet 没必要定义吧,直接 xxMap.get 不就行么?

确实,包一层的目的是为了可以加一些额外的逻辑,这里也可以直接从 weakMap 取。

但这样写起来也很麻烦呀,有没有更简单的方式呢?

能不能设计一种语法糖,它自动编译成这种方式呢?

想的没错,确实有这种语法糖:

#prop

现在有一个私有属性的 es 草案,可以通过 # 的方式来标识私有属性和方法。

比如这样:

class Dong {    constructor() {        this.#name = 'dong';        this.#age = 20;        this.friend = 'guang';    }    hello() {        return 'I\'m ' + this.#name + this.#age + 'years old';    }}

这里的 name 和 age 都是私有的,而 friend 是公有的。

这种新语法 JS 引擎没那么快支持,但是可以通过 babel 或者 ts 编译器来编译成低版本语法的方式来提前用。

比如 babel 有 @babel/proposal-private-property-in-object 的插件,它可以实现这种语法的编译:

JS私有属性的实现方式有哪些

babel 就是把 #prop 编译成上面那种 WeakMap 的方式来实现的。

这个插件在 @babel/preset-env 的预设里,会自动引入:

JS私有属性的实现方式有哪些

除了 babel,ts 里也可以直接用这种语法:

JS私有属性的实现方式有哪些

也是会编译成 WeakMap 的方式来实现。

其实 ts 实现的新语法还是不少的,比如 ? 和 ?? 分别是可选链和默认值的语法,下面这两种写法等价:

const res = data?.name ?? 'dong';const res2 = data && data.name  || 'dong';

这种新语法都是直接可用的,babel 的话需要引入下 proposal 插件。

对了,我记得 ts 里 class 也是有 private 的修饰符的,那个不也是私有属性么?

其实它是私有属性但也不完全是,我们来看一下:

ts private

ts 可以通过 private 来修饰属性、方法的可见性:

  • private 表示属性私有,只有 class 内部可访问

  • protected 表示保护,只有 class 和子 class 可访问

  • public 表示公有,外部也可访问

类型检查和提示的时候是有区别的,比如 private 属性在 class 外部不可访问:

JS私有属性的实现方式有哪些

而 class 内部是可以访问的:

JS私有属性的实现方式有哪些

但是这种约束只是用于类型检查的,只存在编译期间,运行时并没有这种约束。

我们可以看下编译后的代码:

JS私有属性的实现方式有哪些

可以看到没有做任何处理。

而如果用 #prop 的方式,除了编译时是 private 的,运行时也是:

JS私有属性的实现方式有哪些

所以,要实现真正的 private 的话,还是用 #prop 的方式,如果只是编译时约束那声明下 private 就行。

总结

class 用于定义围绕某个概念的一系列属性和方法,这些属性和方法有的是内部用的,有的是对外的。只有内部用的属性、方法需要实现私有化。

实现私有属性方法,我树立了 6 种方式:

  • 通过下划线 _prop 从命名上区分

  • 通过 Proxy 来定义 get、set、ownKeys 的逻辑

  • 通过 Symbol 来定义唯一的属性名,不能通过 keys 拿到

  • 通过 WeakMap 来保存所有对象的私有属性和方法

  • 通过 #prop 的 es 新语法实现私有,babel 和 tsc 会把它们编译成 WeakMap 的方式

  • 通过 ts 的 private 在编译时约束

这六种方式,有三种只是伪私有,比如 _prop(依然可以访问)、ts 的 private(运行时可访问)、Symbol(可以通过 Object.getOwnSymbols 拿到 symbol 来访问)。

另外三种是真正的私有,包括 Proxy、WeakMap、#prop(目前是编译为 WeakMap 的方式)。

有的是从属性名上想办法,比如 _prop 和 Symbol,有的是从 this 上想办法,比如 Proxy(包一层) 和 WeakMap(不挂到 this),有的是从语言本身想办法,比如 ts 的 private 或者 es 新语法的 #prop。

以上是“JS私有属性的实现方式有哪些”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注编程网精选频道!

--结束END--

本文标题: JS私有属性的实现方式有哪些

本文链接: https://www.lsjlt.com/news/326012.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • JS私有属性的实现方式有哪些
    这篇文章主要为大家展示了“JS私有属性的实现方式有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JS私有属性的实现方式有哪些”这篇文章吧。class 是创建对象的模版,由一系列属性和方法构成...
    99+
    2023-06-29
  • 一文详解JS私有属性的6种实现方式
    目录_propProxySymbolWeakMap#propts private总结class 是创建对象的模版,由一系列属性和方法构成,用于表示对同一概念的数据和操作。 有的属性和...
    99+
    2024-04-02
  • Python 私有属性与私有方法
    目录1. 场景定义2. 语法定义3. 调用分析4. Python伪私有属性和私有方法1. 场景定义 私有属性: 是指在 Python 的面向对象开发过程中,对象的某些属性只想在对象的...
    99+
    2024-04-02
  • JS继承实现方式有哪些
    这篇文章主要介绍“JS继承实现方式有哪些”,在日常操作中,相信很多人在JS继承实现方式有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JS继承实现方式有哪些”的疑惑有所帮...
    99+
    2024-04-02
  • js实现倒计时的方式有哪些
    小编给大家分享一下js实现倒计时的方式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一般倒计时的时间都是后台传来的然后渲染...
    99+
    2024-04-02
  • js实现瀑布流的方式有哪些
    使用原生JavaScript实现:通过计算每一列的高度,将新的元素添加到高度最小的列中,从而实现瀑布流布局。 使用jQuer...
    99+
    2024-03-08
    JS
  • 聊聊Python私有属性与私有方法
    1、 场景定义私有属性是指在 Python 的面向对象开发过程中,对象的某些属性只想在对象的内部被使用,但不想在外部被访问到这些属性。即:私有属性是对象不愿意公开的属性。私有方法是指在 Python 的面向对象开发过程中,对象的某些方法或者...
    99+
    2023-05-14
    Python 私有属性 私有方法
  • SpringBoot属性注入的方式有哪些
    这篇文章给大家分享的是有关SpringBoot属性注入的方式有哪些的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、@Value注解注入属性SpringBoot默认可以将application.propertie...
    99+
    2023-06-25
  • JS的script标签属性有哪些
    本篇内容介绍了“JS的script标签属性有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!JS script标签有哪些属性:charse...
    99+
    2023-06-22
  • 私有属性/方法的访问
    在属性/方法名前有双下划线的,称为私有属性/方法,私有属性/方法外部不能直接访问, 一般访问类的私有属性,可以通过自身调用 使用了私有属性的公有方法 间接访问私有属性/方法, 但python中并没有真正意义的私有,可以通过 _类名__属性...
    99+
    2023-01-30
    属性 方法
  • JS实现网络请求的方式有哪些
    这篇文章将为大家详细讲解有关JS实现网络请求的方式有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。背景为了应对越来越多的测试需求,减少重复性的工作,有道智能硬件测试组基于 electron 开发了一系...
    99+
    2023-06-29
  • Spring Bean属性注入的方式有哪些
    这篇文章主要介绍“Spring Bean属性注入的方式有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Spring Bean属性注入的方式有哪些”文章能帮助大家解决问题。属性...
    99+
    2023-07-02
  • python中的私有属性和私有方法是什么
    这篇文章给大家介绍python中的私有属性和私有方法是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。私有权限面向对象三大特性:封装、继承、多态封装的意义:将属性和方法放到一起做为一个整体,然后通过实例化对象来处理;...
    99+
    2023-06-14
  • js event对象都有哪些属性
    JS事件对象具有以下一些属性:1. event.type:表示事件的类型。2. event.target:表示触发事件的元素。3. ...
    99+
    2023-09-15
    js
  • js中位置的相关属性有哪些
    今天小编给大家分享一下js中位置的相关属性有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一.Dom对象属性&m...
    99+
    2023-06-30
  • vue的实例属性有哪些
    vue中的实例属性有:1.$data属性,vur实例观察的数据对象;2.$options属性,当前vue实例的初始化选项;3.$slot属性,当前组件树的根vue实例;4.listeners属性,包含了父作用域中的时间监听器;5.$attr...
    99+
    2024-04-02
  • js继承的方式有哪些
    这篇文章主要介绍js继承的方式有哪些,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!原型链继承原型链继承是ECMAScript的主要继承方式。其基本思想就是通过原型继承多个引用类型的属性和方法。什么是原型链每个构造函数...
    99+
    2023-06-14
  • python基础知识之私有属性和私有方法
    私有权限 面向对象三大特性:封装、继承、多态 封装的意义: 将属性和方法放到一起做为一个整体,然后通过实例化对象来处理; 隐藏内部实现细节,只需要和对象及其属性和方法交互就...
    99+
    2024-04-02
  • JavaScript中Class私有属性与私有方法的示例分析
    小编给大家分享一下JavaScript中Class私有属性与私有方法的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!pr...
    99+
    2024-04-02
  • C++超详细讲解隐藏私有属性和方法的两种实现方式
    目录例子用抽象类解决问题用Pimpl风格解决问题总结参考在我们编写程序的时候,会将程序模块化,常见的就是用动态链接库的方式,然后导出函数接口或者类。而对于导出类的方式,作为模块的实现...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作