knockout.js 对象返回私有属性,

xpcnnkqh  于 2022-11-10  发布在  其他
关注(0)|答案(4)|浏览(165)

我用Typescript创建了class/viewModel。我将这个类中的一个字段设置为private,以便在我尝试获取所有其他类属性时跳过它。
这是正确的吗?我怎么能跳过我的私人财产?

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

我的类的例子:

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('');
}
2w2cym1i

2w2cym1i1#

private关键字只影响TypeScript中可见性,不影响JS输出
对于那些没有在原型上定义的类属性,因此不能用类属性装饰器修改,最直接的方法是对私有属性使用_命名约定:

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

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

whitzsjs2#

TypeScript像编译常规属性一样编译私有属性,私有性的实施仅在编译时完成,并且它们在运行时仍然存在。
在github上有很多要求使私有属性即使在运行时也不可访问,但由于设计限制和/或哲学问题,这还没有实现,也可能永远不会实现。
您可以阅读一些设计讨论历史记录here
这意味着您必须使用自己的约定来处理这个问题,例如,在名称前面加上下划线,并在循环中过滤它。

yvgpqqbh

yvgpqqbh3#

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

unhi4e5o4#

**TL;DR:**使用私有标识符来定义私有字段。这样,在运行时也会强制执行它们的可访问性。

正如已经指出的,可访问性只由TypeScript转发器静态地(在编译时)强制执行。
因此,所有的属性,不管是public还是private,都是作为普通的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代码的唯一原因。
因此,我们剩下的唯一解决方案是使用私有标识符。这是一个TypeScript特性,使得任何名称以#开头的字段不仅在编译时,甚至在运行时都被强制为私有。

class Foo {

    #bar = "Hello world"

    constructor() {
        console.log(this.#bar)
    }
}

console.log(Object.keys(new Foo()))

上面的示例可以在TypeScript Playground中进行测试。
这是如何实现的呢?您可能只需要看一下转换后的JavaScript代码,就会突然注意到一个WeakMap。实际上,对新WeakMap的引用是在定义声明类的同一词法作用域中为具有私有标识符的类中的每个字段定义的。无论在何处访问私有字段,这是通过调用使用给定Map的getter或setter函数来完成的(在引用该字段时传递)以获取或设置给定键处的值,它是访问字段的类的示例。在getter和setter函式中也会进行执行阶段检查,以便在以未注册的接收端呼叫时掷回TypeError,以防止以不同型别的执行严修或根本没有执行严修来存取私用字段。

相关问题