TypeScript'te al ve ayarla


659

Bir özellik için get ve set yöntemi oluşturmaya çalışıyorum:

private _name: string;

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

Değer ayarlamak için anahtar kelime nedir?


12
Alt çizgi ve PascalCase, Typcript kodlama kılavuz ilkeleriyle çakışıyor: github.com/Microsoft/TypeScript/wiki/Coding-guidelines
Niels Steenbeek

2
Hi @NielsSteenbeek - TypeScript katkıda bulunanlar yönergelerini izleyerek özellikleri ve destek alanlarını bir ad çakışmasıyla karşılaşırsınız. Önerilen yaklaşım nedir?
Ürdün,

Belki de: typescript private name: string; getName() { get: { return this.name; } set: { this.name = ???; } }
Ürdün,

7
Bu yazı tipi kodlama yönergeleri oldukça çirkin olması iyi bir şey. Onları sadece baskı altında kullanırdım (örneğin bana ödendi).
Thomas Eding

14
@NielsSteenbeek: bu belgeyi okudun mu? "Bu, TypeScript topluluğu için kuralcı bir kılavuz DEĞİL"
Jonathan Cast

Yanıtlar:


1084

TypeScript, ActionScript3 gibi bir alıcı / ayarlayıcı sözdizimi kullanır.

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

Bu, ECMAScript 5 Object.defineProperty()özelliğini kullanarak bu JavaScript'i üretecektir .

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

Kullanmak için,

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

Ancak, onu kullanmak için, TypeScript derleyicisinin ECMAScript5'i hedeflediğinden emin olmalısınız. Komut satırı derleyicisini çalıştırıyorsanız, --targetböyle bir bayrak kullanın ;

tsc --target ES5

Visual Studio kullanıyorsanız, TypeScriptCompile derleme aracının yapılandırmasına bayrak eklemek için proje dosyanızı düzenlemeniz gerekir. Bunu burada görebilirsiniz :

@DanFromGermany'nin aşağıda belirttiği gibi, sadece yerel bir özelliği okuyup yazıyorsanız foo.bar = true, bir ayarlayıcı ve alıcı çiftine sahip olmak aşırıdır. Özellik okunduğunda veya yazıldığında günlük kaydı gibi bir şey yapmanız gerekiyorsa bunları daha sonra ekleyebilirsiniz.


59
Güzel cevap. Ayrıca, C # 'dan farklı olarak, özelliklerin şu anda TypeScript'te (v0.9.5) sanallaştırılmadığını unutmayın. Türetilmiş bir sınıfa "get bar ()" uyguladığınızda, üst öğedeki "get bar ()" yerine geçersiniz. Çıkarımlar, türetilmiş erişimciden temel sınıf erişimcisini çağıramamayı içerir. Bu sadece özellikler için geçerlidir - yöntemler beklediğiniz gibi davranır. SteveFenton'un cevabını buradan görebilirsiniz: stackoverflow.com/questions/13121431/…
David Cuccia

14
Alt çizgiyle ilgili biraz kafam karıştı. Daktilo kuralı özel değişkenler için alt çizgi kullanmama diyor? Ancak bu durumda, alt çizgi kullanmalıyız - yoksa özel ve genel "bar" arasında bir çatışma elde edeceğiz
Kokodoko

4
Alt çizgi kullanımı özel mülkler için kişisel bir tercihtir. Ancak, mülkün alıcı / ayarlayıcı yöntemlerinden farklı bir ada sahip olmasını istediğimiz konusunda haklı olduğuna inanıyorum.
Ezward

3
Neden veya myFoo.bar = trueyerine kullanıyorsunuz ?? myFoo.bar(true);myFoo.setBar(true);
Daniel W.

6
@DanFromGermany Bir özellik "get" ve "set" yöntemleri için "sözdizimsel şeker" dir. Microsoft, bir özellik kavramını Visual Basic ile oluşturdu ve C # ve VB.NET gibi .NET dillerine taşıdı. Örneğin, bkz. Özellikler (C # Programlama Kılavuzu) . Özellikler, bir nesnenin durumuna erişmeyi kolaylaştırır ve (bence), "get / set" yöntemi çiftleriyle uğraşmanın “gürültüsünü” ortadan kaldırır. (Veya bazen sadece değişmezliğin istendiği durumlarda "alın" yöntemleri.)
DavidRR

112

Ezward zaten iyi bir cevap verdi, ancak yorumlardan birinin nasıl kullanıldığını sorduğunu fark ettim. Benim gibi bu soruya rastlayan insanlar için, iyi açıklayan, yazım web sitesinde alıcılar ve ayarlayıcılar ile ilgili resmi belgelere bir bağlantı kurmanın yararlı olacağını düşündüm, çünkü değişiklikler her zaman güncel kalacaktır. yapılmış ve örnek kullanım gösterir:

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

