案例一:使用工廠方法建立物件
function createPerson(name,age,gender){
//建立一個新物件
var obj = new Object();
//向物件新增屬性
obj.name = name;
obj.age = age;
obj.gender = gender;
obj.sayName = function(){
alert(this.name);
};
//將新的物件返回
return obj;
}
var obj2 = createPerson("豬八戒",28,"男");
var obj3 = createPerson("白骨精","16","女");
var obj4 = createPerson("蜘蛛精","18","女");
obj3.sayName();
複製程式碼
建構函式的執行流程
- 立刻建立一個新的物件
- 將新的物件設定為函式中this,在建構函式中可以使用this來引用新建的物件
- 逐行執行函式中的程式碼
- 將新建的物件作為返回值返回
使用同一個建構函式建立的物件,我們稱為一類物件,也將一個建構函式稱為一個類。比如如下的Person和Dog就是兩個類。
通過一個建構函式建立的物件叫做該建構函式的一個例項。
案例二:使用建構函式建立物件
function Person(name , age , gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = function(){
alert(this.name);
};
function Dog(){
}
var per = new Person("孫悟空",18,"男");
var per2 = new Person("白骨精",16,"女");
var per3 = new Person("蜘蛛精",18,"女");
var dog = new Dog();
console.log(per);//Person……
console.log(dog);//Dog
//使用instanceof可以檢查一個物件是否是一個類的例項,如果是則返回true。
console.log(per instanceof Person);//true
console.log(dog instanceof Object);//true所有通過建構函式建立的物件都是Object類的例項,都是true
複製程式碼
關於this
- 當以函式形式呼叫時,this是window
- 當以方法形式呼叫時,誰呼叫this就是誰
- 當以建構函式形式呼叫時,this就是新建立的那個物件。
建構函式的優化
//建構函式每執行一次就會建立一個新的sayName方法,也就是所有例項的sayName都是唯一的。這就導致建構函式每執行一次,就會建立一次方法。
function Person(name , age , gender){
this.name = name;
this.age = age;
this.gender = gender;
this.sayName = fun;
}
function fun(){
alert("Hello大家好,我是:"+ this.name);
}
var per = new Person("孫悟空",18,"男");
var per2 = new Person("豬八戒",16,"女");
console.log(per.sayName==per2.sayName);
//得出的結果是true,因為它兩的值其實就是fun函式本身,而不是fun函式呼叫後的值。
複製程式碼
原型物件
我們所建立的每一個函式,解析器都會向函式中新增一個屬性prototype,這個屬性對應著一個物件,這個物件就是我們所謂的原型物件。
如果函式作為普通函式呼叫,prototype沒有任何作用。
當函式以建構函式的形式被呼叫時,它所建立的物件中都會有一個隱含的屬性,指向該建構函式的原型物件,我們可以通過__prto__來訪問該屬性。
原型物件就相當於一個公共的區域,所有同一個類的例項都可以訪問這個原型物件,我們可以將物件中共有的餓內容,統一設定到原型物件中。
當我們訪問物件的一個屬性或方法時,它會先在物件自身中尋找,如果有則直接使用,如果沒有則會去原型物件中尋找,如果找到則直接使用。
建立建構函式時,可以將那些物件共有的屬性和方法,統一新增到建構函式的原型物件中,這樣不用分別為每一個物件新增,也不會影響到全劇作用域。
function MyClass(){
}
//向MyClass原型中新增屬性a
MyClass.prototype.a = 123;
//向MyClass原型中新增一個方法
MyClass.prototype.sayHello = function(){
alert("hello");
};
var mc = new MyClass();
var mc2 = new MyClass();
//console.log(MyClass.prototype);
//console.log(mc2.__proto__ == MyClass.prototype);
//向mc新增a屬性
mc.a = "我是mc中的a";
//console.log(mc2.a);這裡的結果就不是123了,因為mc2物件本身有一個a屬性,所以不再向建構函式的原型物件查詢
mc.sayHello();
複製程式碼
function Person(name , age , gender){
this.name = name;
this.age = age;
this.gender = gender;
//this.sayName = fun;
}
//將sayName方法在全劇作用域中定義
/*將函式定義在全域性作用域,汙染了全域性作用域的名稱空間,而且也不安全*/
/* function fun(){
alert("Hello大家好,我是:"+ this.name);
};*/
//向原型中新增sayName方法
Person.prototype.sayName = function(){
alert("Hello大家好,我是:"+ this.name);
};
var per = new Person("孫悟空",18,"男");
var per2 = new Person("豬八戒",16,"女");
per.sayName();//Hello大家好,我是:孫悟空
per2.sayName();//Hello大家好,我是:豬八戒
console.log(per.sayName==per2.sayName);
//得出的結果是true,因為它兩的值其實就是fun函式本身,而不是fun函式呼叫後的值。
複製程式碼
toString方法
function Person(name , age , gender){ this.name = name; this.age = age; this.gender = gender; } //修改Person原型的toString Person.prototype.toString = function(){ return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]"; } //建立一個Person例項 var per = new Person("孫悟空",18,"男"); var per2 = new Person("豬八戒",16,"女"); //當我們直接在頁面中列印一個物件時,實際上是輸出的物件的toString()方法的返回值 //如果我們希望在輸出物件時,不輸出[object object],可以為物件新增一個toString()方法 /*per.toString = function(){ return "我是一個快樂的人"; };*/ //var result = per.toString(); //console.log("result = " + result); //console.log(per.__proto__.__proto__hasOwnProperty("toString")); console.log(per); console.log(per.sayName==per2.sayName); //得出的結果是true,因為它兩的值其實就是fun函式本身,而不是fun函式呼叫後的值。