前端 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.mzph.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加…