javascript高階程式設計--建立物件的那些事兒
瞭解完了物件,也瞭解了常用的建立物件的方式--建構函式式和字面量式,那麼除此自外,還有哪些建立物件的方式呢?
工廠模式
說白了就是一個封裝函式,在函式內部定義物件的細節,最後返回之
function createObj(name,job,age){ var obj = new Object(); obj.name = name; obj.job = job; obj.age = age; obj.logAge = function(){ console.log(this.age)//該函式執行的時候是在物件中執行的所以,this指向物件本身 } return obj } console.log(createObj("張三","小白",23))//是一個物件; var person = createObj("李四","會計",23);//person儲存了一個指標,指向新建立的物件; var person1 = person;//共同指向同一個物件 console.log(person.logAge);//23 console.log(person1);//還是一個物件
建構函式模式
a).由建構函式創建出來的是一個物件,
b).建構函式內部的this指向的是new 出來的例項物件;
c).例項.constructor是一個指標,指向例項的建立者--建構函式,預設呼叫的是prototype物件的constructors屬性;
function CreateObj(name, job, age){ // var hobby = "作詩"; this.name = name; this.job = job; this.age = age ; this.logAge = function(){ console.log(this.age) } } var person_new = new CreateObj("王五","財務",27);//person_new是一個物件; var person_new1 = new CreateObj("吳六", "飯店老闆", 46);//person_new是一個物件; person_new.logAge();//27 person_new1.logAge()//46; console.log(person_new.constructor)//建構函式本身; console.log(person_new1 instanceof Object)//因為畢竟person_new1也是一個物件嘛! //建構函式當作普通函式呼叫; CreateObj("李白","詩人",48);//this此時指向的是window,因為呼叫的時候是在全域性環境中呼叫的; console.log(name)//李白
建構函式.prototype(原型模式):
每一個函式都有該屬性,是一個指標,指向一個物件(原型物件),該物件包含由該建構函式建立的所有例項物件所共有的屬性和方法;與此同時,該原型物件也包含著一個constructor屬性(是一個指標,指向擁有該原型物件的建構函式)
1.例項.__proto__:在通過建構函式建立例項後,該例項有一個屬性__proto__,是一個指標,指向該建構函式的原型物件。也就相當於,例項.__proto__ = 建構函式.prototype;
2.訪問建構函式例項的屬性的搜尋順序:function Plant(height,classify){ this.height = height; this.class = classify; } Plant.prototype.name = "水稻";//將來所有的例項都將擁有屬性name,值為“水稻” console.warn(Plant.prototype.constructor)//建構函式本身; Plant.prototype.constructor.prototype.loca = "河南·許昌"// console.warn(Plant.prototype.constructor)//建構函式本身; var plant_xiaomai = new Plant(137,"旱季作物");//建構函式的例項 console.log(plant_xiaomai);//一個物件 console.log(plant_xiaomai.name)//水稻 console.log(plant_xiaomai.loca);//河南.許昌 console.log(plant_xiaomai.__proto__)//原型物件
當為例項物件新增一個屬性的時候,如果該屬性名和原型物件中的屬性名一樣,那麼該屬性就會遮蔽原型物件中的對應屬性,結果是會阻止我們 訪問原型中的對應屬性(但不會修改),因為在訪問例項中的某屬性的時候,首先會訪問例項中的屬性,如果有就停止搜尋,如果沒有就往建構函式的的原型物件中尋找。
2.1例項.hasOwnProperty(prop):就是用來檢測屬性prop是存在於例項中還是對應建構函式的原型物件中,當存在於例項中時返回true,畢竟顧名思義--就是看看例項中有沒有屬性prop嘛,
2.2 原型模式也是有缺點的,其最大的缺點就是例項物件的屬性高度共享,因為prototype中的屬性是所有建構函式例項所共有的。 因此當修改原型物件中的屬性的時候,其它例項訪問該屬性的時候也會發生改變
// 訪問例項中的屬性的時候,其訪問機制是,首先會在例項中的屬性中尋找,如果找到了就停止尋找,如果找不到就在該例項的
//建構函式的原型中尋找....
function Xmw (name,sex,age){
this.name = name;
this.age = age;
this.sex = sex;
}
Xmw.prototype.school = "陳楊寨楊村廟小學";
var dmw = new Xmw ("董曼文","女",7);//一個物件
console.log(dmw.school);//陳楊寨楊村廟小學
console.log(dmw.__proto__);//指向建構函式的原型物件
console.log(dmw.__proto__ == Xmw.prototype);//true
var dhl = new Xmw("董涵琳","女",7);
dhl.school = "吳劉小學"
console.log(dhl.school)//吳劉小學;
console.log(dhl.hasOwnProperty("school"));//true
delete dhl.school;//刪除例項屬性
console.log(dhl.school)//楊村廟小學,沒有了同名的例項屬性,就會尋找該例項的對應建構函式的原型中的屬性
建構函式和原型的正確開啟方式1.建構函式+prototype混用(推薦):建立自定義型別的最常見方式,就是組合使用建構函式模式與原型模式。建構函式(可傳參)模式用於定義實
例屬性,而原型模式用於定義方法和共享的屬性。
function Animal(name,age,weight){
this.name = name;
this.age = age;
this.weight = weight;
this.height = 1.03;
}
Animal.prototype = {
constructor:Animal,//顯式指定constructor指標的指向
sayAniName:function(){
console.log(this.name)
}
}
var cat = new Animal("傲嬌Cat",1,5);//一個物件
console.log(cat);
cat.sayAniName()//傲嬌Cat
cat.height =1.30
console.log(cat.height)//1.30
var dog = new Animal("憨厚Dog",2,20);//另一個物件
console.log(dog.height)//1.03,因為dog例項物件中的height屬性是1.03
2. 動態原型模式(不推薦) function Animal_1(name, age, weight){
this.name = name;
this.age = age;
this.weight = weight;
this.height = 1.03;
if(typeof this.sayAniName != "function"){//當例項中沒有sayAniName屬性的時候,
//這段程式碼只會在初次呼叫建構函式時才會執行。此後,原型已經完成初始化
Animal_1.prototype.sayAniName = function(){
console.log(this.name)
}
}
}
var cat1 = new Animal_1("粘人貓",2,9);//新建立的例項,此時就會執行if語句,因為此時滿足跳撿,在此之後,當再次呼叫該建構函式的時候不執行if語句了
//,因為此時例項已經有了公用的方法了
cat1.sayAniName()//粘人貓
var dog1 = new Animal_1("淘氣狗",2,10);
dog1.sayAniName()//淘氣狗
3.寄生建構函式模式(不推薦):說白就是一個建構函式,在函式體內新建一個物件,然後定義物件的一些細節,最後返回物件 然後呼叫的時候使用 new 操作符 function Plant(classify,iswatered){
var plant = new Object();
plant.classify = classify;
plant.iswatered = iswatered;
return plant
}
var apple = new Plant("灌木類",false);//既可以被當作建構函式使用
var orange = Plant("草",true);//也可也被當作普通的函式使用
console.log(apple);
console.log(orange);
4.穩妥建構函式模式(一般用在安全性要求高的環境中):和寄生建構函式模式差不多,只不過在該模式下,新建立物件的例項方法不引用this(也就是說,在建構函式中定義物件例項細節的時不能使用this),其二不使用new操作符呼叫建構函式(要像呼叫普通函式那樣呼叫)function Person(name, age, weight) {
var person = new Object();
person.alertName = function () {
alert(name)
}
return person
}
//新物件
Person("張三", 23, 170).alertName();//張三
注意:
函式物件有 __proto__ 屬性,又有 prototype 屬性。普通物件只有 __proto__ 屬性,沒有 prototype 屬性。
console.log(obj.__proto__)//Object物件
console.log(obj.prototype)//undefined
function abs(){
console.log(1)
}
console.log(abs.__proto__)//function物件的原型
console.log(abs.prototype)//將abs其視為一個物件,物件的原型是Object
Function.prototype 比較特殊,是個空函式,因為Function是一個建構函式,建構函式.prototype指向該建構函式的原型物件
typeof Function.prototype 輸出 “function” 但是它不能當成構造器,Function.prototype.prototype 為 undefined
Object.prototype.__proto__ 為 null,原型鏈到這裡結束。