Özellikle, aşina olmayanlar için, bir alıcıya (ve benzer şekilde ayarlayıcılar için) bir çağrıya 'get' kelimesini eklemediğinizi unutmayın:

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

Bunu basitçe yapmanız gerekir:

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

şöyle bir sınıf verildi:

class foo {
  private _bar:boolean = false;

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

özel '_bar' özelliği için 'bar' alıcısı çağrılır.


Genel sınıf düzeyinde bir varlığı bir mülkle değiştirmek istiyorsam, yerine koyabileceğim ve bu konuda endişelenmeyeceğim düz bir bırakma ikamesi mi? Başka bir deyişle, bir erişimci ve bir pasör regresyon testi yaparsam, bunu bir başarı olarak değerlendirebilir miyim? Ya da bir var ile tam olarak aynı işe yaramayacağı durumlar var mı ve bu var / prop kullanan 100 yeri de test etmem gerekiyor mu?
Adam Plocher

Özellik adını alıcı veya ayarlayıcı yöntemlerinden ayırmak için alt çizgi kullanmak için bir çözüm olup olmadığını merak ediyordum. Yaptığım bir derste alt çizgilerin tercih edilmediğini ancak alternatif vermediklerini söylediler.
cham

1
@cham Burada alt çizgi kullanmanıza gerek yok ... İsterseniz notbar özel değişkenini çağırabilirsiniz.
Robert McKee

58

İşte size doğru yönü göstermesi gereken çalışan bir örnek:

class Foo {
    _name;

    get Name() {
        return this._name;
    }

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

JavaScript'teki harfler ve ayarlayıcılar yalnızca normal işlevlerdir. Ayarlayıcı, değeri ayarlanan değer olan bir parametreyi alan bir işlevdir.


30
Açık olmak gerekirse, mülk, alıcı ve ayarlayıcı olmaya gerek yoktur static.
Drew Noakes

1
değişken referansları hala statiktir. Foo._namedeğiştirilmelidirthis._name
Johannes

6

Bunu yazabilirsin

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
Neden kurucu halk?
MuriloKunze

17
Evet, bu kodda kurucuda herkese açık olamaz. publicburada yinelenen üyeler tanımlanır.
orad

2
Justin

3

TS teklifler Alıcıları ve nesne özellikleri onlar (alıcı) veya güncellenmiş (ayarlayıcı) erişilen nasıl daha fazla kontrol için izin belirleyiciler dışında nesnenin. Özelliğe doğrudan erişmek veya bu özelliği güncellemek yerine bir proxy işlevi çağrılır.

Misal:

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

Genel yöntemler oluşturmaya çok benzer, sadece anahtar kelimeyi ayrılmış getveya setbaşlangıçta koymanız yeterlidir .

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

Bu durumda iade türünü atlayabilirsiniz get getMethod1() {

    get getMethod1() {
        return this._name;
    }

1

Sanırım neden bu kadar kafa karıştırıcı olduğunu anladım. Örneğinizde, alıcılar ve ayarlayıcılar istedik _name. Ancak, ilgisiz bir sınıf değişkeni için alıcılar ve ayarlayıcılar oluşturarak bunu başarıyoruz Name.

Bunu düşün:

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

Yukarıdaki kod şunları yapar:

  1. getve setiçin alıcı ve ayarlayıcı oluşturun yourCarTiresCount(için değiltiresCount ).

Alıcı:

function() {
    return this.tiresCount ;
}

ve ayarlayıcı:

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

Yani, her yaptığımızda new Car().yourCarTiresCountgetter koşuyor. Ve her new Car().yourCarTiresCount('7')setter koşusu için.

  1. Özel için dolaylı olarak alıcıyı oluşturun, ancak ayarlayıcıyı yaratmayın tireCount.

0

Eğer herhangi bir nesnede get ve set kullanmanın bir yolunu arıyorsanız (bir sınıf değil) Proxy yararlı olabilir: 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

Not: Bunun yeni API desteklenmediğini ve daha eski tarayıcılar için gerekli yükseltmenin olduğunu unutmayın.


-6

TypeScript modülleriyle çalışıyorsanız ve dışa aktarılan alıcıyı eklemeye çalışıyorsanız, şöyle bir şey yapabilirsiniz:

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

Sonra başka bir dosyada:

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

8
Bu korkunç bir tavsiye. Özellikle, thisbir modülün en üst düzeyde tanımlanmamış olmalıdır. Bunun exportsyerine kullanabilirsiniz, ancak uyumluluk sorunlarına neden olduğu neredeyse garanti edildiği için bunu
yapmamalısınız
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.