JavaScript 的对象构建和面向对象的编程模式
一个对象对外分享的,别人可以获取到的公开属性
不对外暴露的,别人不能随便获取的私有属性
静态属性,属于类,而不是单独属于对象的。
包含公开属性和私有属性。
如何创建私有属性?
与Java不一样,当用JavaScript创建的一个对象,无论是使用class、字面量、还是函数构造式,一般情况下,在定义了属性和方法后就可以公开调用,并没有限制。
用 # 符号创建私有属性,来定义一个私有的属性。
class WidgetD {
#appName;
constructor(){
this.#appName = "天气应用";
}
getName(){
return this.#appName;
}
}
var widget4 = new WidgetD();
console.log(widget4.appName); // 返回 undefined
console.log(widget4.getName()); // 返回 “天气应用”
在 # 问世之前,工程师们是怎么实现私有属性的。主要有闭包、WeakMap 和 Symbol 这三种方式。
用闭包和 IIFE 创建私有属性
首先,我们声明一个 WidgetE 的变量,然后再来创建一个立即被调用的函数式表达(IIFE),在这个表达里面,我们先给内部的 appName 变量赋值为“天气应用”。之后,在函数中我们再给 WidgetE 赋值,这里赋值的是一个对象,里面我们定义了 getName 的方法,它返回的就是外部函数的 appName。
// 对象字面量
var WidgetE;
(function(){
var appName = "天气应用";
WidgetE = {
getName: function(){
return appName;
}
};
}());
WidgetE.appName; // 返回 undefined
WidgetE.getName(); // 返回 “天气应用”
先定义一个函数,在里面声明一个变量 appName,然后创建一个 getName 的表达式函数,返回 appName。
// 构造函数
function WidgetF() {
var appName = "天气应用";
this.getName = function(){
return appName;
}
}
var widget6 = new WidgetF();
console.log(widget6.appName); // 返回 undefined
console.log(widget6.getName()); // 返回 “天气应用”
这个例子中还有一个问题,就是我们每次在创建一个新对象的时候,私有属性都会被重新创建一次,这样就会造成重复工作和冗余内存。解决这个问题的办法就是把通用的属性和功能赋值给 prototype,这样通过同一个构建者创建的对象,可以共享这些隐藏的属性。
function WidgetG() {
var appName = "天气应用";
this.getName = function(){
return appName;
}
}
WidgetG.prototype = (function(){
var model = "支持安卓";
return {
getModel: function(){
return model;
}
}
}());
var widget7 = new WidgetG();
console.log(widget7.getName()); // 返回 “天气应用”
console.log(widget7.getModel()); // 返回 “支持安卓”
用 WeakMap 创建私有属性
Set 用的是集合的数据结构,Map 用的是字典的数据结构。
我们首先声明了一个 WidgetG 变量。接下来,建立一个块级作用域,在这个作用域里,我们再声明一个 privateProps 的 WeakMap 变量。然后我们给 WidgetG 赋值一个函数声明,在里面给 WeakMap 的键名设置为 this,键值里面的 appName 为“天气应用”。下一步,我们基于 WidgetF 的 prototype 来创建一个 getName 方法,里面返回了 appName 的值。
var WidgetH;
{
let privateProps = new WeakMap();
WidgetH = function(){
privateProps.set(this,{appName : "天气应用"});
}
WidgetH.prototype.getName = function(){
return privateProps.get(this).appName;
}
}
var widget8 = new WidgetH();
console.log(widget8.appName); // 返回 undefined
console.log(widget8.getName()); // 返回 “天气应用”
用 Symbol 创建私有属性
和上个例子相似,这里我们建立了一个块级作用域,但区别是我们把 privateProps 从 WeakMap 换成了 Symbol 来实现私有属性。
var WidgetI;
{
let privateProps = Symbol();
WidgetI = function(){
this[privateProps] = {appName : "天气应用"};
}
WidgetI.prototype.getName = function(){
return this[privateProps].appName;
}
}
var widget9 = new WidgetI();
console.log(widget9.getName()); // 返回 “天气应用”
如何创建公开属性?
创建公开静态属性
static: 静态属性只能作用于 class 本身。
创建私有静态属性
其实就是把 # 符号和 static 关键词相加来使用。