class 類 this指向的問題

apy發表於2018-12-28

ES6 實現了類的概念

    class Prosen {
        
    }

ES5使用函式模擬

    function Prosen() {
        
    }

ES6中的 class定義一個類, 其內部包含 constructor建構函式, 除了在建構函式顯示的定義一些屬性, 其餘的預設都新增到這個類的原型物件上。

在一個類中定義一個讀取名字的函式:

    class Prosen {
        constructor(name) {
            this.name = name;
        }
        sayName() {
            console.log(this.name)
        }
    }
    
    const prosen = new Prosen(`zhangsan`)
    prosen.sayName()  //張三

如果我們把 sayName 這個函式拿出來執行會是什麼結果呢?

繼以上程式碼

    const prosen1 = new Prosen(`lisi`)
    const { sayName } = prosen1
    sayName()  // 報錯

以上報錯的原因是 sayName函式中的 this不對。指向的不是 prosen1這個例項物件,所以是無法讀取name 屬性的。

使用 proxy來代理例項物件,攔截讀取操作並修改this的指向

    function classProxy(target) {
        const m = WeakMap()
        // 讀取攔截配置, 只需要配置 get
        const hanlder = {
            get(target, key) {
                const val = Reflect.get(target, key)
                // 要獲取的是函式執行, 如果不是函式就直接返回 val
                if (typeof val !== `function`) return val
                if (!m.has(val)) {
                    // 使用 bind改變執行函式的 this為攔截的例項物件
                    m.set(val, val.bind(target))
                }
                return m.get(val)
            }
        }
        const proxy = new Proxy(target, hanlder)
        return proxy
    }

繼以上程式碼

    const prosen2 = new Prosen(`qiqingfu`)
    const { sayName } = classProxy(prosen2)
    sayName()  // qiqingfu

以上程式碼 classProxy(prosen2) 返回的是包含一層攔截器的例項物件, 當讀取 sayName這個函式的是和會出發 get攔截等操作。

總結其它知識點

proxy: 攔截器, 用於物件操作的自定義行為(如屬性查詢, 賦值, 列舉, 函式呼叫, 是例項化等)

Reflect 是一個內建的物件, 它提供攔截 Javascript方法,和Object操作類似。

WeakMap: 可以實現物件 值-值的對應, 並且一個物件的鍵值只能是物件,且不計入垃圾回收機制,可物件引用常駐記憶體造成的記憶體洩漏等問題。

WeakMap:

    const n = {a: 1}
    const m = new WeakMap()
    m.set(n, 1)
    m.get(n) // 1
    m.has(n) // true

相關文章