Object.keys returns 私人财产
Object.keys returns private properties
我用 Typescript 创建了 class/viewModel。
我将此 class 中的一个字段设为私有,以便在我尝试获取所有其他 class 属性时跳过它。
这样对吗?如何跳过我的私人属性?
Object.keys(myObject).forEach(property => {
//some stuff
}
});
我的 class 示例:
class MyModel{
id: any = ko.observable('');
name: any = ko.observable('');
address: any = ko.observable('');
city: any = ko.observable('');
state: any = ko.observable('');
country: any = ko.observable('');
private secretField= ko.observable('');
}
TypeScript 像普通属性一样编译私有属性,私有性的强制执行只在编译时完成,它们在运行时仍然存在。
在 github 上有很多要求即使在运行时也无法访问私有属性,但由于设计限制 and/or 哲学问题,这尚未实现,而且可能永远不会实现。
您可以阅读一些设计讨论历史here。
这意味着您必须使用自己的约定来处理这个问题,例如在名称前加上下划线并在循环中过滤它。
private
关键字仅影响 TypeScript 中的可见性,不影响 JS 输出。
对于未在原型上定义的 class 属性,因此无法使用 class 属性 装饰器进行修改,最直接的方法是使用 _
私有属性的命名约定:
class MyModel {
// ...
private _secretField = ko.observable('');
}
Object.keys(myObject)
.filter(key => !(typeof key === 'string' && key.charAt(0) === '_'))
.forEach(property => {
// some stuff
});
从ES6开始可以使用Symbols。
它可以存储值并且不会出现在Object.keys结果
中
Js代码
const privateStuff = Symbol()
var obj = {
name: "Andrew",
age: 23,
[privateStuff]: "Don't show it"
}
var keys = Object.keys(obj);
keys.forEach((k)=>{console.log(k)});
//get value
var serverStuff=obj[privateStuff]
TL;DR: 使用 private identifiers 定义您的私有字段。这样,它们的可访问性也将在运行时强制执行。
正如已经指出的那样,可访问性仅由 TypeScript 转换器静态地(在编译时)强制执行。
因此,所有属性,无论是 public 还是私有属性,都作为正常的 JavaScript 属性发出。这里没有魔法,除了使用 Proxy
来捕获 ownKeys()
方法或使用 Object.defineProperties
而不是以 TypeScript 方式声明它们之外,您无法做任何事情来隐藏它们。对于后一种想法,我想出了一个例子:
class Foo {
constructor() {
Object.defineProperties(this, {
bar: {
enumerable: false,
value: "Hello world"
}
})
console.log((this as any).bar)
}
}
上面的例子可以在TypeScript Playground.
中测试
但是,我认为这样做是一种反模式,因为它破坏了所有 TypeScript 的安全性,这是选择它而不是仅仅写出 JavaScript 代码的唯一原因。
因此,我们剩下的唯一解决方案是使用 private identifiers。这是一个 TypeScript 特性,因此任何名称以 #
开头的字段都被强制为私有,不仅在编译时,甚至在运行时也是如此。
class Foo {
#bar = "Hello world"
constructor() {
console.log(this.#bar)
}
}
console.log(Object.keys(new Foo()))
上面的例子可以在TypeScript Playground.
中测试
这是如何运作的?好吧,您可能只是看一下转译后的 JavaScript 代码,您会突然注意到一个 WeakMap
。实际上,在 class 中的每个字段都定义了对新 WeakMap
的引用,每个字段都有一个私有标识符,在定义它们的声明 class 的同一词法范围内。无论在何处访问私有字段,都是通过调用 getter 或 setter 函数来完成的,该函数使用给定映射(在引用该字段时传递)来获取或设置给定键的值,这是class 访问字段的实例。在 getter 和 setter 函数中也会进行运行时检查,以便在使用未注册的接收器调用时抛出 TypeError
以防止使用的实例访问私有字段不同类型或根本没有实例。
我用 Typescript 创建了 class/viewModel。 我将此 class 中的一个字段设为私有,以便在我尝试获取所有其他 class 属性时跳过它。
这样对吗?如何跳过我的私人属性?
Object.keys(myObject).forEach(property => {
//some stuff
}
});
我的 class 示例:
class MyModel{
id: any = ko.observable('');
name: any = ko.observable('');
address: any = ko.observable('');
city: any = ko.observable('');
state: any = ko.observable('');
country: any = ko.observable('');
private secretField= ko.observable('');
}
TypeScript 像普通属性一样编译私有属性,私有性的强制执行只在编译时完成,它们在运行时仍然存在。
在 github 上有很多要求即使在运行时也无法访问私有属性,但由于设计限制 and/or 哲学问题,这尚未实现,而且可能永远不会实现。
您可以阅读一些设计讨论历史here。
这意味着您必须使用自己的约定来处理这个问题,例如在名称前加上下划线并在循环中过滤它。
private
关键字仅影响 TypeScript 中的可见性,不影响 JS 输出。
对于未在原型上定义的 class 属性,因此无法使用 class 属性 装饰器进行修改,最直接的方法是使用 _
私有属性的命名约定:
class MyModel {
// ...
private _secretField = ko.observable('');
}
Object.keys(myObject)
.filter(key => !(typeof key === 'string' && key.charAt(0) === '_'))
.forEach(property => {
// some stuff
});
从ES6开始可以使用Symbols。 它可以存储值并且不会出现在Object.keys结果
中Js代码
const privateStuff = Symbol()
var obj = {
name: "Andrew",
age: 23,
[privateStuff]: "Don't show it"
}
var keys = Object.keys(obj);
keys.forEach((k)=>{console.log(k)});
//get value
var serverStuff=obj[privateStuff]
TL;DR: 使用 private identifiers 定义您的私有字段。这样,它们的可访问性也将在运行时强制执行。
正如已经指出的那样,可访问性仅由 TypeScript 转换器静态地(在编译时)强制执行。
因此,所有属性,无论是 public 还是私有属性,都作为正常的 JavaScript 属性发出。这里没有魔法,除了使用 Proxy
来捕获 ownKeys()
方法或使用 Object.defineProperties
而不是以 TypeScript 方式声明它们之外,您无法做任何事情来隐藏它们。对于后一种想法,我想出了一个例子:
class Foo {
constructor() {
Object.defineProperties(this, {
bar: {
enumerable: false,
value: "Hello world"
}
})
console.log((this as any).bar)
}
}
上面的例子可以在TypeScript Playground.
中测试但是,我认为这样做是一种反模式,因为它破坏了所有 TypeScript 的安全性,这是选择它而不是仅仅写出 JavaScript 代码的唯一原因。
因此,我们剩下的唯一解决方案是使用 private identifiers。这是一个 TypeScript 特性,因此任何名称以 #
开头的字段都被强制为私有,不仅在编译时,甚至在运行时也是如此。
class Foo {
#bar = "Hello world"
constructor() {
console.log(this.#bar)
}
}
console.log(Object.keys(new Foo()))
上面的例子可以在TypeScript Playground.
中测试这是如何运作的?好吧,您可能只是看一下转译后的 JavaScript 代码,您会突然注意到一个 WeakMap
。实际上,在 class 中的每个字段都定义了对新 WeakMap
的引用,每个字段都有一个私有标识符,在定义它们的声明 class 的同一词法范围内。无论在何处访问私有字段,都是通过调用 getter 或 setter 函数来完成的,该函数使用给定映射(在引用该字段时传递)来获取或设置给定键的值,这是class 访问字段的实例。在 getter 和 setter 函数中也会进行运行时检查,以便在使用未注册的接收器调用时抛出 TypeError
以防止使用的实例访问私有字段不同类型或根本没有实例。