淺談Javascript中的對象和繼承
Javascript是一門函數(shù)式編程語言,Javascript當(dāng)中函數(shù)是核心,在Javascript中函數(shù)也是對象,函數(shù)對象在創(chuàng)建的時候會被添加屬性和方法。
在Javascript中函數(shù)對象有兩種調(diào)用方式,一種是new關(guān)鍵字的調(diào)用,另一種是沒有new關(guān)鍵字的調(diào)用,前者會返回一個對象,后者會返回return語句中的內(nèi)容。
function Obj (name) { this.name = name; return name; }
用new關(guān)鍵字來調(diào)用如下:
var obj = new Obj('張三') // 返回 { 'name': '張三' }
不用new關(guān)鍵字調(diào)用如下:
var obj = Obj('張三') // 返回 '張三'
說完了js當(dāng)中的對象和調(diào)用方式,那讓我們來理解下什么是對象。
什么是對象?
對象是類的一個實例(對象可不是女朋友),有狀態(tài)和行為。例如:一個電腦就是一個對象,它的狀態(tài)有:大小、顏色、品牌等,他的行為有:播視頻、聽音樂、聊天等。
而類是對象的抽象,可以理解為類是一個模板,它來描述一類對象的狀態(tài)和行為。軟件對象也有狀態(tài)和行為,軟件對象的狀態(tài)就是屬性,行為就是方法。在軟件開發(fā)中,在方法中可以操作對象的內(nèi)部狀態(tài),對象的相互調(diào)用也是通過方法來完成。
類既然可以理解為一個模板,我們通過一個Person的簡單例子來理解下:
function Person (name, age, sex) { this.name = name; this.age = age; this.sex = sex; run = function () { console.log('Run') } }
在這個類中name,age,sex為這個類的屬性,而run為這個類的方法;Person的職責(zé)是構(gòu)造對象,進(jìn)行對象的初始化。
接下來我們看下在js中如何聲明并調(diào)用對象。
對象的創(chuàng)建(多種方法)
塊級對象
var person = { name: '王小端coder', age: 29 } console.log(person.name); // 王小端coder
構(gòu)造函數(shù) --- 系統(tǒng)自帶
var obj = new Object(); obj.name = '王小端coder' console.log(obj.name); // 王小端coder
系統(tǒng)自帶的對象有:Object、Array、Number、Boolean、Date等
構(gòu)造函數(shù) --- 自定義
function Obj (name) { this.name = name; } var obj = new Obj('王小端coder'); console.log(obj.name); // 王小端coder
對象的增刪改查
增:為對象添加一個屬性
var person = {}; person.name = '王小端coder'; console.log(person.name);
刪:通過delete操作符刪除一個對象的屬性
var person = { name: '王小端coder' }; console.log(person.name); // 王小端coder delete person.name; console.log(person.name); // undefined
改:直接通過賦值來修改一個對象的屬性
var person = { name: '王小端coder' }; console.log(person.name); // 王小端coder person.name = '王小端JS' console.log(person.name); // 王小端JS
查:查詢對象的屬性,有兩種方法
var person = { name: '王小端coder' }; console.log(person['name']); // 第一種方法 console.log(person.name); // 第二種方法
原型的定義
原型是function對象的一個屬性,它定義了構(gòu)造函數(shù)制造出的對象的公共祖先。通過構(gòu)造函數(shù)產(chǎn)生的對象,可以繼承該原型的屬性和方法,原型也是對象。
function Person (name, age) { this.name = name; this.age = age; } Person.prototype = { eat: function (food) { console.log('eat ' + food); }, sleep: function () { console.log('sleeping'); } } var person = new Person ('王小端coder', 29); console.log(person.name); // 王小端coder person.eat('apple') // eat apple
我們定義了一個Person構(gòu)造函數(shù),而屬于Person構(gòu)造對象共有的方法,則定義到了Person原型上。
查看構(gòu)造函數(shù)原型的接口:隱士屬性__proto__(其實我們能夠訪問原型的屬性,或者說繼承原型,靠的就是__proto__屬性連接著構(gòu)造函數(shù)和原型,可以說沒有__proto__屬性的存在,就無法實現(xiàn)原型的繼承)直接通過new操作符創(chuàng)建的對象訪問__proto__屬性即可查看到原型。
原型鏈
原型鏈就是將一個個原型串聯(lián)起來,形成一條原型繼承的鏈子。Child繼承Parent, Parent繼承GrandParent, 而GrandParent沒有自定義原型,所以默認(rèn)為原型鏈的最頂端new Object();
對象的繼承(多種方式)
創(chuàng)建的子類將繼承超類的所有屬性和方法,包括構(gòu)造函數(shù)及方法的實現(xiàn)。記住,所有屬性和方法都是公用的,因此子類可直接訪問這些方法。子類還可添加超類中沒有的新屬性和方法,也可以覆蓋超類的屬性和方法。和其他功能一樣,JavaScript實現(xiàn)繼承的方式不止一種。這是因為JavaScript中的繼承機制并不是明確規(guī)定的,而是通過模仿實現(xiàn)的。這意味著所有的繼承細(xì)節(jié)并非完全由解釋程序處理。作為開發(fā)者,你有權(quán)決定最適用的繼承方式。
我們先定義一個父類
// 定義一個父類 function Person (name) { this.name = name; this.sleep = function () { console.log('朕正在睡覺!'); } } // 在父類原型上面增加一個方法 Person.prototype.eat = function (food) { console.log('朕現(xiàn)在吃的食物是:' + food); }
下面為您介紹幾種具體的繼承方式:
原型鏈繼承
// 定義一個嬰兒來繼承人的父類 function Baby () { } Baby.prototype = new Person(); Baby.prototype.name = '小端'; var baby = new Baby() console.log(baby.name); // 小端 baby.eat('milk'); // 朕現(xiàn)在吃的食物是:milk
優(yōu)點: 簡單、易于實現(xiàn);父類新增的原型方法和屬性子類都能訪問到;
缺點: 無法實現(xiàn)多繼承;來自原型的對象的所有屬性被所有實例共享;如果為子類增加屬性和方法,無法放倒構(gòu)造器中;創(chuàng)建子類實例時無法向父類構(gòu)造函數(shù)傳參;
構(gòu)造繼承
// 定義一個嬰兒來繼承人的父類 function Baby (name) { Person.call(this); this.name = name || 'Coder' } let baby = new Baby(); console.log(baby.name); // Coder baby.sleep(); // 朕正在睡覺! console.log(baby instanceof Person); // false console.log(baby instanceof Baby); // true
優(yōu)點: 可以實現(xiàn)多繼承;創(chuàng)建子類時可以向父類傳遞參數(shù);子類可以共享父類引用的屬性;
缺點: 實例不是父類的實例;只能繼承父類的實例屬性和方法;無法實現(xiàn)函數(shù)復(fù)用,每個子類都有父類實例函數(shù)的副本,影響性能;
實例繼承
function Baby (name) { var instance = new Person(); instance.name = name || 'Coder'; return instance; } let baby = new Baby(); console.log(baby.name); // Coder baby.sleep() // 朕正在睡覺!
優(yōu)點: 不限制調(diào)用方式,返回的對象具有相同的效果;
缺點: 不支持多繼承;實例是父類的實例,不是子類的實例;
拷貝繼承
// 定義一個嬰兒來繼承人的父類 function Baby (name) { var person = new Person(); for (let p in person){ Baby.prototype[p] = person[p]; } Baby.prototype.name = name || 'Coder'; } let baby = new Baby(); console.log(baby.name); // Coder baby.sleep() // 朕正在睡覺!
優(yōu)點: 支持多繼承;
缺點: 效率較低,內(nèi)存占用高;無法獲取父類不可枚舉的方法;
注意:不可枚舉的方法是不能使用for in訪問到的方法
組合繼承
// 定義一個嬰兒來繼承人的父類 function Baby (name) { Person.call(this); this.name = name || 'Coder'; } Baby.prototype = new Person(); Baby.prototype.constructor = Baby; let baby = new Baby(); console.log(baby.name); // Coder baby.eat('milk'); // 朕現(xiàn)在吃的食物是:milk
優(yōu)點: 不存在引用屬性共享問題,可以傳參,函數(shù)可復(fù)用;
缺點: 調(diào)用兩次構(gòu)造函數(shù),生成了兩份實例;
寄生組合繼承
// 定義一個嬰兒來繼承人的父類 function Baby (name) { Person.call(this); this.name = name || 'Coder'; } (function () { let Super = function () {}; Super.prototype = Person.prototype; Baby.prototype = new Super(); })(); let baby = new Baby(); console.log(baby.name); // Coder baby.eat('milk'); // 朕現(xiàn)在吃的食物是:milk
優(yōu)點: 整合了以上幾種繼承的優(yōu)點;
缺點: 實現(xiàn)復(fù)雜;
ES6的class
ES6 提供了更接近傳統(tǒng)語言的寫法,引入了 Class(類)這個概念,作為對象的模板。通過class關(guān)鍵字,可以定義類?;旧?,ES6的class可以看作只是一個語法糖,它的絕大部分功能,ES5 都可以做到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向?qū)ο缶幊痰恼Z法而已。
可以像如下定義:
class Person { constructor (name) { this.name = name; } sleep () { console.log('朕正在睡覺!'); } eat (food) { console.log('朕現(xiàn)在吃的食物是:' + food); } } let person = new Person('小端'); console.log(person.name); // 小端 person.eat('milk'); // 朕現(xiàn)在吃的食物是:milk
ES6 class的繼承
// 定義一個嬰兒來繼承人的父類 class Baby extends Person { constructor(name){ super(name); } } let baby = new Baby('小端'); console.log(baby.name); // 小端 baby.eat('milk'); // 朕現(xiàn)在吃的食物是:milk
我們可以看到Class可以通過extends關(guān)鍵字實現(xiàn)繼承,這比ES5的通過修改原型鏈實現(xiàn)繼承,要清晰和方便很多。
我之后會單獨用一章來詳細(xì)講ES6中的Class和繼承。
以上所述是小編給大家介紹的Javascript中的對象和繼承詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
- Javascript面向?qū)ο缶幊蹋ㄈ?非構(gòu)造函數(shù)的繼承
- Javascript面向?qū)ο缶幊蹋ǘ?構(gòu)造函數(shù)的繼承
- javascript的函數(shù)、創(chuàng)建對象、封裝、屬性和方法、繼承
- javascript 面向?qū)ο笕吕砭氈屠^承
- javascript 面向?qū)ο罄^承
- javascript 面向?qū)ο?實現(xiàn)namespace,class,繼承,重載
- js對象繼承之原型鏈繼承實例
- javascript 面向?qū)ο蠓庋b與繼承
- JavaScript面向?qū)ο笾甈rototypes和繼承
- 徹底理解js面向?qū)ο笾^承
相關(guān)文章
實現(xiàn)在?Chrome?中執(zhí)行?JavaScript?代碼
這篇文章主要介紹了實現(xiàn)在?Chrome?中執(zhí)行?JavaScript?代碼,下面來介紹如何在?Chrome?中打開開發(fā)者工具,以及如何在開發(fā)者工具中運行調(diào)試?JavaScript?代碼,具有一的的參考價值,需要的朋友可以參考一下2022-03-03關(guān)于JS中的apply,call,bind的深入解析
下面小編就為大家?guī)硪黄P(guān)于JS中的apply,call,bind的深入解析。小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-04-04如何基于小程序?qū)崿F(xiàn)發(fā)送語音消息及轉(zhuǎn)文字功能
最近為小程序增加語音識別轉(zhuǎn)文字的功能,坑路不斷,特此記錄,下面這篇文章主要給大家介紹了關(guān)于如何基于小程序?qū)崿F(xiàn)發(fā)送語音消息及轉(zhuǎn)文字功能的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11