lấy và thiết lập trong TypeScript


656

Tôi đang cố gắng tạo phương thức get và set cho một thuộc tính:

private _name: string;

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

Từ khóa để đặt giá trị là gì?


12
Dấu gạch dưới và PascalCase xung đột với hướng dẫn mã hóa Bản mô tả: github.com/Microsoft/TypeScript/wiki/Coding-guferences
Niels Steenbeek

2
Xin chào @NielsSteenbeek - làm theo hướng dẫn của người đóng góp TypeScript với các thuộc tính và các trường sao lưu mà bạn kết thúc bằng xung đột tên. Cách tiếp cận được đề xuất là gì?
Jordan

Có lẽ: typescript private name: string; getName() { get: { return this.name; } set: { this.name = ???; } }
Jordan

7
Điều tốt là các hướng dẫn mã hóa Typecript là không hấp dẫn. Tôi sẽ chỉ sử dụng chúng dưới sự ép buộc (ví dụ: tôi được trả tiền để làm như vậy).
Thomas Eding

14
@NielsSteenbeek: bạn đã đọc tài liệu đó chưa? "Đây KHÔNG phải là một hướng dẫn quy định cho cộng đồng TypeScript"
Jonathan Cast

Câu trả lời:


1079

TypeScript sử dụng cú pháp getter / setter giống như ActionScript3.

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

Điều đó sẽ tạo ra JavaScript này, sử dụng Object.defineProperty()tính năng ECMAScript 5 .

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

Vì vậy, để sử dụng nó,

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

Tuy nhiên, để sử dụng nó, bạn phải đảm bảo trình biên dịch TypeScript nhắm mục tiêu ECMAScript5. Nếu bạn đang chạy trình biên dịch dòng lệnh, hãy sử dụng --targetcờ như thế này;

tsc --target ES5

Nếu bạn đang sử dụng Visual Studio, bạn phải chỉnh sửa tệp dự án của mình để thêm cờ vào cấu hình cho công cụ xây dựng TypeScriptCompile. Bạn có thể thấy điều đó ở đây :

Như @DanFromGermany gợi ý dưới đây, nếu bạn chỉ đơn giản là đọc và viết một thuộc tính cục bộ như thế foo.bar = true, thì việc có một cặp setter và getter là quá mức cần thiết. Bạn luôn có thể thêm chúng sau nếu bạn cần làm gì đó, như đăng nhập, bất cứ khi nào tài sản được đọc hoặc viết.


59
Câu trả lời tốt đẹp. Ngoài ra, lưu ý rằng, không giống như trong C #, các thuộc tính hiện không được ảo hóa trong TypeScript (v0.9.5). Khi bạn triển khai "get bar ()" trong lớp dẫn xuất, bạn sẽ thay thế "get bar ()" trong phần cha mẹ. Hàm ý bao gồm không thể gọi trình truy cập lớp cơ sở từ trình truy cập dẫn xuất. Điều này chỉ đúng với các thuộc tính - các phương thức hoạt động như bạn mong đợi. Xem câu trả lời của SteveFenton tại đây: stackoverflow.com/questions/13121431/
Kẻ

14
Tôi hơi bối rối về gạch dưới. Quy ước đánh máy nói không sử dụng dấu gạch dưới cho các biến riêng? Nhưng trong trường hợp này, chúng tôi phải sử dụng dấu gạch dưới - hoặc chúng tôi sẽ có xung đột giữa "thanh" riêng tư và công cộng
Kokodoko

4
Sử dụng dấu gạch dưới là một sở thích cá nhân cho các thuộc tính riêng tư. Tuy nhiên, tôi tin rằng bạn đúng ở chỗ chúng tôi muốn thuộc tính có một tên khác với các phương thức getter / setter.
Ezward

3
Tại sao bạn sử dụng myFoo.bar = truethay vì myFoo.bar(true);hay myFoo.setBar(true);??
Daniel W.

6
@DanFromGermany Một thuộc tính là "đường cú pháp" cho một cặp phương thức "get" và "set". Microsoft khởi nguồn khái niệm một thuộc tính với Visual Basic và chuyển nó sang các ngôn ngữ .NET như C # và VB.NET. Ví dụ: xem Thuộc tính (Hướng dẫn lập trình C #) . Các thuộc tính đơn giản hóa việc truy cập trạng thái của một đối tượng và (theo tôi) loại bỏ "sự ồn ào" của việc phải xử lý các cặp phương thức "get / set". (Hoặc đôi khi chỉ có các phương thức "có được" trong trường hợp không thay đổi được mong muốn.)
DavidRR

112

Ezward đã cung cấp một câu trả lời tốt, nhưng tôi nhận thấy rằng một trong những ý kiến ​​hỏi nó được sử dụng như thế nào. Đối với những người như tôi vấp phải câu hỏi này, tôi nghĩ rằng sẽ rất hữu ích khi có một liên kết đến tài liệu chính thức về getters và setters trên trang web Typecript vì điều đó giải thích tốt, hy vọng sẽ luôn cập nhật vì những thay đổi là thực hiện, và hiển thị ví dụ sử dụng:

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

