javaScript原型及继承
一、淺談原型
首先我們要知道創建對象的方法有兩種:
1.通過字面量的方式直接創建
1 var obj = { 2 name:'baimao', 3 age:21 4 }?
2.通過構造函數創建對象
1 function People(name,age) { 2 this.name = name; 3 this.age = age; 4 }而當我們使用構造函數創建對象時,對對象的屬性或者方法的設置是通過傳參的方式進行的,考慮一個問題,公有的屬性或者方法如果仍在構造函數中通過傳參設置,每次new出來的新的對象都保留有一份構造函數中的信息,且有部分信息時相同并不會更改的,比如,人生來就有四肢,能吃飯能說話等。這樣就浪費了內存,相同的信息在內存中存在了很多份(每通過構造函數new一個實例就復刻了一份相同的東西)。
而原型就是為了解決相同信息的復用問題,使用原型可以使得所有通過構造函數new出來的對象的原型指向的是同一個地址空間,避免了內存上的浪費,也使得繼承概念更合理。
這里面要指明的是,放在原型中的屬性和方法在內存中只存在一份,所有通過該構造函數new出來的對象都使用的是這一份原型。所以js中的原型是引用原型。
來聲明一下對象的 __proto__ 與構造函數的prototype區別。對象都存在__proto__ 屬性,而通過調用構造函數new出來的對象,其__proto__ 屬性是指向構造函數的prototype屬性的,而構造函數的prototype屬性本身也是一個對象,仍存在 __proto__ 屬性,這將會引入后續的原型鏈的問題,在后面會介紹。
3.為構造函數設置原型的方法
1 People.prototype.arms = 2; 2 People.prototype.eat = function() { 3 console.log(this.name + '會吃飯'); 4 } 1 var people = new People('baimao',21); 2 people.__proto__.arms = 2; 3 people.__proto__.eat = function() { 4 console.log(this.name + '會吃飯'); 5 }
?
二.js中的繼承
我們都理解的是js中實際是不存在類的概念的,所謂繼承只是通過構造函數的繼承和構造函數中的原型的繼承來實現的。但我們下面直接用類的概念來講更容易理解,假設js中存在類吧
1.構造函數的繼承
(1)首先介紹構造函數的繼承
?
function People(name,age) {this.name = name;this.age = age;}People.prototype.eat = function () {console.log(this.name + '正在吃...');}function Student(name,age) {People.call(this,name,age);//People.apply(this,arguments); }console.log(new Student('baimao',21));?
通過上圖我們可以看到通過call或者apply的方法調用父類的構造函數是可以使用父類的構造函數對子類實例進行賦值的,總結一下,也就是說通過call,apply方法可以使用父類的構造函數。但是這種方法有局限性,細心的人可能會觀察到,使用call或者apply方法繼承到的只有父類的構造方法中的屬性或者方法,父類原型中的屬性和方法不會被繼承,為了解決這一問題,我們可以通過如下方式:
2.子類原型的繼承
方法一:Student.prototype = Object.create(People.prototype);//在這里之所以要自己添加子類原型中的構造函數是因為我們直接使用//Object.create(People.prototype)創建一個對象出來給子類的原型賦值,會//覆蓋掉子類原有的構造函數,所以需要手動設置Student.prototype.constructor = Student;方法二:Student.prototype.__proto__ = People.prototype;var student = new Student('baimao',21);student.eat();console.log(student); View Code 實際中我們可以發現,通過上述兩種方式是在子類構造函數的原型的原型中添加方法,當我們通過new子類對象并調用方法時,該方法會先在子類自己的構造函數中找,找不到則在子類的原型中找,再找不到就去子類原型的原型中找,直到找到為止,否則報錯,該方法未定義 not defined
即為原型鏈的概念:
關于原型鏈:先在對象自身去找(構造函數中找),找到后調用即可;如果找不到,就去自身原型中找,找到調用即可;如果還找不到,就去原型的原型中找,找到調用即可...直到找到Object的原型,還是找不到,就拋出異常
通過繼承父類而得到的子類對象,如果繼續在子類的原型中添加父類中存在的屬性或者方法,意義上為重寫父類的方法,但實際意義上只是在子類的原型中添加了一個方法,并沒有真正覆蓋父類的方法,通過子類構造函數的原型的原型中還是可以查看到父類原型的屬性或者方法.
?關于isPrototypeOf 和 hasOwnProperty()
?1. isPrototypeOf
判斷原型和對象之間的關系
isPrototypeOf 判斷原型和對象之間的關系:判斷對象是否存在于另一個對象的原型鏈中
2. hasOwnProperty()
?用于指示一個對象自身(不包括原型鏈)是否具有指定名稱的屬性。 如果有,返回true,否則返回false。
?3. in
? 可以查看原型鏈中是否存在某屬性
? console.log('family' in dog)
?
注意我們在修改原型時不能使用對象的打點調用:
dog.family = '哈哈';這樣寫是為對象新增加一個屬性,不會修改到原型,通過打點調用的方法相當于只能get不能set
3.修改父類原型中的方法
子類繼承父類,對父類的原型中修改原先存在的屬性,修改只供自身使用,對父類沒有影響但如果子類對父類的原型中添加了父類不存在的屬性,添加操作會影響父類。
function Animal(family) {this.family = family;Animal.prototype.run = function () {console.log('動物都會跑');}Animal.prototype.legs = 4;}function Dog(family, name, color) {Animal.call(this, family);this.name = name;this.color = color;}// 用一個中間變量obj 作為橋梁去完成子類對父類的繼承var obj = Object.create(Animal.prototype);Dog.prototype = obj;Dog.prototype.constructor = Dog;Dog.prototype.skill = function () {console.log('看家');}//修改了父類Dog.prototype.__proto__.add = function () {console.log('這是一個通過子類去修改父類的測試');}//會發現中間變量被改,所以js中對象的拷貝是引用拷貝,即拷貝地址的值拷貝 console.log(obj);Dog.prototype.__proto__.legs = 2;var animal = new Animal('test');//在這里輸出父類對象,會發現add方法增添了,但父類的legs屬性并沒有被改 animal.add();console.log(animal.legs); View Code執行結果如下:
?
三、ES6中的繼承新語法?
在ES6中新增了class和extends關鍵字
class People {// 構造函數 constructor(name, age) {//初始化屬性this.name = name;this.age = age;}eat(food) {console.log(this.name + '吃:' + food);}}//設置原型中的內容People.prototype.legs = 2;//創建People對象var people = new People('baimao', 21);people.eat('蘋果');console.log(people);class Man extends People {constructor(name, age, sex) {//相當于會自動的去執行People的構造函數 super(name, age);//新增,擴展自己的屬性this.sex = sex;}playMJ(hours) {console.log(this.name + '打了' + hours + '個小時麻將');}}var man1 = new Man('翠花', 28, '男');man1.playMJ(2); View CodeES6中類的數據類型就是函數,類本身指向構造函數
在ES6中,除了constructor中的屬性是放在類中,其余定義的方法都是放在構造函數的prototype中.
子類繼承父類,使用super關鍵字調用父類的構造方法
?
?
?
轉載于:https://www.cnblogs.com/baimaoccc/articles/baimaoccc.html
總結
以上是生活随笔為你收集整理的javaScript原型及继承的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Codeforces A - Bear
- 下一篇: WHYZOJ-#60 工资(二分)