JavaScript 如何创建一个私有变量
Closures, Symbols, WeakMaps, class private fields, and Proxies是一些可以用来在JavaScript中创建私有变量的技术。每种技术都有好处和坏处,所以选择一个最适合你的要求的技术是很关键的。
像其他许多编程语言一样,JavaScript也有私有变量和公共变量的概念。私有变量只能被同属一个范围的代码访问和改变,但公共变量可以被任何代码访问和改变。让我们来看看在JavaScript中创建私有变量的不同技术。
使用闭合
闭包方法是在JavaScript中创建私有变量的一种方法。如果一个函数可以访问定义在其父级函数范围内的变量,甚至在父级函数完成并返回之后,它就是一个闭包。我们可以在一个函数中定义一个变量,使其成为一个私有变量,只能由该函数中的代码访问。
例子
<html>
<body>
<div id="demo"></div>
<script>
function createPrivateVariable() {
let privateVariable = "This is a private variable";
return {
getValue: function () {
return privateVariable;
},
setValue: function (value) {
privateVariable = value;
},
};
}
let privateVar = createPrivateVariable();
document.getElementById("demo").innerHTML = privateVar.getValue();
</script>
</body>
</html>
上面例子中的函数createPrivateVariable返回一个具有getValue和setValue方法的对象。这些方法可以检索或改变在父函数中声明的privateVariable 的值,因为它们可以访问它。如果你试图从函数外部访问privateVariable,将会发生引用错误。
使用符号数据类型
使用 Symbol 数据类型是创建私有变量的第二种方法。符号可以被用作属性键,因为它们是独特的、非字符串的标识符。由于它们是唯一的,所以不能轻易被外部程序访问或改变。
let privateVariable = Symbol();
let obj = {
[privateVariable]: "This is a private variable"
};
console.log(obj[privateVariable]);
例子
我们可以使用上述代码,如下所示
<html>
<body>
<div id="demo"></div>
<script>
let privateVar = Symbol();
let obj = {
[privateVar]: "This is a private variable"
};
Object.defineProperty(obj, 'getValue', {
get: function() {
return obj[privateVar];
}
});
document.getElementById("demo").innerHTML = obj.getValue;
</script>
</body>
</html>
在这个例子中,一个名为privateVariable的符号已经被定义,并被用作一个对象的属性键。因为它是一个符号,该属性的值不能通过使用点符号获得,但它可以通过使用方括号符号通过对象进行访问。
使用WeakMaps
WeakMaps可以作为第三种方法来构建私有变量。JavaScript引擎只弱化引用WeakMap中的键值对,这让你可以将一个对象与一个键联系起来。这使得错误地维护对私有变量的引用变得更加困难,因为如果没有其他对键的引用,垃圾收集器会销毁键值对。
例子
<html>
<body>
<div id="demo"></div>
<script>
let privateVariables = new WeakMap();
let obj = {};
privateVariables.set(obj, "This is a private variable");
document.getElementById("demo").innerHTML = privateVariables.get(obj);
</script>
</body>
</html>
在这个例子中,我们做了一个名为privateVariables的WeakMap,我们用它来保存一个对象的私有变量。一旦使用set()方法将私有变量链接到对象上,get()方法就被用来获取该私有变量。然而,该私有变量不能从形成对象的范围之外被访问,因为只有当你拥有对该对象的引用时才能访问它。
使用面向对象的类语法
使用面向对象的类语法也可以用来创建私有变量。JavaScript的class关键字使我们能够定义类,作为对象的模板。一个类可以定义一个变量,在变量名前加上#符号来生成私有变量;这是一个实验性的功能,表示一个私有变量。我们不建议在生产代码中使用这个功能,因为它目前还没有得到广泛的支持。
例子
<html>
<body>
<p id="output"></p>
<script>
class MyClass {
#privateVariable = "This is a private variable";
getValue() {
return this.#privateVariable;
}
setValue(value) {
this.#privateVariable = value;
}
}
let obj = new MyClass();
document.getElementById("output").innerHTML = obj.getValue(); // "This is a private variable"
obj.setValue("New value");
document.getElementById("output").innerHTML = obj.getValue(); // "New value"
</script>
</body>
</html>
在这个例子中,一个名为 MyClass 的类已经被构建,使用了私有变量#privateVariable、getValue和setValue。 如果类外的方法试图访问一个只能由类内的方法访问的私有变量,就会发生引用错误。
使用代理对象
最后,使用代理对象是构建私有变量的另一种选择。一个可以用来拦截或改变其他对象行为的对象被称为代理。你可以通过将一个对象包围在一个代理对象中来制造一个只能由拥有代理对象的代码访问的私有变量。
例子
<html>
<body>
<div id="demo"></div>
<script>
let privateVariable = "This is a private variable-proxy obj.";
let handler = {
get: function (target, name) {
if (name === "privateVariable") {
return privateVariable;
}
},
set: function (target, name, value) {
if (name === "privateVariable") {
privateVariable = value;
}
},
};
let obj = new Proxy({}, handler);
document.getElementById("demo").innerHTML = obj.privateVariable;
</script>
</body>
</html>
在这个例子中,已经建立了一个带有getter和setter方法的处理程序的Proxy。这些方法可以检索或改变定义在Proxy之外的私有变量的值,并且可以访问它。然而,由于引用错误,该私有变量将不能从Proxy外部访问。