前端 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;

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/750071.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT的keypressevent只响应功能键不响应字母键或者组合键

参考https://bbs.csdn.net/topics/392378467 这位兄弟准确说明了解决方案。 在pyqt中&#xff0c;则在__init__中添加 self.grabKeyboard()

专题页面设计指南:从构思到实现

如何设计专题页&#xff1f;你有什么想法&#xff1f;专题页的设计主要以发扬产品优势为核心。一个好的专题页可以从不同的角度向用户介绍产品&#xff0c;扩大产品的相关优势&#xff0c;表达产品的优势&#xff0c;让用户在短时间内了解产品。因此&#xff0c;在设计详细信息…

数据采集Selenium中的弹窗处理

在爬虫技术中&#xff0c;弹窗处理是一个常见但具有挑战性的问题。Selenium作为一个强大的网页自动化工具&#xff0c;可以帮助我们有效地处理网页中的各种弹窗。本文将概述如何使用Selenium处理弹窗&#xff0c;并提供实现代码&#xff0c;代码中将使用代理IP技术。 概述 弹…

基于Java微信小程序火锅店点餐系统设计和实现(源码+LW+调试文档+讲解等)

&#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者&#xff0c;博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f31f;文末获取源码数据库&#x1f31f;感兴趣的可以先收藏起来&#xff0c;还…

突然!某大客户核心凌晨突然崩溃....

这几天实在太忙&#xff0c;刚弄完文档。业务线的同事就找到我&#xff0c;说一个银行客户的核心系统昨晚出了故障&#xff0c;还没找到原因&#xff0c;希望能帮忙分析下。 从提供的信息来看是业务跑任务报错&#xff0c;遇到了Oracle-00600和ora-07445 错误。 Doing block re…

Zynq7000系列FPGA中的DMA控制器——PL外设请求接口

图9-4中展示了PL外设请求接口主要由两部分组成&#xff1a;PL外设请求总线和DMAC确认总线。这两部分分别使用特定的前缀进行标识&#xff0c;具体如下&#xff1a; PL外设请求总线&#xff08;PL Peripheral Request Bus&#xff09;&#xff1a; 前缀&#xff1a;DR功能&…

YOLO模型评价指标

在模型训练完成之后&#xff0c;需要对模型的优劣作出评估&#xff0c;YOLO系列算法的评价指标包括&#xff1a; 1. 准确率&#xff08;Precision&#xff09;&#xff1a;指模型预测为正样本中实际为正样本的比例。 &#x1d447;&#x1d443;、&#x1d439;&#x1d443;、…

uniapp字体ttf在小程序报错,解决方法

文章目录 导文解决方法1&#xff1a;把字体改成base64格式解决方法2&#xff1a;改成线上模式 导文 报错1&#xff1a; uniapp 小程序报错&#xff1a;app.js错误: Error: Module build failed (from ./node_modules/mini-css-extract-plugin/dist/loader.js): ModuleBuildErro…

【Java Web】Pinia实现组件间数据共享

目录 一、Pinia概述 二、Pinia基本用法 一、Pinia概述 在前端工程化的开发环境中&#xff0c;当多个组件(.vue)文件需要使用同一个数据对象时&#xff0c;传统的方法可以使用组件传参或者路由传参来解决但此两种方式都有自己的缺点。pinia可以将多个组件需要共享使用的数据单独…

2024热门骨传导蓝牙耳机怎么选?超全的选购攻略附带好物推荐!

对于很多喜欢运动健身的小伙伴&#xff0c;在现在市面上这么多种类耳机的选择上&#xff0c;对于我来说的话还是很推荐大家去选择骨传导运动耳机的&#xff0c;相较于普通的入耳式蓝牙耳机&#xff0c;骨传导耳机是通过振动来传输声音的&#xff0c;而入耳式耳机则是通过空气传…

餐饮冷库安全守护神:可燃气体报警器检定的科学性与有效性

