日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

JavaScript之继承和原型

發布時間:2023/12/20 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JavaScript之继承和原型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、類的繼承與對象的原型繼承:

? ? ? ? JavsScript不存在“類”的概念,都是“對象”。Java中如果想擁有某個類的屬性和方法,需要使用extends關鍵字繼承這個類。但是JavaScript不同于Java中的類的繼承,如果想擁有像某個對象的屬性和方法,需要使用prototype指定對象的原型對象。例如:

var tom = {name: 'tom',play: function () {console.log(this.name + ' like playing...');} };

? ? ? ?現在要創建另一個對象Jim,但是Jim除了像tom一樣,有名字、喜歡玩之外,他還愛學習,最笨的辦法可以這樣定義:

var jim = {name: 'jim',play: function () {console.log(this.name + ' like playing...');},study: function () {console.log(this.name + ' like studying...');} };

? ? ? ?但如果使用原型可以這樣定義:

var jim = {name: 'jim',study: function () {console.log(this.name + ' like studying...');} }; jim.__proto__ = tom;jim.name //jim jim.play(); //jim like playing... jim.study(); //jim like studying...

? ? ? ?在編寫JavaScript代碼時,不要輕易用__proto__去改變對象的原型,按照標準__proto__是不對外公開的,但是chrome的引擎卻將他暴露了出來成為了一個公有屬性,我們可以對其進行訪問和賦值。但IE瀏覽器是不能訪問這個屬性的,所以不推薦大家直接操作這個屬性,以免造成瀏覽器兼容問題。通常我們可以使用Object.create(obj),傳入原型對象即可創建一個以指定對象為原型的新對象,比如:

var jim = Object.create(tom); jim.name = 'jim'; jim.study = function(){console.log(this.name + ' like studying...');}; jim.name //jim jim.play(); //jim like playing... jim.study(); //jim like studying...

二、原型:

? ? ? ??JavaScript對每個創建的對象都會設置一個原型__proto__,指向它的原型對象。當我們訪問某個對象的屬性時,JavaScript引擎先在當前對象上查找該屬性,如果沒有找到,就到其原型對象上找,如果還沒有找到,就一直上溯到Object.prototype對象,最后,如果還沒有找到,就只能返回undefined。prototype是函數的一個屬性,只有Function類型的對象才具有prototype屬性。例如創建一個數組對象:

var arr = [1, 2, 3];

其原型鏈為:arr ——>?Array.prototype ——> Object.prototype ——> null,Array.prototype定義了indexOf()、shift()等方法,因此在所有的Array對象上都可以直接調用這些方法。再比如創建一個函數結象:

function foo() {return 0; }

函數也是一個對象,它的原型鏈是:foo ——> Function.prototype ——> Object.prototype ——> null,由于Function.prototype定義了apply()等方法,因此所有函數都可以調用apply()方法。很容易想到,如果原型鏈很長,那么訪問一個對象的屬性就會因為花很多時間查找而變得更慢,因此要注意不要把原型鏈搞得太長。? ? ? ?

三、構造函數:

? ? ? ??可以把構造函數理解為一個普通的函數,但是這個普通的函數可以在調用時使用new關鍵字調用,并返回新創建的對象(不需要顯式寫return this),this則會自動指向這個新創建的對象。為了區分普通函數和構造函數,按照約定,構造函數首字母應當大寫,而普通函數首字母應當小寫。另外:新創建的對象的constructor屬性始終指向創建該對象的構造函數本身。例如:

function Student(name) {this.name = name;this.study = function () {console.log(this.name + ' is studying ...');} } var tom = new Student('tom'); tom.name //tom tom.study() //tom is studying ... tom.constructor //Student(name) {// this.name = name;// this.study = function () {// console.log(this.name + ' is studying ...');// }//}

其原型鏈為:tom ——> Student.prototype ——> Object.prototype ——> null,用關鍵字new創建的對象還獲得了一個constructor屬性,該屬性指向這個構造函數本身。關系如下圖所示:

tom.constructor === Student.prototype.constructor; //true Student.prototype.constructor === Student; //true Object.getPrototypeOf(tom) === Student.prototype; //true tom instanceof Student; //true

如果修改Student的prototype的某個屬性,Student創建的對象的constructor依然為Student

