我們要搞清楚new操作符到底做了一些什么事情?
1.創建一個新的對象
2.將構造函數的作用域賦給新對象(因此this指向了這個新對象)
3.執行構造函數中的代碼(為這個新對象添加屬性)
4.返回新對象
上面給出了new操作符到底做了一些什么事情,我們就一步一步的實現這些,是不是就實現了new操作符的功能。
首先定義一個構造函數Person如下:
function Person(name) { this.name = name; } Person.prototype.sayName = function () { console.log(this.name); }
然后創建模擬new操作符功能的函數如下:
function Person(name) { this.name = name; } Person.prototype.sayName = function () { console.log(this.name); } function createPerson() { // 1 創建一個新的對象 var o = {}; // 2 獲取構造函數,以便實現作用域的綁定 var _constructor = [].shift.call(arguments); // 3 由於通過new操作創建的對象實例內部的不可訪問的屬性[[Prototype]](有些瀏覽器里面為__proto__) //指向的是構造函數的原型對象的,所以這里實現手動綁定。 o.__proto__ = _constructor.prototype; // 4.作用域的綁定使用apply改變this的指向
_constructor.apply(o, arguments); return o; } var person1 = createPerson(Person, 'ydb'); person1.sayName();
這樣子就實現了new操作符的功能了。
其實上面代碼還可以這樣子寫:
function Person(name) { this.name = name; } Person.prototype.sayName = function () { console.log(this.name); } function createPerson() { // 1 獲取構造函數,以便實現作用域的綁定 var _constructor = [].shift.call(arguments); // 2 創建一個對象 var o = Object.create(_constructor.prototype); // 由於通過new操作創建的對象實例內部的不可訪問的屬性[[Prototype]](有些瀏覽器里面為__proto__) //指向的是構造函數的原型對象的。 //而Object.create()方法創建一個新對象,使用現有的對象來提供新創建的對象的__proto__。// 4.作用域的綁定 _constructor.apply(o, arguments); return o; } var person1 = createPerson(Person, 'ydb'); person1.sayName();
用Object.create可以創建一個沒有任何屬性的對象,如下:
var o = Object.create(null);