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