前端 Array.sort() 源碼學習

源碼地址

V8源碼Array
710行開始為sort()相關

Array.sort()方法是那種排序呢?

去看源碼主要是源于這個問題

// In-place QuickSort algorithm.
// For short (length <= 22) arrays, insertion sort is used for efficiency.

源碼中的第一句話就回答了我的問題

// 通常使用快速排序算法
// 如果數組長度小于23,則插入排序效率更好

既然都打開了,索性就看看源碼叭,看看sort到底做了些啥
我把一整坨源碼碼分成一塊一塊來看,讓自己比較清晰的知道sort到底干了些啥,下面是閱讀代碼時,自己的思路梳理

第一塊代碼

if (!IS_CALLABLE(comparefn)) {comparefn = function (x, y) {if (x === y) return 0;if (%_IsSmi(x) && %_IsSmi(y)) {return %SmiLexicographicCompare(x, y);}x = TO_STRING(x);y = TO_STRING(y);if (x == y) return 0;else return x < y ? -1 : 1;};
}

第一塊內容判斷,如果傳進來的參數不可回調,則給一個默認的回調函數
這個回調函數,判斷倆值是不是Smi

// Smi:小整數(Small integers)V8引擎中的元素類型之一
`https://medium.com/@justjavac/v8-internals-how-small-is-a-small-integer-ba5e17a3ae5f`
// PS: markdown語法有問題,這里直接貼出 url

如果是則進行小整數字典序比較
什么是字典序

否則將兩個值轉換成字符串進行字符串比較大小
字符串如何比較大小

第二塊代碼

var InsertionSort = function InsertionSort(a, from, to) {...
};
var QuickSort = function QuickSort(a, from, to) {if (to - from <= 10) {InsertionSort(a, from, to);return;}...
};

第二塊就是正常的快速排序和插入排序
這里采取的是數量小于10的數組使用 InsertionSort(插入),比10大的數組則使用 QuickSort(快速)。

第三塊代碼

if (!is_array) {// For compatibility with JSC, we also sort elements inherited from// the prototype chain on non-Array objects.// We do this by copying them to this object and sorting only// own elements. This is not very efficient, but sorting with// inherited elements happens very, very rarely, if at all.// The specification allows "implementation dependent" behavior// if an element on the prototype chain has an element that// might interact with sorting.max_prototype_element = CopyFromPrototype(array, length);
}

這塊代碼里面的注釋,講的還是比較詳細的,百度翻譯也非常nice

// 為了與JSC兼容,我們還在非數組對象上對從原型鏈繼承的元素進行排序。
// 我們通過將它們復制到這個對象并只對自己的元素排序來實現這一點。
// 這不是很有效,但是使用繼承的元素進行排序的情況很少發生,如果有的話。
// 如果原型鏈上的元素具有可能與排序交互的元素,則規范允許“依賴于實現”的行為。

第四塊代碼