随着餐饮业的快速发展&#xff0c;冷库成为储存食材、保证食品质量的重要场所。 然而&#xff0c;由于冷库环境的特殊性&#xff0c;如密封性强、温度低、湿度大等&#xff0c;一旦冷库内发生可燃气体泄露&#xff0c;后果将不堪设想。因此&#xff0c;在餐饮冷库中安装并合理…

武汉星起航:自运营团队深耕亚马逊,智慧运营打造跨境电商新标杆

在全球化的浪潮下&#xff0c;跨境电商已成为企业拓展海外市场的重要渠道。而亚马逊作为全球领先的电商平台&#xff0c;其巨大的市场潜力和成熟的运营体系吸引了无数卖家竞相入驻。武汉星起航电子商务有限公司正是众多成功入驻亚马逊的卖家之一&#xff0c;其自运营团队凭借多…

使用Python Selenium,动态网页不再是难题!

目录 1、直接执行JS代码 🌐 1.1 execute_script基础用法 1.2 带参数执行JS函数 1.3 获取执行结果 2、使用execute_async_script异步执行 🔄 2.1 适用场景分析 2.2 实现异步操作示例 2.3 错误处理与调试技巧 3、JS与页面元素交互 👤 3.1 修改DOM属性 3.2 触发事…

独立开发者系列(10)——fastadmin后台框架的认识

软件开发项目涉及到的东西非常多&#xff0c;作为独立开发者&#xff0c;普遍性的面对的是中小项目。而其中接单的情况下&#xff0c;以WEB方向的居多。其中主要有以下这么些类的:搭建官网cms 就是常见的资讯发布平台&#xff0c;发布一些企业新闻/活动宣传&#xff0c;纯粹是…

鸿蒙期末项目(3)

服务器搭建完成之后&#xff0c;编写了诸多api用于数据传输工作&#xff08;略&#xff09; 编写完成之后&#xff0c;回到鸿蒙开发工具&#xff0c;开始编写搜索页面的代码。 打开搜索页面时&#xff0c;先会展示历史搜索记录&#xff08;如果有的话&#xff09;&#xff0c;…

爬取必应关键字搜索结果url

上代码 import aiohttp import asyncio from lxml import etree import aiofiles import time import random aiohttp 和 asyncio 用于异步HTTP请求和事件循环。 lxml 用于解析HTML。 aiofiles 用于异步文件操作。 time 和 random 用于控制爬取速度。 headers {User-Agent: M…

mysql安装创建数据库防止踩坑

为了安装MySQL的家人们走弯路&#xff0c;稍微有些啰嗦&#xff0c;讲述我安装的时遇到的问题&#xff0c;如何解决。仔细看看离成功不远。 mysql下载链接 MySQL :: Download MySQL Community Server windows下安装mysql-8.0.29-winx64&#xff0c;下载安装包后解压到文件夹中…

2024十大首码地推拉新app平台,一手首码对接平台!

到了2024年&#xff0c;地推新应用的接单平台成为创业者们关注的焦点。对于地推行业的从业人员而言&#xff0c;选择一家拥有一手单资源的平台至关重要&#xff0c;因为这直接关系到他们的利益。 2024年如果想要进行app地推活动&#xff0c;却没有人脉渠道的困扰&#xff0c;建…

谷歌网络营销中SEO的策略有哪些?

在网络营销中&#xff0c;SEO&#xff08;搜索引擎优化&#xff09;是一种关键策略&#xff0c;旨在提高网站在搜索引擎结果中的排名。首先&#xff0c;要进行关键词研究&#xff0c;找出潜在客户使用的搜索词。接下来&#xff0c;优化网站内容&#xff0c;使其包含这些关键词&…

【Java Web】Ajax异步请求

目录 一、Ajax概述 二、Ajax执行原理 三、实现Ajax的请求 一、Ajax概述 传统情况下&#xff0c;浏览器与服务端的交互都是采用同步交互的方式进行的&#xff1b;此交互方式用户在向服务端发送请求后只有等到服务端的响应报文回来后用户才能在标签页上进行其它操作&#xff0c;即…