構造函數:如用函數用來初始化(使用new運算符)一個新建的對象,我們稱之為構造函數(constructor)
function Person(){ this.name = "zqq"; this.age = 28; } var p = new Person();
當以new調用構造函數(執行var p = new Person())時,函數內部會發生以下情況:
1.創建一個空對象
var p = {};
2.this變量指向對象p
Person.call(p)
3.p繼承了構造函數Person()的原型
p.__proto__ = Person.prototype
4.執行構造函數Person()內的代碼
構造函數和普通函數的區別:
1.構造函數使用new關鍵字調用;普通函數不用new關鍵字調用;
var p = new Person(); var p = Person();
2.構造函數內部可以使用this關鍵字;普通函數內部不建議使用this,因為這時候this指向的是window全局對象,這樣無意間就會為window添加了一些全局變量或函數
在構造函數內部,this指向的是構造出來的新對象
在普通函數內部,this指向的是window全局對象
3.構造函數默認不用return返回值;普通函數一般都有return返回值
構造函數會默認返回this,也就是新的實例對象
普通函數如果沒有return值的話,返回undefined
如果使用了return,那返回值會根據return值的類型而有所不同
return的是五種簡單數據類型:String,Number,Boolean,Null,Undefined的話,構造函數會忽略return的值,依然返回this對象;而普通函數會返回return后面的值 function Person(){ var a; this.name = "zqq"; this.age = 28; return a; } var p = new Person();//返回this對象 var p = Person();//因為a沒初始化,所以a是undefined,而undefined屬於簡單數據類型,所以返回undefined,String,Number,Boolean,Null同理 如果return的是引用類型:Array,Date,Object,Function,RegExp,Error的話,構造函數和普通函數都會返回return后面的值 function Person(){ var arr = []; this.name = "zqq"; this.age = 28; return arr; } var p = new Person();//返回arr空數組,Date,Object,Function,RegExp,Error同理 var p1 = new Person();//返回arr空數組,Date,Object,Function,RegExp,Error同理
4.構造函數首字母建議大寫;普通函數首字母建議小寫
構造函數的優點與缺點
優點就是能夠通過instanceof識別對象,缺點是每次實例化一個對象,都會把屬性和方法復制一遍
function CreateObj(uName) { this.userName = uName; this.showUserName = function () { return this.userName; } } var obj1 = new CreateObj('ghostwu'); var obj2 = new CreateObj('衛庄'); console.log( obj1.showUserName === obj2.showUserName ); //false
從以上執行結果,可以看出obj1.showUserName和obj.showUserName不是同一個【在js中,引用類型比較的是地址, 函數是一種引用類型】,而是存在兩個不同
的內存地址,因為每個對象的屬性是不一樣的,這個沒有什么問題,但是方法執行的都是一樣的代碼,所以沒有必要復制,存在多份,浪費內存.這就是缺點
怎么解決構造函數的方法復制多次的問題?
function CreateObj(uName) { this.userName = uName; this.showUserName = showUserName; } function showUserName() { return this.userName; } var obj1 = new CreateObj('ghostwu'); var obj2 = new CreateObj('衛庄'); console.log(obj1.showUserName === obj2.showUserName); //true
把對象的方法指向同一個全局函數showUserName, 雖然解決了多次復制問題,但是全局函數非常容易被覆蓋,也就是大家經常說的污染全局變量.
比較好的解決方案?
通過原型(prototype)對象,把方法寫在構造函數的原型對象上
function CreateObj(uName) { this.userName = uName; } CreateObj.prototype.showUserName = function () { return this.userName; } var obj1 = new CreateObj('ghostwu'); var obj2 = new CreateObj('衛庄'); console.log(obj1.showUserName === obj2.showUserName); //true