// Copy elements in the range 0..length from obj's prototype chain
// to obj itself, if obj has holes. Return one more than the maximal index
// of a prototype property.
var CopyFromPrototype = function CopyFromPrototype(obj, length) {var max = 0;for (var proto = %object_get_prototype_of(obj); proto;proto = %object_get_prototype_of(proto)) {var indices = IS_PROXY(proto) ? length : %GetArrayKeys(proto, length);if (IS_NUMBER(indices)) {// It's an interval.var proto_length = indices;for (var i = 0; i < proto_length; i++) {if (!HAS_OWN_PROPERTY(obj, i) && HAS_OWN_PROPERTY(proto, i)) {obj[i] = proto[i];if (i >= max) { max = i + 1; }}}} else {for (var i = 0; i < indices.length; i++) {var index = indices[i];if (!HAS_OWN_PROPERTY(obj, index) && HAS_OWN_PROPERTY(proto, index)) {obj[index] = proto[index];if (index >= max) { max = index + 1; }}}}}return max;
};

這塊代碼是對于非數組的一個處理
注釋里面說到

// 如果obj有holes(能猜出大概意思,不咋好翻譯這個hole)
// 就把obj原型鏈上0-length所有元素賦值給obj本身
// 返回一個max,max是比原型屬性索引最大值+1

返回的max會在下面用到

第五塊代碼

if (!is_array && (num_non_undefined + 1 < max_prototype_element)) {// For compatibility with JSC, we shadow any elements in the prototype// chain that has become exposed by sort moving a hole to its position.ShadowPrototypeElements(array, num_non_undefined, max_prototype_element);
}

注釋翻譯:

// 為了與JSC兼容
// 我們對原型鏈中通過sort將一個hole移動到其位置而暴露的所有元素
// 進行shadow處理。

可能因為英語語法水平不夠,單看注釋還有點不明白
大致意思是,把“掀開的東西,再蓋上”
直接看下面一塊代碼,看看這個shadow操作到底干了啥叭

第六塊代碼

// Set a value of "undefined" on all indices in the range from..to
// where a prototype of obj has an element. I.e., shadow all prototype
// elements in that range.
var ShadowPrototypeElements = function(obj, from, to) {for (var proto = %object_get_prototype_of(obj); proto;proto = %object_get_prototype_of(proto)) {var indices = IS_PROXY(proto) ? to : %GetArrayKeys(proto, to);if (IS_NUMBER(indices)) {// It's an interval.var proto_length = indices;for (var i = from; i < proto_length; i++) {if (HAS_OWN_PROPERTY(proto, i)) {obj[i] = UNDEFINED;}}} else {for (var i = 0; i < indices.length; i++) {var index = indices[i];if (from <= index && HAS_OWN_PROPERTY(proto, index)) {obj[index] = UNDEFINED;}}}}
};

這塊代碼就是shadow操作,注釋翻譯如下:

// 在范圍從..到obj原型包含元素的所有索引上設置一個“undefined”值。
// 換句話說
// 在該范圍內對所有原型元素進行shadow處理。

其中:
I.e.是拉丁文id est 的縮寫,它的意思就是“那就是說,換句話說”
英文不夠你用了是不你還要寫拉丁文?!

果然大致的意思猜的沒錯
在剛剛把對象的原型屬性的復制,現在要設置undefined來shadow他了

第七塊代碼

if (num_non_undefined == -1) {// There were indexed accessors in the array.// Move array holes and undefineds to the end using a Javascript function// that is safe in the presence of accessors.num_non_undefined = SafeRemoveArrayHoles(array);
}

意思是 數組中有索引訪問器。使用JS函數將數組hole和未定義項移到末尾,該函數在訪問器存在時是安全的。
下面是安全移出數組hole方法

var SafeRemoveArrayHoles = function SafeRemoveArrayHoles(obj) {// Copy defined elements from the end to fill in all holes and undefineds// in the beginning of the array.  Write undefineds and holes at the end// after loop is finished.var first_undefined = 0;var last_defined = length - 1;var num_holes = 0;while (first_undefined < last_defined) {// Find first undefined element.while (first_undefined < last_defined &&!IS_UNDEFINED(obj[first_undefined])) {first_undefined++;}// Maintain the invariant num_holes = the number of holes in the original// array with indices <= first_undefined or > last_defined.if (!HAS_OWN_PROPERTY(obj, first_undefined)) {num_holes++;}// Find last defined element.while (first_undefined < last_defined &&IS_UNDEFINED(obj[last_defined])) {if (!HAS_OWN_PROPERTY(obj, last_defined)) {num_holes++;}last_defined--;}if (first_undefined < last_defined) {// Fill in hole or undefined.obj[first_undefined] = obj[last_defined];obj[last_defined] = UNDEFINED;}}// If there were any undefineds in the entire array, first_undefined// points to one past the last defined element.  Make this true if// there were no undefineds, as well, so that first_undefined == number// of defined elements.if (!IS_UNDEFINED(obj[first_undefined])) first_undefined++;// Fill in the undefineds and the holes.  There may be a hole where// an undefined should be and vice versa.var i;for (i = first_undefined; i < length - num_holes; i++) {obj[i] = UNDEFINED;}for (i = length - num_holes; i < length; i++) {// For compatability with Webkit, do not expose elements in the prototype.if (i in %object_get_prototype_of(obj)) {obj[i] = UNDEFINED;} else {delete obj[i];}}// Return the number of defined elements.return first_undefined;
};

還會判斷數組長度

if (length < 2) return array;

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/36576.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/36576.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/36576.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Potato(土豆)一款輕量級的開源文本標注工具(二)

示例項目&#xff08;模版&#xff09; Potato 旨在提高數據標注的可復制性&#xff0c;并降低研究人員設置新標注任務的成本。因此&#xff0c;Potato 提供了一系列預定義的示例項目&#xff0c;并歡迎公眾向項目中心貢獻。如果您使用 Potato 進行了自己的標注工作&#xff0…

海思平臺使用ITTP_Stream調試sensor

目錄 相關資料1.ISP相關資料2.MIPI RX相關資料3.sensor資料4.MIPI標準 準備工作1.準備sensor驅動2.準備sample vio3.準備上位機和下位機程序 運行1.只運行HiPQTool1.1.板端運行1.2.PC端運行HiPQTool 2.使用ITTP_Stream2.1.板端運行2.2.打開上位機軟件 相關資料 1.ISP相關資料 …

uniapp開發手機APP、H5網頁、微信小程序、長列表插件

ml-list 插件地址&#xff1a;https://ext.dcloud.net.cn/plugin?id18928 ml-list介紹 1、ml-list 列表組件&#xff0c;包含基本列表樣式、可擴展插槽機制、長列表性能優化、多端兼容。 2、ml-list 低代碼列表&#xff0c;幫助使用者快速構建列表&#xff0c;簡單配置&…

秋招突擊——6/26~6/27——復習{二維背包問題——寵物小精靈之收服}——新作{串聯所有單詞的字串}

文章目錄 引言復習二維背包問題——寵物小精靈之收服個人實現重大問題 滾動數組優化實現 新作串聯所有單詞的字串個人實現參考實現 總結 引言 今天應該是舟車勞頓的一天&#xff0c;頭一次在機場刷題&#xff0c;不學習新的東西了&#xff0c;就復習一些之前學習的算法了。 復…

百度Apollo的PublicRoadPlanner一些移植Ros2-foxy的思路(持續更新)

如今的PublicRoadPlanner就是之前耳熟能詳的EM planner 計劃 —— ROS2與CARLA聯合仿真 結構化場景: 規劃算法:EM-planner 控制算法:MPC和PID 非結構化場景: 規劃算法采用Hybrid A* (1)小車模型搭建(計劃參考Github上Hybrid上的黑車,比較炫酷) (2)車輛里程計: 位…

深入比較:Batch文件與Shell腳本的異同

在操作系統中&#xff0c;自動化腳本是一種常見的工具&#xff0c;用于執行一系列自動化命令或程序。Windows和類Unix系統都提供了各自的腳本解決方案&#xff1a;Batch文件&#xff08;在Windows中&#xff09;和Shell腳本&#xff08;在類Unix系統中&#xff09;。本文將詳細…

有哪些方法可以恢復ios15不小心刪除的照片?

ios15怎么恢復刪除的照片&#xff1f;在手機相冊里意外刪除了重要的照片&#xff1f;別擔心&#xff01;本文將為你介紹如何在iOS 15系統中恢復已刪除的照片。無需專業知識&#xff0c;只需要按照以下步驟操作&#xff0c;你就能輕松找回寶貴的回憶。 一、從iCloud云端恢復刪除…

SRC公益上分的小技巧一

前言 之前發布的文章&#xff0c;例如SRC中的一些信息收集姿勢- Track 知識社區 - 掌控安全在線教育 - Powered by 掌控者 里面就有提到若依系統&#xff0c;默認賬號密碼非常簡單 是 admin / admin123 但是&#xff0c;往往我們去挖掘的時候很容易出現 這說明了若依系統的門…

Viewer.js 圖片預覽插件使用

參考&#xff1a;Viewer.js 圖片預覽插件使用 demo鏈接&#xff1a;viewerjs_demo

【Linux:文件描述符】

文件描述符&#xff1a; 文件描述符的分配原則&#xff1a;最小未分配原則 每一個進程中有一個task_struct結構體&#xff08;PCB)&#xff0c;而task_struct中含有struct file_sturct*file的指針&#xff0c;該指針指向了一個struct files_struct的結構體該結構體中含有一個f…

PHP框架詳解- symfony框架

Symfony框架是一個開源的PHP框架&#xff0c;由SensioLabs公司開發并維護&#xff0c;最早發布于2005年。它旨在為Web應用程序的開發提供一個高效且結構化的環境。Symfony框架的設計理念是減少Web應用程序的創建和維護時間&#xff0c;并避免重復性任務。 Symfony框架采用MVC&…

PG最大連接數

在 PostgreSQL 數據庫中&#xff0c;您可以使用 SQL 查詢來獲取最大連接數、當前連接數以及每個數據庫的連接數。以下是一些常用的查詢&#xff1a; 查看最大連接數&#xff1a; PostgreSQL 的最大連接數由配置參數 max_connections 決定。您可以在 postgresql.conf 文件中設置…

使用IMAP服務獲取163郵箱的未讀郵件

使用IMAP服務獲取163郵箱的未讀郵件 整體的邏輯思路如下&#xff1a; 開啟163郵箱的IMAP服務&#xff0c;拿到授權碼用于登錄IMAP服務登錄IMAP服務&#xff0c;獲取郵箱的未讀郵件列表遍歷未讀郵件列表&#xff0c;獲取郵件內容 # 導入必要的庫 import os import imaplib im…

三大工作流引擎技術Activiti、Flowable、Camunda選型指南

文章目錄 前言1 流程引擎發展歷程2 流程引擎主要概念BPM (Business Process Management)BPMN (Business Process Model and Notation)CMMN (Case Management Model and Notation)DMN (Decision Model and Notation)事件&#xff08;Event&#xff09;順序流&#xff08;Sequenc…

從靜電到浪涌,全面防護:雷卯多電壓等級電源保護設計方案匯總

在當今數字化、電氣化日益加速的時代&#xff0c;電子設備和電力系統面臨著前所未有的挑戰&#xff0c;其中靜電放電(ESD)、浪涌以及雷擊等瞬態事件成為了威脅設備穩定性和壽命的關鍵因素。從精密的消費電子產品到工業級控制系統&#xff0c;從智能家居到新能源汽車&#xff0c…

區塊鏈技術的核心要素:共識機制、加密技術與分布式賬本

區塊鏈聽起來像個非常高大上的技術&#xff0c;其實它的核心原理并不難理解。今天我們要聊的就是區塊鏈的三個核心要素&#xff1a;共識機制、加密技術和分布式賬本。想象一下區塊鏈是一個巨大的數字筆記本&#xff0c;我們要弄清楚大家如何共同寫這個筆記本&#xff0c;又如何…

用一個實例看如何分享大量照片 續篇二,關于Exif (Exchangeable Image File) - 可交換圖像文件

續篇二&#xff1a;說說關于照片隱含的 Exif (Exchangeable Image File) 可交換圖像文件 數碼照片的Exif 參數有很多&#xff0c;重要的Exif信息&#xff1a;拍攝日期、時間、拍攝器材、GPS信息。 當然這主要對自己的檔案有意義&#xff0c;如果放到網上還是建議抹去這些信息。…

Bad owner or permissions on C:\\Users\\username/.ssh/config > 過程試圖寫入的管道不存在。

使用windows連接遠程服務器出現Bad owner or permissions 錯誤 問題&#xff1a; 需要修復文件權限 SSH 配置文件應具有受限權限以防止未經授權的訪問 確保只有用戶對該.ssh/config文件具有讀取權限 解決方案&#xff1a; 在windows下打開命令行&#xff0c;通過以下命令打開文…

C++編程(四)this指針 常函數 常對象 靜態成員

文章目錄 一、this指針&#xff08;一&#xff09;概念&#xff08;二&#xff09;顯式使用this指針的場景1. 當形參和成員變量名一致時2. 返回對象自身的時候必須要使用this指針3. 在類中銷毀一個對象 二、常函數和常對象&#xff08;一&#xff09;常函數1. 概念2. 語法格式 …

python OpenCV 庫中的 cv2.Canny() 函數來對圖像進行邊緣檢測,并顯示檢測到的邊緣特征

import cv2# 加載圖像 image cv2.imread(4.png)# 使用 Canny 邊緣檢測算法提取邊緣特征 edges cv2.Canny(image, 100, 200)# 顯示邊緣特征 cv2.imshow(Edges, edges) cv2.waitKey(0) cv2.destroyAllWindows() 代碼解析&#xff1a; 導入 OpenCV 庫&#xff1a; import cv2加…