前幾天遇到一個有趣的問題,代碼如下:
function Person(){ this.age = 0; setInterval(() => { this.age++; }, 1000); } var p = new Person();
運行起來會發現p值是一個動態改變的對象,那么它是怎么做到的呢?下面一起來看看:
// 直接運行Person方法並打印當前this對象 function Person(){ this.age = 0; setInterval(() => { this.age++; console.log(this); }, 1000); } Person(); // 打印的結果是window對象
上面的代碼我們直接運行了Person方法,發現此時打印的是window對象,原因是函數在調用的時候函數的this指向window,下面我們看一下通過new Person()運行的結果如何:
// 通過new Person()方式調用 function Person(){ this.age = 0; // 這里不用箭頭函數最后會指向window對象 setInterval(() => { this.age++; console.log(this); }, 1000); } var p = new Person(); // 打印的結果是當前的p對象
運行上面的代碼會發現打印了當前的p對象,不難看出,new語法改變了我們調用函數時候的this指向,並返回了執行后的this對象,那么它是怎么做到的呢?我們可以用一個簡單的實現解釋一下其原理:
function Person(age) { this.age = age; } Person.prototype.sayAge = function () { console.log(this.age); } function createNew (target, ...argArr) { // 判斷類型 if (Object.prototype.toString.call(target).slice(8, -1) !== 'Function') return; // 以構造器的prototype屬性為原型,創建新對象; var source = Object.create(target.prototype); // 在source上執行target內容 target.apply(source, argArr); // 返回執行后的source return source; } var p = createNew(Person, 18); console.log(p.age); p.sayAge && p.sayAge(); // 打印結果為 // 18 // 18
另一種解釋方式是:
var p = {}; p._ptoto_ = Person.prototype; Person.apply(p, 18);
Over,自行理解吧~