在TypeScript中获取并设置


656

我正在尝试为属性创建get和set方法:

private _name: string;

Name() {
    get:
    {
        return this._name;
    }
    set:
    {
        this._name = ???;
    }
}

设置值的关键字是什么?


12
下划线和PascalCase与Typescript编码准则
Niels Steenbeek

2
@NielsSteenbeek,您好-遵循TypeScript贡献者指南以及属性和后备字段,您最终会遇到名称冲突。建议的方法是什么?
约旦

也许: typescript private name: string; getName() { get: { return this.name; } set: { this.name = ???; } }
乔丹

7
好吧,那些Typescript编码指南没有吸引力。我只会在强制条件下使用它们(例如,我被要求这样做)。
Thomas Eding

14
@NielsSteenbeek:您读过那个文件吗?“这不是TypeScript社区的规范性指南”
Jonathan Cast

Answers:


1080

TypeScript使用类似于ActionScript3的getter / setter语法。

class foo {
    private _bar: boolean = false;
    get bar(): boolean {
        return this._bar;
    }
    set bar(value: boolean) {
        this._bar = value;
    }
}

这将使用ECMAScript 5 Object.defineProperty()功能生成此JavaScript 。

var foo = (function () {
    function foo() {
        this._bar = false;
    }
    Object.defineProperty(foo.prototype, "bar", {
        get: function () {
            return this._bar;
        },
        set: function (value) {
            this._bar = value;
        },
        enumerable: true,
        configurable: true
    });
    return foo;
})();

所以要使用它

var myFoo = new foo();
if(myFoo.bar) {         // calls the getter
    myFoo.bar = false;  // calls the setter and passes false
}

但是,要完全使用它,必须确保TypeScript编译器以ECMAScript5为目标。如果您正在运行命令行编译器,则使用如下--target标记:

tsc --target ES5

如果使用的是Visual Studio,则必须编辑项目文件以将标志添加到TypeScriptCompile构建工具的配置中。您可以在这里看到:

就像@DanFromGermany在下面建议的那样,如果您只是在读写本地属性(例如)foo.bar = true,那么拥有一对setter和getter对就太过了。如果需要在读取或写入属性时执行某些操作(例如日志记录),则以后可以随时添加它们。


59
好答案。另外,请注意,与C#不同,属性当前未在TypeScript(v0.9.5)中虚拟化。在派生类中实现“ get bar()”时,将替换父级中的“ get bar()”。含义包括无法从派生的访问器调用基类访问器。这仅适用于属性-方法的行为符合您的预期。见SteveFenton答案在这里:stackoverflow.com/questions/13121431/...
大卫Cuccia

14
我对下划线有点困惑。Typescript约定说不要对私人变量使用下划线?但在这种情况下,我们必须使用下划线-否则我们将在私人和公共“酒吧”之间发生冲突
Kokodoko

4
使用下划线是私有财产的个人偏好。但是,我相信您是对的,因为我们希望该属性的名称与getter / setter方法的名称不同。
Ezward '16

3
为什么使用myFoo.bar = true代替myFoo.bar(true);myFoo.setBar(true);
Daniel W.

6
@DanFromGermany一个属性是一对“获取”和“设置”方法的“语法糖”。Microsoft从Visual Basic继承了属性的概念,并将其继承到.NET语言,例如C#和VB.NET。例如,请参见属性(《 C#编程指南》)。属性简化了访问对象状态的过程,并且(我认为)消除了必须处理“获取/设置”方法对的“麻烦”。(或者有时只有希望获得不变性的“获取”方法。)
DavidRR

112

Ezward已经提供了一个很好的答案,但是我注意到其中一条评论询问如何使用它。对于像我这样偶然遇到此问题的人,我认为在Typescript网站上获得有关吸气剂和塞脂剂的官方文档的链接会很有用,因为它可以很好地解释这一点,希望它会始终保持最新,因为更改会不断并显示用法示例:

http://www.typescriptlang.org/docs/handbook/classes.html

特别是,对于那些不熟悉它的人,请注意,不要将“ get”一词包含在对getter的调用中(对于setter来说也是如此):

var myBar = myFoo.getBar(); // wrong    
var myBar = myFoo.get('bar');  // wrong

您应该简单地这样做:

var myBar = myFoo.bar;  // correct (get)
myFoo.bar = true;  // correct (set) (false is correct too obviously!)

给一个像这样的课程:

class foo {
  private _bar:boolean = false;

  get bar():boolean {
    return this._bar;
  }
  set bar(theBar:boolean) {
    this._bar = theBar;
  }
}

然后将调用私有“ _bar”属性的“酒吧”吸气剂。


如果我想用属性替换公共类级别的var,是否可以直接使用而不用担心的直接替换?换句话说,如果我对一个访问器和一个二传手进行回归测试,我可以认为它成功吗?还是在某些情况下它不能与var完全一样,我需要测试使用此var / prop的所有100个地方?
亚当·普洛彻

我想知道是否存在使用下划线区分属性名称与getter或setter方法的解决方法。在一个过程中,我正在做他们说下划线不是首选,但没有其他选择。

