一、js中new一個對象的過程
首先了解new做了什么,使用new關鍵字調用函數(new ClassA(…))的具體步驟:
1、創建一個新對象:
var obj = {};
2、設置新對象的constructor屬性為構造函數的名稱,設置新對象的__proto__屬性指向構造函數的prototype對象;
obj.__proto__ = ClassA.prototype;
3、使用新對象調用函數,函數中的this被指向新實例對象:
ClassA.call(obj); //{}.構造函數()
4、將初始化完畢的新對象地址,保存到等號左邊的變量中
注意:若構造函數中返回this或返回值是基本類型(number、string、boolean、null、undefined)的值,則返回新實例對象;若返回值是引用類型的值,則實際返回值為這個引用類型。
var foo = "bar"; function test () { this.foo = "foo"; } new test(); //test中的this指新對象,並未改變全局的foo屬性
console.log(this.foo); // "bar"
console.log(new test().foo); // "foo";
二、用原生JS實現new方法
// 通過分析原生的new方法可以看出,在new一個函數的時候, // 會返回一個func同時在這個func里面會返回一個對象Object, // 這個對象包含父類func的屬性以及隱藏的__proto__
function New(f) { //返回一個func
return function () { var o = {"__proto__": f.prototype}; f.apply(o, arguments);//繼承父類的屬性
return o; //返回一個Object
} }
首先寫一個父類方法(包含參數name,age):
function Person(name,age){ this.name = name; this.age = age; }
//new一個Person的實例p1做研究對比
var p1 = new Person("Richard", 22); //此時p1包含name、age屬性,同時p1的__proto__指向Person的prototype
p1.name;//Richard
p1.age;//22
通過自定義New方法創建一個實例對象p2:
var p2 = New(Person)("Jack",25); p2.name;//Jack
p2.age;//25
此時p2 instanceof Person 返回的是true;
Person.prototype.gender ="male"; p1.gender//male
p2.gender//male
三、優先級問題
優先級由高到低:小括號(xxx) > 屬性訪問. > new foo() > foo()
注意new Foo()優先級高於Foo();
function getName(){ console.log(1) } function Foo() { this.getName = function () { console.log(2); }; return this; } Foo.getName = function () { console.log(3); }; //先從.屬性訪問符號開始往前面找一個最近的對象,同時注意new Foo()優先於Foo();
var a=new Foo.getName();//3;
屬性.的優先級高於new foo(),所以===new (Foo.getName)();返回Foo.getName類型的實例
var b=new Foo().getName();//2;
new foo()的優先級高於foo(),所以就相當於new foo()的屬性,===(new Foo()).getName();返回undefined
var c=new new Foo().getName();//2;
new foo()優先級低於屬性.,所以其實相當於就是new一個new foo()的getName屬性函數,===new (new Foo().getName)();返回Foo.getName類型的實例
new Date().getTime();//===((new Date()).getTime)()
(new Date).getTime();//===((new Date()).getTime)() new Date.getTime();//Uncaught TypeError: Date(...).getTime is not a function;===new (Date.getTime)()
需要注意的是:new Date 其實也是正確的,和new Date()一樣