課程介紹:
重點: 原型鏈
* 重點:不同的繼承
* 原型的另一個作用
* 重點:this指向要知道到底是誰
*
* 複習原型
* 原型鏈
* 原型的指向是否可以改變
* 繼承
* 如何實現繼承
* 原型的方式繼承
* 借用構造函數繼承
* 組合繼承
* 拷貝繼承
*
* 函數的不同的表現方式
* 函數的調用的不同的方式
*
* this指向
* 嚴格模式
*
* 函數也是對象---記住就可以了
* 對象不一定是函數
*
* 數組中的函數如何調用
* apply和call講了
03原型與原型鏈
<script>
//使用對象---->使用對象中的屬性和對象中的方法,使用對象就要先有構造函數
//構造函數
function Person(name,age) {
//屬性
this.name=name;
this.age=age;
//在構造函數中的方法
this.eat=function () {
console.log("吃好吃的");
};
}
//添加共享的屬性
Person.prototype.sex="男";
//添加共享的方法
Person.prototype.sayHi=function () {
console.log("您好啊,怎麼這麼帥,就是這麼帥");
};
//實例化對象,並初始化
var per=new Person("小明",20);
per.sayHi();
//如果想要使用一些屬性和方法,並且屬性的值在每個對象中都是一樣的,方法在每個對象中的操作也都是一樣,那麼,爲了共享數據,節省內存空間,是可以把屬性和方法通過原型的方式進行賦值
console.dir(per);//實例對象的結構
console.dir(Person);//構造函數的結構
//實例對象的原型__proto__和構造函數的原型prototype指向是相同的
//實例對象中的__proto__原型指向的是構造函數中的原型prototype
console.log(per.__proto__==Person.prototype);
//實例對象中__proto__是原型,瀏覽器使用的
//構造函數中的prototype是原型,程序員使用的
//原型鏈:是一種關係,實例對象和原型對象之間的關係,關係是通過原型(__proto__)來聯繫的
</script>
圖片解析
04原型的指向是否可以改變
//人的構造函數
function Person(age) {
this.age=10;
}
//人的原型對象方法
Person.prototype.eat=function () {
console.log("人的吃");
};
//學生的構造函數
function Student() {
}
Student.prototype.sayHi=function () {
console.log("嗨,小蘇你好帥哦");
};
//學生的原型,指向了一個人的實例對象
Student.prototype=new Person(10);
var stu=new Student();
stu.eat();----人的吃
stu.sayHi();---會報錯,應爲學生原型指向person,person裏面沒有sayhi
//原型指向可以改變
//實例對象的原型__proto__指向的是該對象所在的構造函數的原型對象
//構造函數的原型對象(prototype)指向如果改變了,實例對象的原型(__proto__)指向也會發生改變
//原型的指向是可以改變的
//實例對象和原型對象之間的關係是通過__proto__原型來聯繫起來的,這個關係就是原型鏈
05原型最終指向了哪裏
function Person() {
}
Person.prototype.eat=function () {
console.log("吃東西");
};
var per=new Person();
console.dir(per);
console.dir(Person);
//實例對象中有__proto__原型
//構造函數中有prototype原型
//prototype是對象
//所以,prototype這個對象中也有__proto__,那麼指向了哪裏
//實例對象中的__proto__指向的是構造函數的prototype
//所以,prototype這個對象中__proto__指向的應該是某個構造函數的原型prototype
//Person的prototype中的__proto__的指向
//console.log(Person.prototype.__proto__);
//per實例對象的__proto__------->Person.prototype的__proto__---->Object.prototype的__proto__是null
console.log(per.__proto__==Person.prototype); true
console.log(per.__proto__.__proto__==Person.prototype.__proto__); true
console.log(Person.prototype.__proto__==Object.prototype); true
console.log(Object.prototype.__proto__); null
06原型指向和如何添加方法
function Person(age) {
this.age=age;
}
//人的原型中添加方法
Person.prototype.eat=function () {
console.log("一方園地1在吃東西");
};
//學生構造函數
function Student(sex) {
this.sex=sex;
}
//學生的原型中添加方法----先在原型中添加方法
Person.prototype.sayHi=function () {
console.log("一方園地1");
};
//改變了原型對象的指向
Student.prototype=new Person(10);
Student.prototype.eat=function () {
console.log("一方園地2在吃東西");
};
Student.prototype.sayHi=function () {
console.log("一方園地2");
};
var stu=new Student("男");
stu.eat(); //一方園地2吃東西
stu.sayHi(); //一方園地2
下一個案例重複總結:
function Person(age) {
this.age = age;
}
//指向改變了
Person.prototype = {
eat: function () {
console.log("吃");
}
};
//先添加原型方法
Person.prototype.sayHi = function () {
console.log("方園您好");
};
var per = new Person(10);
per.sayHi();
上面運行結果是:方園,您好。分析:因爲前面雖讓指向了一個新的對象,但後面又重新更新了原型,有了新的指向。
那麼下面這樣改變一下---------->
function Person(age) {
this.age = age;
}
//指向改變了,下面是個大括號,代表着一個對象。
Person.prototype = {
eat: function () {
console.log("吃");
}
};
//先添加原型方法
Person.prototype.sayHi = function () {
console.log("方園您好");
};
Person.prototype = {
eat: function () {
console.log("吃");
}
};
var per = new Person(10);
per.sayHi();
上面結果會報錯》
爲啥會這樣?因爲指向改變了,大括號代表新的對象,代表對象改變了,之前做的原型吃是沒有用的!這句話是僅僅我自己的理解
07實例對象中的和原型對象中的屬性重名問題
首先先給你分析一下何爲屬性:看一下下面的代碼
function Person(age,sex) {
this.age=age;
this.sex=sex;
}
Person.prototype.sex="女";
var per=new Person(10,"男");
console.log(per.sex);//男
console.log(per.fy);//undefind
console.log(fy); //報錯
//因爲JS是一門動態類型的語言,對象沒有什麼,只要點了,那麼這個對象就有了這個東西,沒有這個屬性,只要對象.屬性名字,(例如上面的per.fy)對象就有這個屬性了,但是,該屬性沒有賦值,所以,結果是:undefined.而沒有點,(僅僅fy)則沒有這個屬性,會報錯
function Person(age,sex) {
this.age=age;
this.sex=sex;
}
Person.prototype.sex="女";
var per=new Person(10,"男");
console.log(per.sex);
Person.prototype.sex="一方園地";
per.sex="二哈";
console.log(per.sex);
console.dir(per);
此處最後的的per.sex="二哈"; 代表重新更改他的屬性sex
//實例對象訪問這個屬性,應該先從實例對象中找,找到了就直接用,找不到就去指向的原型對象中找,找到了就使用,找不到呢?
//通過實例對象能否改變原型對象中的屬性值?不能
//就想改變原型對象中屬性的值,怎麼辦?直接通過原型對象.屬性=值;可以改變(就是上面的per.sex=二哈)
08一個很神奇的原型鏈
原型鏈:實例對象和原型對象之間的關係,通過__proto__來聯繫
var divObj=document.getElementById("dv");
console.dir(divObj);
//divObj.__proto__---->HTMLDivElement.prototype的__proto__--->HTMLElement.prototype的__proto__---->Element.prototype的__proto__---->Node.prototype的__proto__---->EventTarget.prototype的__proto__---->Object.prototype沒有__proto__,所以,Object.prototype中的__proto__是null
09繼承
* 面向對象編程思想:根據需求,分析對象,找到對象有什麼特徵和行爲,通過代碼的方式來實現需求,要想實現這個需求,就要創建對象,要想創建對象,就應該顯示有構造函數,然後通過構造函數來創建對象.,通過對象調用屬性和方法來實現相應的功能及需求,即可
* 首先JS不是一門面向對象的語言,JS是一門基於對象的語言,那麼爲什麼學習js還要學習面向對象,因爲面向對象的思想適合於人的想法,編程起來會更加的方便,及後期的維護....
* 面向對象的編程語言中有類(class)的概念(也是一種特殊的數據類型),但是JS不是面向對象的語言,所以,JS中沒有類(class),但是JS可以模擬面向對象的思想編程,JS中會通過構造函數來模擬類的概念(class)
*
*
* 小明,小紅,小麗,小白,小花 都是人
* 共同的特徵和行爲
* 特徵--->屬性
* 行爲---方法
*
* 面向對象的特性:封裝,繼承,多態
*
* 封裝:就是包裝
* 一個值存儲在一個變量中--封裝
* 一坨重複代碼放在一個函數中--封裝
* 一系列的屬性放在一個對象中--封裝
* 一些功能類似的函數(方法)放在一個對象中--封裝
* 好多相類似的對象放在一個js文件中---封裝
*
* 繼承: 首先繼承是一種關係,類(class)與類之間的關係,JS中沒有類,但是可以通過構造函數模擬類,然後通過原型來實現繼承
* 繼承也是爲了數據共享,js中的繼承也是爲了實現數據共享
*
* 原型作用之一:數據共享,節省內存空間
* 原型作用之二:爲了實現繼承
*
* 繼承是一種關係:
*
* 父類級別與類級別的關係
*
* 例子:
*
* 小楊--->人, 姓名, 有錢, 帥, 有功夫--降龍十八掌
* 小楊子-->人,
* 繼承:
* 姓氏----繼承
* 外表----繼承
* 財產----繼承
* 功夫---繼承
*
*
* 人: 姓名, 性別, 年齡 ,吃飯, 睡覺
*
* 學生類別: 姓名, 性別, 年齡 ,吃飯, 睡覺 學習行爲
* 老師類別: 姓名, 性別, 年齡 ,吃飯, 睡覺 工資,教學行爲
* 程序員: 姓名, 性別, 年齡 ,吃飯, 睡覺 工資, 敲代碼
* 司機類別: 姓名, 性別, 年齡 ,吃飯, 睡覺 工資 開車
*
*
* 動物類別: 體重, 顏色, 吃
* 狗類別: 體重,顏色, 吃, 咬人
* 二哈類別: 體重,顏色, 吃, 咬人 逗主人開心,汪汪,你好帥
*
*
*
* 多態:一個對象有不同的行爲,或者是同一個行爲針對不同的對象,產生不同的結果,要想有多態,就要先有繼承,js中可以模擬多態,但是不會去使用,也不會模擬,(有了繼承,纔能有多態)
*
//例子:
//人,都有姓名,性別,年齡, 吃飯, 睡覺, 玩
//學生,都有姓名,性別,年齡, 成績, 吃飯, 睡覺, 玩 ,學習的行爲
//js中通過原型來實現繼承(相同的代碼太多,造成了代碼的冗餘(重複的代碼))
function Person(name,age,sex) {
this.name=name;
this.sex=sex;
this.age=age;
}
Person.prototype.eat=function () {
console.log("人可以吃東西");
};
Person.prototype.sleep=function () {
console.log("人在睡覺");
};
Person.prototype.play=function () {
console.log("生活就是不一樣的玩法而已");
};
function Student(score) {
this.score=score;
}
//改變學生的原型的指向即可==========>學生和人已經發生關係
Student.prototype=new Person("小明",10,"男");
Student.prototype.study=function () {
console.log("學習很累很累的哦.");
};
var stu=new Student(100);
console.log(stu.name);
console.log(stu.age);
console.log(stu.sex);
stu.eat();
stu.play();
stu.sleep();
console.log("下面的是學生對象中自己有的");
console.log(stu.score);
stu.study();
10繼承案例
動物有名字,有體重,有吃東西的行爲
小狗有名字,有體重,有毛色, 有吃東西的行爲,還有咬人的行爲
哈士奇名字,有體重,有毛色,性別, 有吃東西的行爲,還有咬人的行爲,逗主人開心的行爲
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.prototype.bitePerson=function () {
console.log("哼~汪汪~咬死你");
};
//哈士奇
function ErHa(sex) {
this.sex=sex;
}
ErHa.prototype=new Dog("黑白色");
ErHa.prototype.playHost=function () {
console.log("哈哈~咬壞衣服,咬壞桌子,拆家..嘎嘎...好玩,開心不,驚喜不,意外不");
};
var erHa=new ErHa("雄性");
console.log(erHa.name,erHa.weight,erHa.color);
erHa.eat();
erHa.bitePerson();
erHa.playHost();