博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【javascript】私有化变量
阅读量:5357 次
发布时间:2019-06-15

本文共 3764 字,大约阅读时间需要 12 分钟。

之前的文章 瓜皮csdn把之前正确的排版,给全部打乱了。。。

----

js中如何像java一样,将实例变量设置为私有呢? 因为没有类似的关键字private

方法一: 

在ES6之前,我们是通过来完成封装的,看例子:

// 结构赋值和函数默认参数的使用function initStudent({name = '', id = null, address =''} = {}) {  let _name = name,    _id = id,    _address =address  return {    setName(name) {      _name = name    },    getName() {      return _name    },    setId(id) {      _id = id    },    getId() {      return _id    },    setAddress(address) {      _address = addredss    },    getAddress(){      return _address    },    toString() {      return `student' name is ${_name}, address is ${_address} ,id is ${_id}`    }  }}

 

这样的话,我们这样`var student = initStudent({id: '001', name: 'Kevin', address: 'somewhere'})`构造一个对象,由于闭包的关系,返回的对象关联了一个函数,这个函数引用了当前函数词法作用域外层也就是initStudent函数作用域的一个局部变量,尽管initStudent执行完毕但是由于存在这样一层引用,外层的作用域在内存中并没有释放掉,数据仍然存在内存中(如果不明白,简易去看下《js高程》的作用域链和闭包章节)。

这个对象 student 不能直接访问name属性,console.log(student.name) 的结果是 undefined

但是我们直接这样操作student.name = 'Kevin2', 成功了。。。然后 你比较student.name  和student.getName()是不同的。 这里我们优化一下代码:

// 结构赋值和函数默认参数的使用function initStudent({name = '', id = null, address =''} = {}) {  let _name = name,    _id = id,    _address =address  let obj =  {    setName(name) {      _name = name    },    getName() {      return _name    },    setId(id) {      _id = id    },    getId() {      return _id    },    setAddress(address) {      _address = addredss    },    getAddress(){      return _address    },    toString() {      return `student' name is ${_name}, address is ${_address} ,id is ${_id}`    }  }  const getErrorFun =function(prop) {    return function () {      throw new Error(`you cannot set ${prop} value directly, use setMethod`)    }  }  Object.defineProperties(obj , {    'name': {      set: getErrorFun('name')    },    'id': {      set: getErrorFun('id')    },    'address': {      set: getErrorFun('address')    },      })  return obj}

 

这样就不能直接设定name等属性了,而且外部也不能直接访问和设定,必须通过get set方法去操作。如果像遍历对象的属性的话,可以自己在返回的对象里面增加一个*[Symbol.iterator]的方法,这个方法是一个生成器。

 

方法二

es6的

因为Symbol函数每一次调用返回的结果都是不同的,Symbol('x') === Symbol('x') 的值false, 可以理解为每次都生产了一个uuid,我们利用这个特性。我们修改上面的代码 如下:

// 用Symbol来封装const _name = Symbol('name'),  _id = Symbol('id'),  _address = Symbol('address')class Student {  constructor({name = '', id = null, address =''} = {}) {    this[_name] = name    this[_id] = id    this[_address] = address  }  get name(){    return this[_name]  }  set name(name) {    this[_name] = name  }  get address(){    return this[_address]  }  set address(address) {    this[_address] = address  }  get id(){    return this[_id]  }  set id(id) {    this[_id] = id  }    }

这里用了getter setter设置属性的存储函数和获取函数,拦截该属性的默认set和get行为【我犯了一个错误,上面闭包的方式实现也可以用这个方法,但是我当时想的是模拟java里面私有属性的公共方法】,如果非要使用getName setName这种形式,其实也行,我们改一下代码:

const _name = Symbol('name'),  _id = Symbol('id'),  _address = Symbol('address')class Student {  constructor({name = '', id = null, address =''} = {}) {    this[_name] = name    this[_id] = id    this[_address] = address  }  get name(){    return this[_name]  }  set name(name) {    throw new Error('cannot set value directly, use setMethod')  }  getName(){    return this[_name]      }  setName(name){    this[_name] = name  }   }

我们通过创建一个实例,var s =  new Student({name: 'kevin', id: 'iook', address: 'somewhere'}) , s.name报错, 其实我们也可以将默认的getter函数给屏蔽掉,只能通过s.getName去获取。这样也完成了我们想要的。

 

其实这种方法和第一种类似,第一种通过闭包隐藏访问途径, 第二种直接隐藏key的名字,有途径也没有用【但是实际上是还是可以通过Object.getOwnPropertySymbols(obj)来访问】。

 

方法三!!

用map来实现,wow,这段代码来自

const privateMap = new WeakMap()const Point = class{  constructor(x, y) {    privateMap.set(this, {x, y})   }  get length(){    let { x, y } = privateMap.get(this)    return Math.sqrt(x ** 2 + y ** 2)  }}

参考这段代码 然后稍微改下就行了! ,这种方式,既没有告诉你门牌号,也没有找到门牌号的路径,除非自己暴露出来。。有没有觉得很赞呢。。

 

转载于:https://www.cnblogs.com/dongguapifly/p/10627090.html

你可能感兴趣的文章
泛型子类_属性类型_重写方法类型
查看>>
练习10-1 使用递归函数计算1到n之和(10 分
查看>>
Oracle MySQL yaSSL 不明细节缓冲区溢出漏洞2
查看>>
Code Snippet
查看>>
zoj 1232 Adventure of Super Mario
查看>>
组合数学 UVa 11538 Chess Queen
查看>>
oracle job
查看>>
Redis常用命令
查看>>
[转载]电脑小绝技
查看>>
windos系统定时执行批处理文件(bat文件)
查看>>
thinkphp如何实现伪静态
查看>>
BZOJ 2243: [SDOI2011]染色( 树链剖分 )
查看>>
BZOJ 1925: [Sdoi2010]地精部落( dp )
查看>>
c++中的string常用函数用法总结!
查看>>
[DLX精确覆盖+打表] hdu 2518 Dominoes
查看>>
SuperMap iServerJava 6R扩展领域开发及压力测试---判断点在那个面内(1)
查看>>
Week03-面向对象入门
查看>>
一个控制台程序,模拟机器人对话
查看>>
Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(上篇——纯前端多页面)
查看>>
我的PHP学习之路
查看>>