Đặc biệt, đối với những người không quen thuộc với nó, lưu ý rằng bạn không kết hợp từ 'get' vào một cuộc gọi đến một getter (và tương tự cho setters):

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

Bạn chỉ cần làm điều này:

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

đưa ra một lớp như:

class foo {
  private _bar:boolean = false;

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

sau đó, getter 'bar' cho thuộc tính '_bar' riêng tư sẽ được gọi.


Nếu tôi muốn thay thế một var cấp độ công cộng bằng một thuộc tính, thì đó có phải là một sự thay thế thả thẳng mà tôi có thể đặt vào vị trí và không phải lo lắng về nó không? Nói cách khác, nếu tôi hồi quy kiểm tra một trình truy cập và một trình thiết lập, tôi có thể coi đó là một thành công không? Hoặc có những trường hợp nó sẽ không hoạt động chính xác như một var và tôi cần kiểm tra tất cả 100 địa điểm sử dụng var / prop này?
Adam Plocher

Tôi đã tự hỏi nếu có một cách giải quyết cho việc sử dụng dấu gạch dưới để phân biệt tên thuộc tính với các phương thức getter hoặc setter. Trong một khóa học tôi đã làm họ nói rằng phần dưới không được ưa thích nhưng không đưa ra giải pháp thay thế.
cham

1
@cham Bạn không cần phải sử dụng dấu gạch dưới ở đây ... Bạn có thể gọi notbar biến riêng nếu bạn muốn.
Robert McKee

58

Đây là một ví dụ hoạt động sẽ chỉ cho bạn đi đúng hướng:

class Foo {
    _name;

    get Name() {
        return this._name;
    }

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

Getters và setters trong JavaScript chỉ là các chức năng bình thường. Setter là một hàm lấy tham số có giá trị là giá trị được đặt.


30
Để rõ ràng, không cần tài sản, getter và setter static.
vẽ Noakes

1
các tham chiếu biến vẫn là tĩnh mặc dù. Foo._namenên được thay thế bằngthis._name
Johannes

6

Bạn có thể viết cái này

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
Tại sao công chúng trong xây dựng?
MuriloKunze

17
Có, không thể có công khai trong hàm tạo trong mã này. publicở đây định nghĩa các thành viên trùng lặp.
orad

2
Bạn có thể viết nó nhưng nó sẽ không biên dịch
Justin

3

TS cung cấp getters và setters cho phép các thuộc tính đối tượng có quyền kiểm soát nhiều hơn về cách chúng được truy cập (getter) hoặc cập nhật (setter) bên ngoài đối tượng. Thay vì trực tiếp truy cập hoặc cập nhật tài sản, một chức năng proxy được gọi.

Thí dụ:

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

Nó rất giống với việc tạo các phương thức phổ biến, chỉ cần đặt từ khóa dành riêng gethoặc setở đầu.

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();

Trong trường hợp này, bạn có thể bỏ qua kiểu trả về get getMethod1() {

    get getMethod1() {
        return this._name;
    }

1

Tôi nghĩ rằng tôi có thể nhận được tại sao nó rất khó hiểu. Trong ví dụ của bạn, chúng tôi muốn getters và setters cho _name. Nhưng chúng tôi đạt được điều đó bằng cách tạo getters và setters cho một biến lớp không liên quan Name.

Xem xét điều này:

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

Mã trên không như sau:

  1. getsettạo getter và setter cho yourCarTiresCount( không phải chotiresCount ).

Các getter là:

function() {
    return this.tiresCount ;
}

và setter là:

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

Có nghĩa là, mỗi khi chúng ta làm new Car().yourCarTiresCount, getter chạy. Và cho mỗi new Car().yourCarTiresCount('7')setter chạy.

  1. Gián tiếp tạo getter, nhưng không phải setter, cho riêng tư tireCount.

0

Nếu bạn đang tìm cách sử dụng get và set trên bất kỳ đối tượng nào (không phải là một lớp) Proxy có thể hữu ích: https://developer.mozilla.org/en-US/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

Lưu ý: lưu ý rằng đây là api mới không được hỗ trợ và yêu cầu polifill cho các trình duyệt cũ hơn


-6

Nếu bạn đang làm việc với các mô-đun TypeScript và đang cố gắng thêm một getter được xuất, bạn có thể làm một cái gì đó như thế này:

// 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;
    },
});

Sau đó, trong một tệp khác, bạn có:

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

8
Đó là lời khuyên khủng khiếp. Cụ thể, thisphải được xác định ở phạm vi cấp cao nhất của mô-đun. Bạn có thể sử dụng exportsthay thế nhưng bạn hoàn toàn không nên làm điều đó vì nó thực sự được đảm bảo để gây ra sự cố tương thích
Aluan Haddad
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.