1
@cham您不必在这里使用下划线...如果需要,可以调用私有变量notbar。
罗伯特·麦基

58

这是一个工作示例,应该为您指明正确的方向:

class Foo {
    _name;

    get Name() {
        return this._name;
    }

    set Name(val) {
        this._name = val;
    }
}

JavaScript中的getter和setter只是正常功能。设置器是一个函数,它接受一个参数,该参数的值是要设置的值。


30
需要明确的是,不需要属性,getter和setter为static
Drew Noakes

1
变量引用仍然是静态的。Foo._name应该替换为this._name
Johannes

6

你可以写这个

class Human {
    private firstName : string;
    private lastName : string;

    constructor (
        public FirstName?:string, 
        public LastName?:string) {

    }

    get FirstName() : string {
        console.log("Get FirstName : ", this.firstName);
        return this.firstName;
    }
    set FirstName(value : string) {
        console.log("Set FirstName : ", value);
        this.firstName = value;
    } 

    get LastName() : string {
        console.log("Get LastName : ", this.lastName);
        return this.lastName;
    }
    set LastName(value : string) {
        console.log("Set LastName : ", value);
        this.lastName = value;
    } 

}

2
为什么在构造函数中公开?
MuriloKunze 2012年

17
是的,此代码中的构造函数不能公开。public这里定义重复成员。
orad 2013年

2
您可以编写它,但无法编译
贾斯汀

3

TS提供了getter和setter,它们使对象属性可以更好地控制如何在对象外部访问(getter)或更新(setter)它们。代替直接访问或更新属性,而是调用代理函数。

例:

class Person {
    constructor(name: string) {
        this._name = name;
    }

    private _name: string;

    get name() {
        return this._name;
    }

    // first checks the length of the name and then updates the name.
    set name(name: string) {
        if (name.length > 10) {
            throw new Error("Name has a max length of 10");
        }

        this._name = name;  
    }

    doStuff () {
        this._name = 'foofooooooofoooo';
    }


}

const person = new Person('Willem');

// doesn't throw error, setter function not called within the object method when this._name is changed
person.doStuff();  

// throws error because setter is called and name is longer than 10 characters
person.name = 'barbarbarbarbarbar';  

1

这与创建通用方法非常相似,只需将关键字保留getset放在开头即可。

class Name{
    private _name: string;

    getMethod(): string{
        return this._name;
    }

    setMethod(value: string){
        this._name = value
    }

    get getMethod1(): string{
        return this._name;
    }

    set setMethod1(value: string){
        this._name = value
    }
}

class HelloWorld {

    public static main(){

        let test = new Name();

        test.setMethod('test.getMethod() --- need ()');
            console.log(test.getMethod());

        test.setMethod1 = 'test.getMethod1 --- no need (), and used = for set ';
            console.log(test.getMethod1);
    }
}
HelloWorld.main();

在这种情况下,您可以跳过返回类型 get getMethod1() {

    get getMethod1() {
        return this._name;
    }

1

我想我可能会明白为什么会如此困惑。在您的示例中,我们希望使用getter和setter _name。但是我们可以通过为不相关的类变量创建getter和setter来实现这一点Name

考虑一下:

class Car{
    private tiresCount = 4;
    get yourCarTiresCount(){
        return this.tiresCount ;
    }
    set yourCarTiresCount(count) {
        alert('You shouldn't change car tire count')
    }
}

上面的代码执行以下操作:

  1. getsetyourCarTiresCount而不是tiresCount)创建getter和setter 。

吸气剂是:

function() {
    return this.tiresCount ;
}

设置者是:

function(count) {
    alert('You shouldn't change car tire count');
}

意思是,每次我们做new Car().yourCarTiresCount,getter都会运行。并且为每个new Car().yourCarTiresCount('7')二传手运行。

  1. 为private 间接创建getter,而不是setter tireCount

0

如果您正在寻找在任何对象(非类)上使用get和set的方法,Proxy 可能会很有用:https : //developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

const target = {
  message1: "hello",
  message2: "everyone"
};

const handler3 = {
  get: function (target, prop, receiver) {
    if (prop === "message2") {
      return "world";
    }
    return Reflect.get(...arguments);
  },
};

const proxy3 = new Proxy(target, handler3);

console.log(proxy3.message1); // hello
console.log(proxy3.message2); // world

注意:请注意,这是旧版浏览器不支持的新API,并且必须执行polifill


-6

如果您正在使用TypeScript模块并尝试添加导出的getter,则可以执行以下操作:

// dataStore.ts
export const myData: string = undefined;  // just for typing support
let _myData: string;  // for memoizing the getter results

Object.defineProperty(this, "myData", {
    get: (): string => {
        if (_myData === undefined) {
            _myData = "my data";  // pretend this took a long time
        }

        return _myData;
    },
});

然后,在另一个文件中,您将拥有:

import * as dataStore from "./dataStore"
console.log(dataStore.myData); // "my data"

8
那是可怕的建议。特别是this必须在模块的顶级范围内未定义。您可以改用exports它,但完全不要这样做,因为实际上可以保证会引起兼容性问题
Aluan Haddad
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.