Javascript - 如何向对象构造函数添加属性
Javascript - how do you add properties to an object constructor function
如何在 JavaScript 中向构造函数添加属性?例如。如果我有以下功能。
function Hotel(name)
{
this.name = name;
};
var hotel1 = new Hotel('Park');
我可以添加一个"局部"变量,该变量可以在类中本地使用,就好像它是私有的一样,使用相同的符号使用关键字"this"。当然,它不会是私有的,因为创建的对象将能够正确使用它?
我可以做这样的事情吗?我是使用 this
关键字还是使用 var
关键字是哪一个?我在底部的函数构造函数上有示例 2
1. var numRooms = 40;
2. this.numRooms = 40;
3. numRooms : 40,
function Hotel(name)
{
this.name = name;
this.numRooms = 40;
};
我知道,如果我想要对象构造函数中的函数,我需要使用this
词。正如我上面问的那样,这也适用于正常变量吗?
function Hotel(name)
{
this.name = name;
this.numRooms = 40;
this.addNumRoomsPlusFive = function()
{
return this.numRooms + 5;
}
};
您可以简单地将私有变量添加到构造函数中:
function Hotel(name) {
var private = 'private';
this.name = name;
};
但是,如果您在没有new
运算符的情况下使用 Hotel
函数,则附加到this
的所有属性和函数都将成为全局属性和函数。
function Hotel(name) {
var private = 'private';
this.name = name;
};
var hotel = Hotel('test');
console.log(name); // test
最好在构造函数中返回一个对象:
function Hotel(name) {
var
private_var = 'private',
private_func = function() {
// your code
};
retur {
name: 'name',
public_func: private_func
}
};
var hotel = Hotel('test');
console.log(name); // undefined
因此,如果您使用Hotel
构造函数而不使用运算符new
则不会创建全局变量。仅当返回值是对象时,才可以执行此操作。否则,如果您尝试返回任何不是对象的内容,构造函数将继续其常规行为并返回 this
。
我可以添加一个"局部"变量,该变量可以在类中本地使用,就好像它是私有的一样,使用相同的符号使用关键字"this"。
是的,我们能:
// API implementation in the library
function Hotel(name) {
// only our library code knows about the actual value
const numRooms = 'privateNoRoomsVar';
this.name = name;
this[numRooms] = 40;
this.addNumRoomsPlusFive = function() {
return this[numRooms] + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
// also, users don't have access to 'numRooms' variable so they can't use hotel[numRooms].
如果用户查看源代码并找出值privateNoRoomsVar
,那么他们可能会滥用 API。
为此,我们需要使用symobls:
// API implementation in the library
function Hotel(name) {
// no one can duplicate a symbol so the variable is really private
const numRooms = Symbol();
this.name = name;
this[numRooms] = 40;
this.addNumRoomsPlusFive = function() {
return this[numRooms] + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
// there is no way users will get access to the symbol object so the variable remains private.
<小时 />
#privateField,所有浏览器都支持私有类功能,因此我们不必再担心这一点。
// API implementation in the library
class Hotel {
// private field
#numRooms = 40;
constructor(name) {
this.name = name;
}
addNumRoomsPlusFive() {
return this.#numRooms + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
//console.log('hotel.numRooms =', hotel.#numRooms); // throws error
Javascript 历来从其他对象的原型创建对象。这是EMCA2015的结果,即您具有指定对象的类的独特语法。顺便说一句,如果您将鼠标悬停在该链接中的表格上,它会给出该功能实现的日期。
由 new 运算符创建的 javascript 对象或多或少是一个关联数组的组合(你用 let avar={};
做的(,它可以访问它定义的函数级范围。数组的键是其属性。根据其创建者的说法,Javascript被创建为一种易于使用的程序语言,没有类型层次结构。它实现这一点的方法之一是或多或少地将其映射类型视为等效于面向对象的编程语言描述的原型对象。
在 2022 年添加属性
function AProtoype(arg1, arg2, arg3){
//this defines a property
this.pa=arg1;
/* unicorns in this section */
let x = 1;
/*
a getter which has the same syntax as a property
but returns x from the scope which it references and
not the object.
*/
get getx() => x;
}
let object = new AProtoype(2,3,4);
等效于以下代码,用于数据访问,而不是继承和类型。new 运算符还会在用于这些目的的对象上设置变量。
function NewObject(arg1, arg2, arg3){
let prototype = {};
/*dragons in this section, as you are not using the this keyword to accomplish things*/
prototype.pa = arg1;
Object.defineProperty(prototype, "getx", {get:()=>x});
return prototype;
}
//If you do this instead of using the new operator it is an anti-pattern.
//And like all anti-patterns: "But it works!"
let object = NewObject(2,3,4);
相关属性定义方法在某种意义上早在2010年、2011年就得到了支持。我没有当时的当代消息来源来确认你是否可以完成我正在做的事情,你只有在所有其他方法都失败并且需要在 Internet Explorer 9 上运行时才想要。如果所有其他方法都失败了,您可能需要阅读 Object.create 的文档,这也很有趣,因为或多或少地提供了一个 API 来创建新对象。
现在,为了享受有趣的时光和恐怖,您还可以定义一个返回 this 的函数,并使用该函数的等效绑定获取对象。当它是全局范围内的对象,并且您重命名该对象的属性时,恐怖就会到来;因为Javascript将通过愉快地写下它发现的任何内容来解决名称冲突,如果可以的话。然后,您可以使用它来重新实现原型模式,javascripts new 运算符是在概念上构建的,为了科学。
当您在 Javascript 中使用"构造函数"时,使用 this
关键字在实例上定义的任何属性都将变为公共属性。这是不可避免的,因为Javascript对象没有私有属性的概念 - 如果存在,可以直接作为object.property
访问。
例如,如果您尝试按照以下代码片段进行操作,在 Java 或 C# 中使用私有变量模拟典型的 getter/setter 模式(请注意,即使这有效,这不是惯用的 Javascript(:
function MyObject(privateVar) {
this.privateVar = privateVar;
}
MyObject.prototype.getVar = function() {
return this.privateVar;
};
MyObject.prototype.setVar = function(newVal) {
this.privateVar = newVal;
};
然后,虽然您确实可以使用 getter 和 setter 来按预期执行,但您也可以直接访问和设置私有变量!示范:
function MyObject(privateVar) {
this.privateVar = privateVar;
}
MyObject.prototype.getVar = function() {
return this.privateVar;
};
MyObject.prototype.setVar = function(newVal) {
this.privateVar = newVal;
};
var obj = new MyObject(1);
// using public getter/setter
console.log(obj.getVar()); // 1
obj.setVar(2);
console.log(obj.getVar()); // 2
// using private variable directly - not intended to work
console.log(obj.privateVar); // 2
obj.privateVar = 3;
console.log(obj.getVar()); // 3 (using public API to get it to show that the direct update to the private variable also affects the intended public methods)
虽然有一种方法可以模仿私有变量的影响。它们实际上不是对象属性 - 因为,正如我刚刚演示的那样,这些属性本质上是公共的 - 但可以通过以下方式模拟:
- 根本不使用"构造函数",而是碰巧返回对象的常规函数。无论如何,这就是构造函数真正做的所有事情 - JS中的区别只是语法上的,当你调用函数时,你不需要使用
new
关键字。(尽管您仍然可以,但如果您真的愿意 - 任何返回对象的函数都可以使用new
调用,并且行为方式与不使用对象相同,尽管性能可能会受到一些影响,因为该函数随后会构造一个全新的对象并将其丢弃。请参阅 MDN 了解这些陈述的理由,特别是第 4 步。 - 在此函数中,使用常规变量作为私有变量。通过简单的范围规则,这个变量将完全无法从外部访问,但你仍然可以让返回的对象通过闭包的"魔术"保留对它的访问权限。
这是上面翻译成此过程的getter/setter示例,以及它工作的演示。(不过,我赶紧再次补充,这在Javascript中不会被视为惯用代码。
function makeObjectWithPrivateVar(privateVar) {
function getPrivateVar() {
return privateVar;
}
function setPrivateVar(newVal) {
privateVar = newVal;
}
return { getPrivateVar, setPrivateVar };
}
var obj = makeObjectWithPrivateVar(1);
// getter
console.log(obj.getPrivateVar()); // 1
// setter
obj.setPrivateVar(2);
// getter again to observe the change
console.log(obj.getPrivateVar()); // 2
// but how could we access the private var directly??
// answer, we can't
console.log(obj.privateVar); // undefined
console.log(privateVar); // ReferenceError, privateVar is not in scope!
最后请注意,在现代 Javascript 中很少使用这种风格的基于函数的构造函数,因为 class
关键字可以更轻松地模仿传统的基于类的语言,如 Java,如果你真的愿意的话。特别是,更新的浏览器直接支持私有属性(您只需要在属性名称前面加上#
(,因此将初始代码片段转换为类并使用此功能即可正常工作:
class MyObject {
#privateVar
constructor(privateVar) {
this.#privateVar = privateVar;
}
getVar() {
return this.#privateVar;
}
setVar(newVal) {
this.#privateVar = newVal;
}
}
var obj = new MyObject(1);
// using public getter/setter
console.log(obj.getVar()); // 1
obj.setVar(2);
console.log(obj.getVar()); // 2
// using private variable directly - now doesn't work
console.log(obj.privateVar); // undefined, it doesn't exist
// console.log(obj.#privateVar); // error as it's explicitly private, uncomment to see error message
通常使用闭包执行:
var Hotel = (function() {
var numrooms=40; // some kind of private static variable
return function(name) { // constructor
this.numrooms = numrooms;
this.name = name;
};
}());
var instance = new Hotel("myname");
- 正在向构造函数添加作用域变量
- Javascript - 如何向对象构造函数添加属性
- 向构造函数或原型添加属性之间的区别
- 在定义了构造函数之后,是否可以将实例属性添加到JavaScript原型中
- 在 JavaScript 中隐式地将方法添加到构造函数的原型中
- 是否存在替换Javascript构造函数的问题'原型,而不是添加到原型中
- 当函数绑定在构造函数中时,如何在 ES6 React 中向事件处理程序添加参数
- 如何在 Javascript 中添加和调用来自构造函数的函数(使用 JQuery)
- 为什么方法总是添加到原型中,而不是在构造函数中定义
- 为什么你不应该向JavaScript构造函数添加功能,而是通过原型
- 将通过原型计算的可观察对象添加到构造函数中
- 将方法添加到操作数组的构造函数
- 用javascript将构造函数添加回object.create的最佳方式
- 将get和set添加到构造函数的原型链中
- 是否可以在JS对象中添加一个默认函数(构造函数)
- 是否有必要为javascript类中的构造函数添加分号
- 为什么实例没有't在没有prototype关键字的情况下继承添加到构造函数的属性
- 使用构造函数添加方法
- 如何使用Object.prototype将函数添加到对象构造函数
- 直接向JavaScript构造函数添加方法和使用prototype添加方法有什么区别