详解链表在前端的应用,顺便再弄懂原型和原型链!
鏈表在前端中的應(yīng)用
- 一、鏈表VS數(shù)組
- 二、JS中的鏈表
- 三、前端與鏈表:JS中的原型鏈
- 1、原型是什么?
- 2、原型鏈?zhǔn)鞘裁?#xff1f;
- 3、原型鏈長啥樣?
- (1)arr → Array.prototype → Object.prototype → null
- (2)obj → Object.prototype → null
- (3)func → Function.prototype → Object.prototype → null
- (4)class中的原型
- (5)new Object() 和 Object.create() 區(qū)別
- 4、原型鏈知識點(diǎn)
- 5、常見面試題
- (1)instanceof原理
- (2)看代碼,得出輸出結(jié)果。
- 四、寫在最后
鏈表 在前端中的應(yīng)用常用于原型和原型鏈當(dāng)中。在接下來的這篇文章中,將講解關(guān)于 鏈表 在前端中的應(yīng)用。
一、鏈表VS數(shù)組
- 數(shù)組:增刪非首尾元素時往往需要移動元素;
- 鏈表:增刪非首尾元素,不需要移動元素,只需要更改 next 的指向即可。
二、JS中的鏈表
- Javascript中沒有鏈表;
- 可以用Object模擬鏈表。
三、前端與鏈表:JS中的原型鏈
1、原型是什么?
- 在 Javascript 中,每個對象都會在其內(nèi)部初始化一個屬性,這個屬性就是原型對象(簡稱原型)。
2、原型鏈?zhǔn)鞘裁?#xff1f;
- 當(dāng)我們訪問一個對象的屬性時,如果這個對象內(nèi)部不存在這個屬性,那么它就會去 prototype 里找這個屬性,這個 prototype 又會有自己的 prototype ,于是就這樣一直找下去,這樣逐級查找形似一個鏈條,且通過 [[prototype]] 屬性連接,這個連接的過程被稱為原型鏈。
- 原型鏈的本質(zhì)是鏈表,且原型鏈上的節(jié)點(diǎn)是各種原型對象,如: Function.prototype 、 Object.prototype ……。
- 原型鏈通過 __proto__ 屬性連接各種原型對象。
3、原型鏈長啥樣?
(1)arr → Array.prototype → Object.prototype → null
- arr.__ proto __ = Array.prototype;
- Array.__ proto __= Object.prototype;
- Object.__ proto __= null。
先用代碼來演示這段關(guān)系:
let arr = []; console.log(arr.__proto__ === Array.prototype); // true console.log(arr.__proto__.__proto__ === Object.prototype); // true console.log(arr.__proto__.__proto__.__proto__); //null解釋說明:
假設(shè)我們定義了一個對象,名字叫 arr ,那么 arr.__proto__ 表示的是arr這個對象的原型,在這個例子中 let arr = [] 間接調(diào)用了 new Array ,所以我們通過 Array.prototype 來表示 Array 這個構(gòu)造函數(shù)的原型對象,通過對 arr.__proto__ 和 Array.prototype 進(jìn)行比較,發(fā)現(xiàn)兩者相等,所以說, arr 的原型屬性就是構(gòu)造函數(shù) Array 的原型對象。
與上述類似的,我們發(fā)現(xiàn) arr.__proto__ 和 Array.prototype 相等,那么繼續(xù)往源頭查找下去, Array 又有它自己的原型屬性,那么這個時候 Array 的原型屬性 arr.__proto__.__proto__ 又會等于什么呢?
其實(shí),在 js 當(dāng)中, Object 是所有對象的父對象,也就是說絕大多數(shù)的對象都有一個共同的原型 Object.prototype 。所以,這個時候 Array 的原型屬性 arr.__proto__.__proto__ 就等于 Object.prototype ,到此為止,找到最原始的父對象 Object 的原型之后,基本就快結(jié)束了。我們最后再檢驗(yàn) Object 的原型屬性 arr.__proto__.__proto__.__proto__ ,發(fā)現(xiàn)是 null 空值,也就意味著原型鏈已經(jīng)走到了最源頭的位置。
總結(jié):
- Object 是所有對象的父對象。
- 從上面例子中可以看到,所有原型對象都會先指向自己的 __proto__ 屬性,之后再指向自己的原型,最后指向父對象 Object 的原型。
下面再給出兩個例子,大家可以依據(jù)(1)的方法進(jìn)行檢驗(yàn)。
(2)obj → Object.prototype → null
- obj.__ proto __ = Object.prototype;
- Object.__ proto __= null。
用代碼來演示這段關(guān)系:
let obj = {}; console.log(obj.__proto__ === Object.prototype); // true console.log(obj.__proto__.__proto__); //null(3)func → Function.prototype → Object.prototype → null
- func.__ proto __ = Function.prototype;
- Function.__ proto __= Object.prototype;
- Object.__ proto __= null。
用代碼來演示這段關(guān)系:
let func = function(){}; console.log(func.__proto__ === Function.prototype); // true console.log(func.__proto__.__proto__ === Object.prototype); // true console.log(func.__proto__.__proto__.__proto__); //null(4)class中的原型
1)先來看第一段代碼。
//父類 class People{constructor(){this.name = name;}eat(){console.log(`${this.name} eat something`);} }//子類 class Student extends People{constructor(name, number){super(name);this.number = number;}sayHi(){console.log(`姓名:${this.name},學(xué)號:${this.number}`);} }console.log(typeof Student); //function console.log(typeof People); //functionlet xialuo = new Student('夏洛', 10010); console.log(xialuo.__proto__); console.log(Student.prototype); console.log(xialuo.__proto__ === Student.prototype); //true從上面代碼中可以看到, typeof Student 和 typeof People 的值是 function ,所以 class 實(shí)際上是函數(shù),也就是語法糖。
再看下面三個 console.log 打印的值,我們來梳理一個原型間的關(guān)系。首先 Student 是一個 class ,那么每個 class 都有它的顯式原型 prototype ,而 xialuo 是一個實(shí)例,每個實(shí)例都有它的隱式原型 __proto__ 。它們兩者之間的關(guān)系就是,實(shí)例 xialuo 的 __proto__ 指向?qū)?yīng)的 class (即 Student )的 prototype 。
因此,對于class中的原型,可以得出以下結(jié)論:
- 每個 class 都有顯式原型 prototype ;
- 每個實(shí)例都有隱式原型 __proto__ ;
- 實(shí)例的 __proto__ 指向?qū)?yīng) class 的 prototype 。
2)再來看第二段代碼。
//父類 class People{constructor(){this.name = name;}eat(){console.log(`${this.name} eat something`);} }//子類 class Student extends People{constructor(name, number){super(name);this.number = number;}sayHi(){console.log(`姓名:${this.name},學(xué)號:${this.number}`);} }let xialuo = new Student('夏洛', 10010); console.log(xialuo.name); //夏洛 console.log(xialuo.number); //10010 console.log(Student.sayHi()); //姓名:夏洛,學(xué)號:10010從上面代碼中可以得出, Student 類本身有 number 這個屬性,所以它會直接讀取自身 number 的值。同時,它是沒有 name 這個屬性的,但是由于它繼承自父類 People ,所以當(dāng)它找不到 name 則個屬性時,它會自動的往 __proto__ 中查找,于是就往它的父類 People 進(jìn)行查找。
所以,從上面的演示中可以得出基于原型的執(zhí)行規(guī)則:
- 先獲取屬性(比如 xialuo.name 和 xiaoluo.number ) 或者獲取執(zhí)行方法 (比如 xialuo.sayhi() );
- 獲取后,先在自身屬性和方法上尋找;
- 如果找不到則自動去 __proto__ 中查找。
(5)new Object() 和 Object.create() 區(qū)別
- {} 等同于 new Object() ,原型為 Object.prototype ;
- Object.create(null) 沒有原型;
- Object.create({...}) 可指定原型。
4、原型鏈知識點(diǎn)
(1)如果 A 沿著原型鏈能找到 B.prototype ,那么 A instanceof B 為 true 。
舉例1:
let obj = {}; console.log(obj instanceof Object); //true對于 obj instanceof Object 進(jìn)行左右運(yùn)算, obj instanceof Object 的意思是查詢 obj 的原型鏈上是否有 Object 的原型對象,即 obj 是否是 Object 的實(shí)例。
舉例2:
let func = function(){}; console.log(func instanceof Function); //true console.log(func instanceof Object); //true對于 func 來說, func 既是 Function 的實(shí)例,也是 Object 的實(shí)例。
(2)如果 A 對象上沒有找到 x 屬性,那么會沿著原型鏈找 x 屬性。
舉例:
const obj = {};Object.prototype.x = 'x';console.log(obj.x); //x從上述代碼中可以看到,obj 在自己的區(qū)域內(nèi)沒有找到x的值,則會繼續(xù)往它的原型鏈找,最終找到 Object.prototype.x ,所以 obj.x = x 。
接下來我們用兩道常見的面試題來回顧這兩個知識點(diǎn)。
5、常見面試題
(1)instanceof原理
知識點(diǎn):如果 A 沿著原型鏈能找到 B.prototype ,那么 A instanceof B 為 true 。
解法:遍歷 A 的原型鏈,如果找到 B.prototype ,返回 true ,否則返回 false 。
代碼演示:
// 判斷A是否為B的實(shí)例 const instanceOf = (A, B) => {// 定義一個指針P指向Alet p = A;// 當(dāng)P存在時則繼續(xù)執(zhí)行while(p){// 判斷P值是否等于B的prototype對象,是則說明A是B的實(shí)例if(p === B.prototype){return true;}// 不斷遍歷A的原型鏈,直到找到B的原型為止p = p.__proto__;}return false; }(2)看代碼,得出輸出結(jié)果。
看下面一段代碼,請給出4個 console.log 打印的值。
let foo = {}; let F = function(){}; Object.prototype.a = 'value a'; Function.prototype.b = 'value b';console.log(foo.a); //value a console.log(foo.b); //undefindconsole.log(F.a); //value a console.log(F.b); //value b知識點(diǎn):如果在 A 對象上沒有找到 x 屬性,那么會沿著原型鏈找 x 屬性。
解法:明確 foo 和 F 變量的原型鏈,沿著原型鏈找 A 屬性和 B 屬性。
解析:從上面一段代碼中可以看到, foo 是一個對象,那么它的 __proto__ 屬性指向 Object.prototype ,所以此時 foo.a 會往它的原型鏈上面找具體的值,也就是 Object.prototype.a 的值。同理, foo.b 會往它的原型鏈找值,但是找不到 Object.prototype.b 的值,所以最終返回 undefined 。 F.a 和 F.b 也是同樣的道理,大家可以進(jìn)行一一驗(yàn)證。
四、寫在最后
原型和原型鏈在前端中是再基礎(chǔ)不過的知識了!我們平常所寫的每一個對象中,基本上都有它的原型和原型鏈。因此,對于前端來說,如果原型和原型鏈的關(guān)系都不明白的話,不知不覺中很容易寫出各種各樣的bug,這對于后續(xù)維護(hù)和程序來說都是一個巨大的災(zāi)難。所以,了解原型和原型鏈,對于前端來說是一項必備的技能。
鏈表在前端中的應(yīng)用就講到這里啦!如果有不理解或者有誤的地方也歡迎私聊我或加我微信指正~
- 公眾號:星期一研究室
- 微信:MondayLaboratory
創(chuàng)作不易,如果這篇文章對你有用,記得點(diǎn)個 Star 哦~
總結(jié)
以上是生活随笔為你收集整理的详解链表在前端的应用,顺便再弄懂原型和原型链!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上肢力量训练的方法
- 下一篇: 2017年html5行业报告,云适配发布