前端 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;
前端 Array.sort() 源码学习的更多相关文章
- [算法1-排序](.NET源码学习)& LINQ & Lambda
[算法1-排序](.NET源码学习)& LINQ & Lambda 说起排序算法,在日常实际开发中我们基本不在意这些事情,有API不用不是没事找事嘛.但必要的基础还是需要了解掌握. 排 ...
- Underscore.js 源码学习笔记(下)
上接 Underscore.js 源码学习笔记(上) === 756 行开始 函数部分. var executeBound = function(sourceFunc, boundFunc, cont ...
- 【Vue源码学习】响应式原理探秘
最近准备开启Vue的源码学习,并且每一个Vue的重要知识点都会记录下来.我们知道Vue的核心理念是数据驱动视图,所有操作都只需要在数据层做处理,不必关心视图层的操作.这里先来学习Vue的响应式原理,V ...
- 【 js 基础 】【 源码学习 】源码设计 (持续更新)
学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析第二部分:undersc ...
- Underscore.js 源码学习笔记(上)
版本 Underscore.js 1.9.1 一共 1693 行.注释我就删了,太长了… 整体是一个 (function() {...}()); 这样的东西,我们应该知道这是一个 IIFE(立即执行 ...
- 【 js 基础 】【 源码学习 】源码设计 (更新了backbone分析)
学习源码,除了学习对一些方法的更加聪明的代码实现,同时也要学习源码的设计,把握整体的架构.(推荐对源码有一定熟悉了之后,再看这篇文章) 目录结构:第一部分:zepto 设计分析 第二部分:unders ...
- SpringBoot源码学习系列之SpringMVC自动配置
目录 1.ContentNegotiatingViewResolver 2.静态资源 3.自动注册 Converter, GenericConverter, and Formatter beans. ...
- 源码学习VUE之Observe
在文章 源码学习VUE之响应式原理我们大概描述了响应式的实现流程,主要写了observe,dep和wather的简易实现,以及推导思路.但相应代码逻辑并不完善,今天我们再来填之前的一些坑. Obser ...
- 【Vue源码学习】依赖收集
前面我们学习了vue的响应式原理,我们知道了vue2底层是通过Object.defineProperty来实现数据响应式的,但是单有这个还不够,我们在data中定义的数据可能没有用于模版渲染,修改这些 ...
- [数据结构1.2-线性表] 动态数组ArrayList(.NET源码学习)
[数据结构1.2-线性表] 动态数组ArrayList(.NET源码学习) 在C#中,存在常见的九种集合类型:动态数组ArrayList.列表List.排序列表SortedList.哈希表HashTa ...
随机推荐
- C++ 多级继承与多重继承:代码组织与灵活性的平衡
C++ 多级继承 多级继承是一种面向对象编程(OOP)特性,允许一个类从多个基类继承属性和方法.它使代码更易于组织和维护,并促进代码重用. 多级继承的语法 在 C++ 中,使用 : 符号来指定继承关系 ...
- 【爬虫GUI】YouTube评论采集软件,突破反爬,可无限爬取!
目录 一.背景介绍 1.1 软件说明 1.2 效果演示 二.科普知识 2.1 关于视频id 2.2 关于评论时间 三.爬虫代码 3.1 界面模块 3.2 爬虫模块 3.3 日志模块 四.获取源码及软件 ...
- Ruby on Rails Active Record数据库常用操作
目录 创建 批量插入 判断是否存在 Ruby on Rails 日期查询方法 文档地址: https://freed.gitee.io/rails-guides/active_record_query ...
- golang sort —— 排序算法
该包实现了四种基本排序算法:插入排序.归并排序.堆排序和快速排序. 但是这四种排序方法是不公开的,它们只被用于sort包内部使用.所以在对数据集合排序时不必考虑应当选择哪一种排序方法,只要实现了sor ...
- Windows server 2012 R2开机进入cmd,关闭后黑屏
出现此问题,一般只有两种情况,操作系统装置前和操作系统装置后出现: 第一种: 装置操作系统的时候没有选择"Windows Server 2012 R2 Strandard( 带有GUI的服务 ...
- Splashtop 教育行业用户增加700%
由于新冠肺炎大流行继续限制对大学.学院和K-12学校的计算机实验室的物理访问,Splashtop的销售数据表明,越来越多的学校开始使用远程访问软件作为使用计算机实验室资源的替代方法. 在6月到8月 ...
- 第二届黄河流域网络安全技能挑战赛Web_wirteup
前言 好久没写过比赛的wp了,黄河流域的web出的不错,挺有意思了,花了点时间,也是成功的ak了 myfavorPython 注册登录,一个base64输入框,猜测pickle反序列化,简单测试下,返 ...
- echarts饼图详细+仪表盘
echarts(数据可视化图表) 标签属性 标签属性:label模板字符串显示name和value 未使用之前,系列的name默认就显示在外面了,显示的是name 系列里面有系列的类型,数据,la ...
- Python:用Pandas输出格式化HTML并高亮
输出格式化的HTML 我们已知一个DataFrame记录了模型Model1.Model2在3个Epoch优化中的精度变化情况: frame = pd.DataFrame({"Model1&q ...
- Android 13 - Media框架(26)- OMXNodeInstance(三)
关注公众号免费阅读全文,进入音视频开发技术分享群! 上一节我们了解了OMXNodeInstance中的端口定义,这一节我们一起来学习ACodec.OMXNode.OMX 组件使用的 buffer 到底 ...