一、new一個函數和直接調用函數的區別
不使用new,也就是普通的函數調用而已,所以若是函數本身沒有返回值,普通的函數調用沒有什么意義
如:
var person=new Person();//person是一個對象
var person = Person();//這只是一次普通的函數調用並賦值而已。
function Person(name,age){ this.name=name; this.age=age; this.sayName=function(){ alert(this.name); }; } //var person=new Person("張三",20); //此處為 構造對象,構造對象的話,返回的新對象是由解析器自己生成的。 var person=Person("張三",20); //假設我在Person函數里面加了return "你好"; 這時的person就不會報undefined,而是一個字符串你好 person.sayName();//報錯 person undefined 此處為普通函數調用,又沒有給定返回值,出錯。 //因為此時this指向window對象, window.sayName();//此時不會報錯 //接下來就問,為什么我賦值給person,可以用window來引用呢? //因為如果不用new就相當於普通函數調用,而 Person()根本沒有返回值, //所以Person根本就沒賦值給person,此時的person只是一個undefined, //但是Person卻執行了一次,成為了window的對象,this指向了window,所以window可以直接使用Person的方法,
如果構造函數返回值為常規意義上的數值類型(Number、String、Boolean)時,new函數將會返回一個該函數的實例對象,
而如果構造函數返回一個引用類型(Object、Array、Function)時,則new函數與直接調用函數產生的結果相同,都返回這個引用。
- 函數返回值為常規意義上的數值類型(Number、String、Boolean)
function Test() { this.name = "test"; return "test"; } var test1 = new Test(); //Object 對象,它有一個name 屬性,並且返回一個字符串test var test2 = Test(); // 函數Test()屬於Function對象 這個test2,它單純是一個字符串
- 函數返回一個引用類型(Object、Array、Function)(工廠模式):
function Person(name,age) { var o = new Object(); o.name = name; o.age = age; o.getName = function() { alert(this.name); } return o; } var obj1 = new Person("liwen",25); var obj2 = Person("liwen1",25); obj1.getName(); //liwen new一個函數的實例對象 obj2.getName(); //liwen1 直接調用
二、new一個對象的過程
首先我們看下new Person輸出什么?
var Person = function(name, age) { this.name = name; this.age = age; }; Person.prototype.show = function() { console.log(this.name, this.age); }; var p = new Person("bella", 10); console.log(p);
對象p里有屬性name, age 和 __proto__;
__proto__里面有原型方法show,constructor, __proto__;
然后我們再輸出構造器Person.prototype:
對比一下,發現p的__proto__的值就是構造函數Person的prototype的屬性值。
因此new操作符創建對象可以分為以下四個步驟:
-
- 創建一個空對象
- 將所創建對象的__proto__屬性值設為構造函數的prototype的屬性值
- 執行構造函數中的代碼,構造函數中的this指向該對象
- 返回對象
因此上面的過程就可以等同於下面的過程:
var newMethod2 = function(Class,...rest){ var p = {}; p.__proto__ = Class.prototype; var result = Class.apply(p, rest); return typeof result==='object'?result:p; }