構造函數其實是一個使用new運算符的函數。當使用new調用時,構造函數的內部用到的this對像會指向新創建的實例。
function Person(name,age,job){
this.name=name;
this.age=age;
this.job=job;
}
var person=new Person("Nicholas",34,'software Engineer');
在沒有使用new運算符來調用構造函數的情況下,由於該this對象是在運行時綁定的,因此直接調用Person會將該對像綁定到全局對像window上,這將導致錯誤屬性意外增加到全局作用域上。這是由於this的晚綁定造成的,在這裡this被解析成了window對象。
解決這個問題的方案是創建一個作用域安全的構造函數。首先確認this對象是否為正確的類型實例,如果不是,則創建新的實例並返回。
function Person(name,age,job){
//檢測this對象是否是Person的實例
if(this instanceof Person){
this.name=name;
this.age=age;
this.job=job;
}else{
return new Person(name,age,job);
}
}
如果使用的構造函數獲取繼承且不使用原型鏈,那麼這個繼承可能就被破壞。
function Polygon(sides){
if(this instanceof Polygon){
this.sides=sides;
this.getArea=function{
return 0;
}
}else{
return new Polygon(sides);
}
}
function Rectangle(width,height){
Polygon.call(this,2);
this.width=width;
this.height=height;
this.getArea=function{
return this.width*this.height;
};
}
var rect=new Rectangle(5,10);
alert(rect.sides);//undefined
Rectangle構造函數的作用域是不安全的。在新創建一個Rectangle實例後,這個實例通過Polygon.call繼承了sides屬性,但由於Polygon構造函數的作用域是安全的,this對象並非是Polygon的實例,因此會創建並返回一個新的Polygon對象。
由於Rectangle構造函數中的this對象並沒有得到增長,同時Polygon.call返回的值沒有被用到,所以Rectangle實例中不會有sides屬性。構造函數配合使用原型鏈可以解決這個問題。
function Polygon(sides){
if(this instanceof Polygon){
this.sides=sides;
this.getArea=function{
return 0;
}
}else{
return new Polygon(sides);
}
}
function Rectangle(width,height){
Polygon.call(this,2);
this.width=width;
this.height=height;
this.getArea=function{
return this.width*this.height;
};
}
//使用原型鏈
Rectangle.prototype=new Polygon;
var rect=new Rectangle(5,10);
alert(rect.sides);//2
這時構造函數的作用域就很有用了。