Object.keys返回私有属性

时间:2016-11-04 17:12:33

标签: javascript typescript knockout.js ecmascript-6 modifiers

我使用Typescript创建了class / viewModel。 我在这个类中创建了一个字段作为私有,以便在我尝试获取所有其他类属性时跳过它。

是不是我怎么能跳过私人财产呢?

ghci> throwE ['a'] `mplus` return () `mplus` throwE ['b'] :: ExceptT [Char] Identity ()
ExceptT (Identity (Right ()))
ghci> throwE ['a'] `mplus` throwE ['b'] :: ExceptT [Char] Identity ()
ExceptT (Identity (Left "ab"))

我班级的例子:

Object.keys(myObject).forEach(property => {
        //some stuff
     }
});

4 个答案:

答案 0 :(得分:3)

TypeScript像常规属性一样编译私有属性,私有性的强制执行仅在编译时完成,并且它们仍在运行时。

github上有很多请求要求私有属性即使在运行时也无法访问,但由于设计限制和/或哲学问题,这个问题尚未实现,而且可能永远不会实现。

您可以阅读一些设计讨论历史here

这意味着您必须使用自己的约定来处理此问题,例如在名称前加上下划线并在循环中对其进行过滤。

答案 1 :(得分:3)

private关键字仅影响TypeScript中的可见性,并且不会影响JS输出。

对于未在原型上定义的类属性,因此无法使用类属性装饰器进行修改,最直接的方法是对私有属性使用_命名约定:

class MyModel{
   ...
   private _secretField= ko.observable('');
}

...

Object.keys(myObject)
.filter(key => !(typeof key === 'string' && key.charAt(0) === '_'))
.forEach(property => {
        //some stuff
     }
});

答案 2 :(得分:0)

您可以使用从ES6开始的符号。 它可以存储值,并且不会出现在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] 

答案 3 :(得分:0)

TL; DR::使用private identifiers定义您的私有字段。这样,它们的可访问性也将在运行时得到加强。


正如已经指出的那样,可访问性仅由TypeScript编译器静态地(在编译时)强制执行。
因此,所有属性(公共或私有)均作为常规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。实际上,在定义了其声明类的相同词汇范围内,为具有私有标识符的类中的每个字段定义了对新WeakMap的引用。无论在何处访问私有字段,都可以通过调用使用给定映射(引用该字段时传递)的getter或setter函数来获取或设置给定键处的值来完成,该键是访问该字段的类的实例上。在getter和setter函数中也都进行了运行时检查,以便在使用未注册的接收器进行调用时抛出TypeError,以防止使用其他类型的实例或根本不使用任何实例来访问私有字段。