//修改Student原型的某個屬性,而不是全部覆蓋其原型 Student.prototype.study = function() {console.log(this.name + ' is not studying ...'); }; var b = new Student("Bob"); b.constructor===Student //true

但如果覆蓋掉Student的prototype,Student創建的對象的constructor則變為Object

//覆蓋Student的原型 Student.prototype = {study: function(){console.log(this.name + ' is not studying ...');} }; var b = new Student("Bob"); b.constructor===Student //false b.constructor===Object //true

? ? ? ? 這是因為覆蓋Student的prototype時實際做的操作是:

Student.prototype = new Object({study: function(){console.log(this.name + ' is not studying ...');} });

? ? ? ? 所以對象的constructor指向的是Object而非Student,可以用以下方法修正這個錯誤:

Student.prototype.constructor=Student;

四、原型鏈的維護:

? ? ? ??方式1:

? ? ? ? 基于上面的示例,如果創建SeniorStudent對象,例如:

function SeniorStudent(name) {Student.call(this, name);this.seniorStudy = function () {console.log(this.name + ' is seniorStudying ...');} }

要使原型鏈變為:new SeniorStudent() ——> SeniorStudent.prototype ——> Student.prototype ——> Object.prototype ——> null,因為現在的SeniorStudent.prototype和Student.prototype的原型鏈都是到Object.prototype的,所以需要重新維護原型鏈:需要借助一個中間對象來實現正確的原型鏈,這個中間對象的prototype要指向Student.prototype,SeniorStudent.prototype要指向這個中間對象的對象,SeniorStudent.prototype的constructor屬性要指向SeniorStudent本身,關系如下圖所示:

?代碼實現如下:

//空函數F: function F() { } //把F.prototype指向Student.prototype F.prototype = Student.prototype; //把SeniorStudent.prototype指向中間對象F的對象 SeniorStudent.prototype = new F(); //把SeniorStudent.prototype的constructor修復為SeniorStudent SeniorStudent.prototype.constructor = SeniorStudent;

可以驗證該原型鏈已修改為期望的順序:

//創建lilei對象 var lilei = new SeniorStudent('LiLei');lilei.name; //LiLei lilei.study(); //LiLei is studying ... lilei.seniorStudy(); //LiLei is seniorStudying ...//驗證原型 lilei.__proto__ === SeniorStudent.prototype; //true lilei.__proto__.__proto__ === Student.prototype; //true//驗證繼承關系 lilei instanceof SeniorStudent; //true lilei instanceof Student; //true

如果把修改原型鏈這個動作用一個inherits()函數封裝起來,還可以隱藏F的定義,并簡化代碼如下:

function inherits(Child, Parent) {var F = function () {};F.prototype = Parent.prototype;Child.prototype = new F();Child.prototype.constructor = Child; }

當然,如果不想用中間對象這么麻煩,只需要最核心的一行代碼也可以實現,只是沒有像原生的原型鏈那么完美。

SeniorStudent.prototype = new Student();

? ? ? ??方式2:

? ? ? ? 使用新關鍵字class,從ES6開始正式被引入到JavaScript中。首先用關鍵字class創建Student類。

class Student {constructor(name) {this.name = name;}study() {console.log(this.name + ' is studying ...');} } var tom = new Student('tom'); tom.name //tom tom.study() //tom is studying ...

如果要繼承Student類創建一個新類,可以這樣寫:

class SeniorStudent extends Student {constructor(name) {super(name); //記得用super調用父類的構造方法!}seniorStudy () {console.log(this.name + ' is seniorStudying ...');} }

ES6引入的class關鍵字和原有的JavaScript原型繼承有什么區別呢?實際上它們沒有任何區別,class的作用就是讓JavaScript引擎去實現原來需要我們自己編寫的原型鏈代碼。簡而言之,用class的好處就是極大地簡化了原型鏈代碼,繼承的方式更接近Java類的繼承方式!

?

參考:Douglas Crockford《JavaScript語言精粹》

? ? ? ? ? ?http://www.cnblogs.com/sanshi/archive/2009/07/08/1519036.html

https://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434499763408e24c210985d34edcabbca944b4239e20000

總結

以上是生活随笔為你收集整理的JavaScript之继承和原型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。