js封装私有属性(闭包的应用)
2021-01-20 本文已影响0人
兮木兮木
私有属性就是不希望被外部访问的,要通过封装者的方法去访问,下面总结几种常见的封装方式
-
普通方式,这种方式就是一般的封装,私有属性不通过封装者的方法也能访问
function Person() { this.name = 'Eric' } Person.prototype = { getName() { return this.name; }, setName(name) { this.name = name } } let p = new Person() console.log(p.getName()) //Eric p.setName('Amy') console.log(p.getName()) //Amy console.log(p.name) // Amy 直接通过对象的属性也能访问到,没有隐藏性 p.name = '张三' console.log(p.name)// 张三 可直接通过对象的属性去修改
-
约定的命名方式,其实也是普通方式,只不过私有属性用约定好的规则命名,一般是在变量前加下划线(_)
function Person() { this._name = 'Eric' //加上下划线,表示私有属性 } Person.prototype = { getName() { return this._name; }, setName(name) { this._name = name } } let p = new Person() console.log(p.getName()) //Eric p.setName('Amy') console.log(p.getName()) //Amy console.log(p._name) // Amy 直接通过对象的属性也能访问到,没有隐藏性 p._name = '张三' console.log(p._name)// 张三 可直接通过对象的属性去修改
-
利用闭包实现变量私有化
function Person() { var name = 'Eric' //私有属性,通过实例对象不能访问 this.getName = function() { return name; } this.setName = function(value) { name = value } } Person.prototype = { getNameTest() { return this.name; }, } let p = new Person() console.log(p.getName()) // Eric p.setName('Amy') console.log(p.getName()) //Amy //直接通过实例对象访问 console.log(p.name) // undefined //通过原型上的方法访问时 console.log(p.getNameTest())// undefined
以上其实形成了一个闭包,
p
的引用指向了实例对象,而实例对象里的getNam
e与setName
方法里用到了Person
函数的局部变量name
。关于闭包更详细的介绍可以自行百度。还有一点,上面的
getName
,setName
方法既可以访问私有属性,也可以访问实例对象的共有属性,成为特权方法。一个原则是,不需要直接访问私有属性的方法应该被定义在原型链中,因为过多的特权方法会增加内存的消耗,每一个实例都会在内存中储存一个特权方法的副本。
-
通过 Symbol 的唯一性,把变量名用Symbol生成,这样对方就不知道该变量了,不知道变量名,也就无法通过实例对象直接访问了,也可以说是隐藏了私有变量
const secret = Symbol('secret') function Person() { this[secret] = 'Eric' } Person.prototype = { getName() { return this[secret]; }, setName(name) { this[secret] = name } } let p = new Person() console.log(p.getName()) //Eric p.setName('Amy') console.log(p.getName()) //Amy //在其他地方创建一个Symbol const secret = Symbol('secret') console.log(p[secret]) // undefined 无法访问