一、函數的原型
1.創建對象的三種方式:
字面量、調用系統的構造函數、自定義構造函數
2.工廠模式創建對象:
function createObject(name,age) {
var obj=new Object();
obj.name=name;
obj.age=age;
obj.sayHi=function () {
console.log("您好");
};
return obj;
};
3.原型
- 每個構造函數都有一個原型對象prototype,這個對象中有一個構造器constructor指向了這個構造函數
- 每個通過構造函數實例化出來的實例對象中都有一個屬性__proto__,這個屬性指向一個原型對象,這個對象和上面的原型對象prototype是同一個,如下圖:
- 我們把需要共享的屬性和方法寫在原型中,節省內存空間。實例對象中的方法可以相互調用,原型中的方法也可以相互調用。
- 簡單的原型寫法:
Student.prototype = {
//必須手動修改構造器的指向
constructor:Student,
height: "188",
weight: "70kg",
study: function () {
console.log("學習真好");
}
};
4.原型鏈
- 原型鏈:是一種關係,實例對象和原型對象的關係是通過__proto__來聯繫的,一個實例對象訪問某個屬性或方法時先在自己的內存中尋找某個屬性和方法,如果沒找到,再在__proto__屬性指向的對象中尋找,如果還是沒找到,則返回uundefined
- 函數的原型對象prototype也是一個對象,這個對象也有__proto__屬性,它指向了Object函數的原型(Object.prototype),而Object的原型對象prototype中的__proto__屬性指向了null
二、繼承
- 改變原型的指向實現繼承:讓子類的構造函數的原型指向父類的一個實例對象,從而實現繼承
function Animal(name,weight) {
this.name=name;
this.weight=weight;
}
//動物的原型的方法
Animal.prototype.eat=function () {
console.log("天天吃東西");
};
//狗的構造函數
function Dog(color) {
this.color=color;
}
Dog.prototype=new Animal("哮天犬","50kg");//實現繼承,Dog的實例對象可以調用eat方法
- 使用call方法繼承
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
Person.prototype.sayHi = function () {
console.log("您好");
};
function Student(name,age,sex,score) {
//借用構造函數
Person.call(this,name,age,sex);//構造函數名字.call(當前對象,屬性,屬性,屬性....);
this.score = score;
}
因爲改變原型指向的繼承方法直接初始化了屬性,繼承過來的屬性的值都是一樣的了,而這種繼承方法就解決了這個問題,但缺陷是父級類別中的方法不能繼承
- 組合繼承
function Person(name,age,sex) {
this.name=name;
this.age=age;
this.sex=sex;
}
Person.prototype.sayHi=function () {
console.log("你好");
};
function Student(name,age,sex,score) {
//借用構造函數:屬性值重複的問題
Person.call(this,name,age,sex);
this.score=score;
}
//改變原型指向----繼承
Student.prototype=new Person();//不傳值
Student.prototype.eat=function () {
console.log("吃東西");
};
var stu=new Student("小黑",20,"男","100分");
即改變原型的指向,又使用call方法,屬性和方法都被繼承了
- 拷貝繼承
用for-in循環將一個對象中的屬性和方法複製到另一個對象中,很少用
三、函數
1.函數兩種表達
- 函數聲明
function f1() {
console.log("我是函數");
}
f1();
- 函數表達式
var ff=function () {
console.log("我也是一個函數");
};
ff();
區別:兩種函數表達在進行預解析的時候會有不同,函數聲明如果放在if-else的語句中,在IE8的瀏覽器中會出現問題,儘量多用函數表達式
2.函數中的this指向問題
- 普通函數和定時器中的this指向window
- 對象中、構造函數中、原型對象中的this指向實例對象
3.函數也是對象
- 每個函數都是對象,所有函數都是構造函數Function的實例對象,是對象就有__proto__屬性,它指向構造函數Function的原型對象,而Function的原型對象prototype中的__proto__屬性指向Object的原型對象
- 這裏有一點複雜,需要細細理解。可以肯定一點,如果沒有改變原型的指向的話,每個構造函數的原型對象中的__proto__都指向Object的原型對象
~待續