iT邦幫忙

2

javascript prototype的疑問

小弟大部分時間都是使用java開發
最近因為一些原因需要使用javascript因此碰的一鼻子灰...

程式碼:

// iterable宣告法
function myIterable() {
    this.StorageArray = {
        storage1: {slot1:'1', slot2:'2'},
        storage2: {slot1:'1', slot2:'2'},
    };
    
    this.length = 2;
}


myIterable.prototype[Symbol.iterator] = () => {
    return {
        i:0,
        next() {
            if(this.i < this.length) {
                return {value: this.StorageArray[this.i], done: false};
            }
            return {value: undefined, done: true};
        }
    };
};

let myIterableTest = new myIterable();

for (const value of myIterableTest) {
    console.log(value);
}

主要想法是想把一個物件變成一個可以用index來迭代的(實作iterable)。
預期的輸出應該為StorageArray的兩個storage物件。
但是看樣子length與StorageArray都是undefine呢。
預先謝謝各位願意看這個奇怪的code >w<

這個程式碼是毫無意義的 只是把一些我對js的妄想寫出來....
大概也知道物件是要用解構的,或是用forin來迭代
但還是想知道不work的原因

1 個回答

4
albert41
iT邦新手 5 級 ‧ 2020-04-11 16:49:38
最佳解答

大大的 code 問題主要是出在 JavaScript 變數 scope 的問題:

  1. 箭頭函式中的 this 會指向 「定義此函示當下,包覆函示的物件」,以你的例子來說會是主要的環境 (例如你在 Chrome 的 console 執行就會是 Window 物件)。因此按照你的需求應該改寫為:
myIterable.prototype[Symbol.iterator] = function() {
 // 略
};
  1. 執行迭代時,判斷條件所用到的 this 也跟你預期的不一樣。由於你的 next() 是屬於你要 return 的 {},所以 next() 中的每一個 this 都會指向 return 的 {};也因此 this.i 會是指向你所定義的 i:0,;而 this.lengththis.StorageArray 因為都沒有定義於 return 的 {} 當中所以會是 undefined。按照你的需求有下面兩種改寫方式:
myIterable.prototype[Symbol.iterator] = function() {
    const myIterableInstance = this;
    return {
        i: -1,
        next() {
            if(this.i < myIterableInstance.length) {
                this.i++;
                return {value: myIterableInstance.StorageArray[this.i], done: false};
            }
            return {value: undefined, done: true};
        }
    };
};

myIterable.prototype[Symbol.iterator] = function() {
    const result = {
        i: -1,
        next: () => {
            if(result.i < this.length) {
                result.i++;
                return {value: this.StorageArray[result.i], done: false};
            }
            return {value: undefined, done: true};
        }
    };
    return result;
};
  1. 最後一個問題是你預期用 index (即你的 i) 去取出 StorageArray 中的元素,可是你的 StorageArray 並沒有任何 key 是 0, 1, 2, ...,所以會回傳 undefuned,按照你的需求有下面兩種改寫方法:
function myIterable() {
    this.StorageArray = [
        {slot1:'1', slot2:'2'},
        {slot1:'1', slot2:'2'},
    ];
    this.length = 2;
}

    // 略
        next: () => {
            if(result.i < this.length) {
                result.i++;
                return {
                    value: Object.values(this.StorageArray)[result.i],
                    done: false
                };
            }
            return {value: undefined, done: true};
        }
jokie7585 iT邦新手 5 級 ‧ 2020-04-11 16:52:58 檢舉

感謝你>w< 非常詳細!

jokie7585 iT邦新手 5 級 ‧ 2020-04-11 16:54:36 檢舉

原來this是這樣運作的
我看好幾篇文章都沒你講的清楚xDD
謝謝~

albert41 iT邦新手 5 級 ‧ 2020-04-11 17:44:04 檢舉

如果習慣 OOP 可以考慮使用 ES6 的語法糖 「class」寫類別,或者改用 TypeScript (如果你的框架支援的話) ~

我要發表回答

立即登入回答