2016-06-22 27 views
0

TypeScript 1.8我試圖圍繞如何使用set訪問器來攔截對象屬性(和子屬性)的編輯操作。它沒有按照我的預期工作,我不知道我的代碼是否有問題。限制ot Typescript設置訪問器或問題與我的代碼?

這裏是我的類的摘錄:

private setAction:number = 0; //track # of edits 

private _person:{ //data to be edited 
    name:string, 
    data:{ 
     activities:Array<{ 
      activityName:string, 
      funFactor:number 
     }>, 
     country:string 
    } 
}; 

//public interfaces for set/get operations 
public set person(val:any){ 
    //indicate which edit is occuring 
    console.log('setting _person: setAction='+this.setAction); 

    if(!this._person) this._person = val;//initial set operation 
    let p = this._person; 
    p.name = val.name || p.name; 
    p.data.activities = val.data.activities || p.data.activities; 
    p.data.country = val.data.country || p.data.country; 
} 

public get person(){ 
    return this._person; 
} 

public addActivity(name:string,value:number){ 
    this.person.data.activities.push(
     {activityName:name,funFactor:value}); 
} 

//Edit this.person and test whether Set Accessor is called 
onLoad(){ 

    console.log('Incrementing setAction to '+ ++this.setAction); 
    this.person = { 
     name:'Mary', 
     data:{ 
      activities:[], 
      country:'Argentina' 
     } 
    }; 

    console.log('Incrementing setAction to '+ ++this.setAction); 
    this.person.name = 'Janet'; 

    console.log('Incrementing setAction to '+ ++this.setAction); 
    this.addActivity('Bowling',7); 

    console.log('Incrementing setAction to '+ ++this.setAction); 
    this.person.data.country = 'Mexico'; 

    console.log('Incrementing setAction to '+ ++this.setAction); 
    this.person.data.activities[0].funFactor = 8; 

    console.log(this.person); 
} 

onLoad被調用時,下面是輸出到控制檯:

遞增的setAction 1

設置_person:setAction命令= 1

遞增setAction爲2

遞增的setAction至3

遞增的setAction至4

遞增的setAction至5

對象{名: 「珍」,數據:對象}

data在最終Object更新爲country="Mexico"和Bowling funFactor=8。所以所有編輯都成功完成,但Set訪問器只被調用一次。爲什麼是這樣?

看看the docs(向下滾動到訪問器部分)沒有提到這個限制。

其他注意事項: 據我所知,爲了執行person.name='Janet',我需要先得到person,所以我希望get要對所有這些操作調用。但由於person.name從'瑪麗'改爲'珍妮特',確實設爲爲一個新值。那麼,爲什麼不是二傳手?我正在努力處理它的邏輯。我期望這個過程是:1)get person,2)set person.name

當屬性從一個值更改爲另一個值時,不應該調用getter和setter嗎?

回答

我一直以爲getset進行時性能讀取或寫入調用。這就是它向我解釋的。 TypeScript文檔說'TypeScript支持getters/setter作爲攔截對象'成員的訪問方式'。 RadimKöhler幫助我理解,當代碼不與對象屬性交互時,而是與對象引用交互時,將調用這些函數。總之,當我執行person.name='Janet'時,雖然屬性值發生變化,但person仍然是指內存中的同一個對象,所以沒有set操作。

回答

1

好,setter被稱爲只有一次,在該行

this.person = { 
    name:'Mary', 
    data:{ 
     activities:[], 
     country:'Argentina' 
    } 
}; 

對方其實是在呼籲getter

console.log('Incrementing setAction to '+ ++this.setAction); 
this.person.name = 'Janet'; 

console.log('Incrementing setAction to '+ ++this.setAction); 
this.addActivity('Bowling',7); 

console.log('Incrementing setAction to '+ ++this.setAction); 
this.person.data.country = 'Mexico'; 

console.log('Incrementing setAction to '+ ++this.setAction); 
this.person.data.activities[0].funFactor = 8; 

因爲this.person.data就像

let person = this.person; // getter 
person.data = ... 

EXTEND

a working example顯示問題的實際情況。當我們調用引用屬性的setter(例如Person)時,我們分配一個引用。之後,當我們更改引用對象的屬性時,我們不會更改原始引用。點擊此處查看:

class Person { 
    // name has setter 
    private _name = null; 
    set name(name: string) { this._name = name; console.log(name) }; 
    get name() { return this._name} 

    // age does not one 
    age: number = null; 
} 

class PersonHolder { 

    private _person; 
    set person(person: Person) { this._person = person; 
           console.log(JSON.stringify(person)) }; 
    get person() { return this._person} 
} 

var holder = new PersonHolder(); 

// this will log to console { name: null, age: null} 
holder.person = new Person(); 
// this will log to console "new name" 
holder.person.name = "new name" 
// this will NOT log to console... no setter 
holder.person.age = 11; 

直播example

+0

我明白,爲了執行'person.name ='Janet'',我需要先得到'person',所以我希望'GET'是正如你所提到的那樣呼籲所有這些行動。然而,由於'person.name'從'Mary'變成了'Janet',它確實**將**設置爲一個新值。那麼,爲什麼不是二傳手?我正在努力處理它的邏輯。我期望的過程是:1)'get person',2)'set person.name' – BeetleJuice

+0

那麼1)得到人..意味着給我參考人。因此,當我們改變名稱時,我們在內存中有一個地址(這是參考),其中人員實例是2)。我們不會改變對人的引用。它仍然是同一個對象..只是某處(在堆上)改變了它的設置名稱。因此,這個人的二傳手是真實的,以引用這個人。不涉及與該實例相關的屬性。也許試着準備一些關於引用和值類型的東西。 http://www.zsoltnagy.eu/understand-value-and-reference-types-in-javascript/ –

+0

我對引用類型和值類型之間的區別有所瞭解(感謝您的鏈接;我會看一看) 。我不知道「* setter是真的引用,而不是屬性*」這是有道理的,但我鏈接到的Typescript文檔沒有提及它。你有沒有參考這個,你可以添加到你的答案? – BeetleJuice