From b17dca87f2c56e4d302ed8241714d9181912926f Mon Sep 17 00:00:00 2001 From: Wangder03 Date: Sun, 15 Dec 2024 00:10:39 +0800 Subject: [PATCH] wangd --- WebContent/js/bootstrap-table.js | 3155 +++++++++++++++++------------- 1 file changed, 1756 insertions(+), 1399 deletions(-) diff --git a/WebContent/js/bootstrap-table.js b/WebContent/js/bootstrap-table.js index 6468574..3c65a58 100644 --- a/WebContent/js/bootstrap-table.js +++ b/WebContent/js/bootstrap-table.js @@ -1,484 +1,656 @@ +// 立即执行函数,用于模块的导出和导入处理,根据不同的环境(CommonJS、AMD、全局变量等)来定义模块的导出方式 +// 如果是CommonJS环境(如Node.js中使用require),则将factory返回的结果赋值给module.exports +// 如果是AMD环境(如使用define来定义模块),则通过define来注册模块并传入依赖和factory +// 如果都不是,则将结果挂载到全局对象(如浏览器的window对象)上作为BootstrapTable (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jquery')) : - typeof define === 'function' && define.amd ? define(['jquery'], factory) : - (global = global || self, global.BootstrapTable = factory(global.jQuery)); + typeof exports === 'object' && typeof module!== 'undefined'? module.exports = factory(require('jquery')) : + typeof define === 'function' && define.amd? define(['jquery'], factory) : + (global = global || self, global.BootstrapTable = factory(global.jQuery)); }(this, (function ($) { 'use strict'; - $ = $ && $.hasOwnProperty('default') ? $['default'] : $; + // 如果传入的$对象有default属性,则取其default属性作为真正的$对象,否则直接使用传入的$对象 + $ = $ && $.hasOwnProperty('default')? $['default'] : $; - var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; + // 根据不同的全局对象存在情况,确定当前的全局对象(优先尝试globalThis,然后是window、global、self等) + var commonjsGlobal = typeof globalThis!== 'undefined'? globalThis : typeof window!== 'undefined'? window : typeof global!== 'undefined'? global : typeof self!== 'undefined'? self : {}; + // 创建一个CommonJS模块的函数,接收一个函数fn和模块对象module + // 执行fn并传入module和module.exports,最后返回module.exports作为模块的导出内容 function createCommonjsModule(fn, module) { return module = { exports: {} }, fn(module, module.exports), module.exports; } + // 检查传入的对象it是否是合法的全局对象(通过判断是否有Math属性且与全局的Math对象相等来简单验证) var check = function (it) { - return it && it.Math == Math && it; + return it && it.Math == Math && it; }; - // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 + // 获取全局对象,通过依次检查不同的全局对象可能性(globalThis、window、self、commonjsGlobal等) + // 如果都不符合则通过创建一个返回this的函数来获取当前上下文的this作为全局对象(在非严格模式下会指向全局对象) var global_1 = - // eslint-disable-next-line no-undef - check(typeof globalThis == 'object' && globalThis) || - check(typeof window == 'object' && window) || - check(typeof self == 'object' && self) || - check(typeof commonjsGlobal == 'object' && commonjsGlobal) || - // eslint-disable-next-line no-new-func - Function('return this')(); - + // eslint-disable-next-line no-undef + check(typeof globalThis == 'object' && globalThis) || + check(typeof window == 'object' && window) || + check(typeof self == 'object' && self) || + check(typeof commonjsGlobal == 'object' && commonjsGlobal) || + // eslint-disable-next-line no-new-func + Function('return this')(); + + // 执行传入的函数exec,如果执行过程中抛出错误则返回true,否则返回函数执行结果的布尔值 + // 用于检测某个操作是否会失败(比如在一些不支持的环境中执行特定代码可能会报错) var fails = function (exec) { - try { - return !!exec(); - } catch (error) { - return true; - } + try { + return!!exec(); + } catch (error) { + return true; + } }; - // Thank's IE8 for his funny defineProperty - var descriptors = !fails(function () { - return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a != 7; + // 检测当前环境是否支持Object.defineProperty的正常行为(通过创建一个带有getter的属性并检查获取的值是否正确来判断) + // 如果不支持(比如在IE8等老版本浏览器中),则descriptors为false + var descriptors =!fails(function () { + return Object.defineProperty({}, 'a', { get: function () { return 7; } }).a!= 7; }); + // 获取原生的propertyIsEnumerable方法(用于判断对象的属性是否可枚举) var nativePropertyIsEnumerable = {}.propertyIsEnumerable; + // 获取Object.getOwnPropertyDescriptor方法(用于获取对象属性的描述符) var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; - // Nashorn ~ JDK8 bug - var NASHORN_BUG = getOwnPropertyDescriptor && !nativePropertyIsEnumerable.call({ 1: 2 }, 1); + // 检测是否存在Nashorn(Java中的JavaScript引擎)与JDK8相关的一个bug(通过检查获取对象属性描述符和原生的propertyIsEnumerable调用结果是否符合预期来判断) + // 如果存在该bug,则NASHORN_BUG为true + var NASHORN_BUG = getOwnPropertyDescriptor &&!nativePropertyIsEnumerable.call({ 1: 2 }, 1); - // `Object.prototype.propertyIsEnumerable` method implementation - // https://tc39.github.io/ecma262/#sec-object.prototype.propertyisenumerable - var f = NASHORN_BUG ? function propertyIsEnumerable(V) { - var descriptor = getOwnPropertyDescriptor(this, V); - return !!descriptor && descriptor.enumerable; + // 根据是否存在NASHORN_BUG来定义propertyIsEnumerable方法的实现 + // 如果有bug,则通过获取属性描述符并检查其enumerable属性来判断是否可枚举 + // 如果没有bug,则直接使用原生的propertyIsEnumerable方法 + var f = NASHORN_BUG? function propertyIsEnumerable(V) { + var descriptor = getOwnPropertyDescriptor(this, V); + return!!descriptor && descriptor.enumerable; } : nativePropertyIsEnumerable; + // 将上述定义的propertyIsEnumerable方法封装到objectPropertyIsEnumerable对象中 var objectPropertyIsEnumerable = { f: f }; + // 根据传入的位图bitmap和值value创建一个属性描述符对象 + // 通过位图的不同位来设置属性的enumerable、configurable、writable等属性的值(位运算判断) var createPropertyDescriptor = function (bitmap, value) { - return { - enumerable: !(bitmap & 1), - configurable: !(bitmap & 2), - writable: !(bitmap & 4), - value: value - }; + return { + enumerable:!(bitmap & 1), + configurable:!(bitmap & 2), + writable:!(bitmap & 4), + value: value + }; }; + // 获取对象的类名(通过调用Object.prototype.toString并截取返回结果的一部分来获取) var toString = {}.toString; - var classofRaw = function (it) { - return toString.call(it).slice(8, -1); + return toString.call(it).slice(8, -1); }; + // 分割字符串的方法(获取空字符串的split方法作为一个函数引用,方便后续使用) var split = ''.split; - // fallback for non-array-like ES3 and non-enumerable old V8 strings + // 处理对象或字符串转换为索引对象(类似数组的可迭代对象)的情况 + // 如果当前环境对于非数组对象或非可枚举的老版本V8字符串有问题(通过检测是否能正确获取字符串的属性是否可枚举来判断) + // 则对字符串进行分割返回字符数组,否则直接返回传入的对象(通过Object进行包装转换为对象类型) var indexedObject = fails(function () { - // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346 - // eslint-disable-next-line no-prototype-builtins - return !Object('z').propertyIsEnumerable(0); - }) ? function (it) { - return classofRaw(it) == 'String' ? split.call(it, '') : Object(it); + // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346 + // eslint-disable-next-line no-prototype-builtins + return!Object('z').propertyIsEnumerable(0); + })? function (it) { + return classofRaw(it) == 'String'? split.call(it, '') : Object(it); } : Object; - // `RequireObjectCoercible` abstract operation - // https://tc39.github.io/ecma262/#sec-requireobjectcoercible + // 确保传入的参数可以转换为对象(如果是undefined则抛出TypeError异常,否则返回该参数本身) + // 类似于ES6中的 `Object` 抽象操作,用于在需要对象的地方进行参数的强制转换 var requireObjectCoercible = function (it) { - if (it == undefined) throw TypeError("Can't call method on " + it); - return it; + if (it == undefined) throw TypeError("Can't call method on " + it); + return it; }; - // toObject with fallback for non-array-like ES3 strings - - - + // 将传入的参数转换为索引对象(先通过requireObjectCoercible确保可以转换为对象,再调用indexedObject进行转换) var toIndexedObject = function (it) { - return indexedObject(requireObjectCoercible(it)); + return indexedObject(requireObjectCoercible(it)); }; + // 判断传入的参数是否为对象(包括函数类型,因为在JavaScript中函数也是对象) var isObject = function (it) { - return typeof it === 'object' ? it !== null : typeof it === 'function'; + return typeof it === 'object'? it!== null : typeof it === 'function'; }; - // `ToPrimitive` abstract operation - // https://tc39.github.io/ecma262/#sec-toprimitive - // instead of the ES6 spec version, we didn't implement @@toPrimitive case - // and the second argument - flag - preferred type is a string + // 将对象转换为原始值(遵循ToPrimitive抽象操作的逻辑,但简化了实现,未处理 @@toPrimitive 情况) + // 如果传入的参数不是对象则直接返回该参数 + // 优先尝试调用toString方法,如果返回值不是对象则返回该值;如果失败则尝试调用valueOf方法;如果还是失败且不要求返回字符串类型,则再次尝试toString方法 + // 如果最终都无法转换则抛出TypeError异常 var toPrimitive = function (input, PREFERRED_STRING) { - if (!isObject(input)) return input; - var fn, val; - if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val; - if (typeof (fn = input.valueOf) == 'function' && !isObject(val = fn.call(input))) return val; - if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject(val = fn.call(input))) return val; - throw TypeError("Can't convert object to primitive value"); + if (!isObject(input)) return input; + var fn, val; + if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' &&!isObject(val = fn.call(input))) return val; + if (typeof (fn = input.valueOf) == 'function' &&!isObject(val = fn.call(input))) return val; + if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' &&!isObject(val = fn.call(input))) return val; + throw TypeError("Can't convert object to primitive value"); }; + // 判断对象是否有指定的自有属性(通过调用原生的hasOwnProperty方法来判断) var hasOwnProperty = {}.hasOwnProperty; - var has = function (it, key) { - return hasOwnProperty.call(it, key); + return hasOwnProperty.call(it, key); }; + // 获取全局的document对象,同时检测document.createElement是否是合法的对象(在老IE中可能不是) var document$1 = global_1.document; - // typeof document.createElement is 'object' in old IE var EXISTS = isObject(document$1) && isObject(document$1.createElement); + // 创建一个指定标签名的DOM元素(如果EXISTS为true则通过document.createElement创建,否则返回一个空对象) var documentCreateElement = function (it) { - return EXISTS ? document$1.createElement(it) : {}; + return EXISTS? document$1.createElement(it) : {}; }; - // Thank's IE8 for his funny defineProperty - var ie8DomDefine = !descriptors && !fails(function () { - return Object.defineProperty(documentCreateElement('div'), 'a', { - get: function () { return 7; } - }).a != 7; + // 检测当前环境是否存在类似IE8中Object.defineProperty的奇怪行为(通过创建一个带有getter的DOM元素属性并检查获取的值是否正确来判断) + var ie8DomDefine =!descriptors &&!fails(function () { + return Object.defineProperty(documentCreateElement('div'), 'a', { + get: function () { return 7; } + }).a!= 7; }); + // 获取原生的Object.getOwnPropertyDescriptor方法(用于获取对象属性的描述符) var nativeGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor; - // `Object.getOwnPropertyDescriptor` method - // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptor - var f$1 = descriptors ? nativeGetOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) { - O = toIndexedObject(O); - P = toPrimitive(P, true); - if (ie8DomDefine) try { - return nativeGetOwnPropertyDescriptor(O, P); - } catch (error) { /* empty */ } - if (has(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]); + // 根据是否支持descriptors以及当前环境情况来定义Object.getOwnPropertyDescriptor方法的实现 + // 如果支持descriptors则直接使用原生方法;如果不支持,则先将对象转换为索引对象,将属性名转换为原始值 + // 然后尝试使用原生方法获取描述符,如果失败(比如在ie8DomDefine的情况下可能会抛错)则根据对象是否有该属性来创建一个简单的属性描述符对象 + var f$1 = descriptors? nativeGetOwnPropertyDescriptor : function getOwnPropertyDescriptor(O, P) { + O = toIndexedObject(O); + P = toPrimitive(P, true); + if (ie8DomDefine) try { + return nativeGetOwnPropertyDescriptor(O, P); + } catch (error) { /* empty */ } + if (has(O, P)) return createPropertyDescriptor(!objectPropertyIsEnumerable.f.call(O, P), O[P]); }; + // 将上述定义的getOwnPropertyDescriptor方法封装到objectGetOwnPropertyDescriptor对象中 var objectGetOwnPropertyDescriptor = { f: f$1 }; + // 确保传入的参数是对象,如果不是则抛出TypeError异常并提示相应信息,否则返回该对象 var anObject = function (it) { - if (!isObject(it)) { - throw TypeError(String(it) + ' is not an object'); - } return it; + if (!isObject(it)) { + throw TypeError(String(it) +'is not an object'); + } + return it; }; + // 获取原生的Object.defineProperty方法(用于定义对象的属性) var nativeDefineProperty = Object.defineProperty; - // `Object.defineProperty` method - // https://tc39.github.io/ecma262/#sec-object.defineproperty - var f$2 = descriptors ? nativeDefineProperty : function defineProperty(O, P, Attributes) { - anObject(O); - P = toPrimitive(P, true); - anObject(Attributes); - if (ie8DomDefine) try { - return nativeDefineProperty(O, P, Attributes); - } catch (error) { /* empty */ } - if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported'); - if ('value' in Attributes) O[P] = Attributes.value; - return O; + // 根据是否支持descriptors以及当前环境情况来定义Object.defineProperty方法的实现 + // 如果支持descriptors则直接使用原生方法;如果不支持,则先确保传入的对象和属性名以及属性描述符对象都是合法的 + // 在ie8DomDefine的情况下尝试使用原生方法定义属性,如果抛错则忽略(可能是不支持的情况) + // 如果属性描述符中有get或set访问器属性则抛出TypeError异常(表示不支持访问器属性的定义) + // 如果有value属性则直接将该值赋给对象的对应属性 + var f$2 = descriptors? nativeDefineProperty : function defineProperty(O, P, Attributes) { + anObject(O); + P = toPrimitive(P, true); + anObject(Attributes); + if (ie8DomDefine) try { + return nativeDefineProperty(O, P, Attributes); + } catch (error) { /* empty */ } + if ('get' in Attributes || 'get' in Attributes) throw TypeError('Accessors not supported'); + if ('value' in Attributes) O[P] = Attributes.value; + return O; }; + // 将上述定义的defineProperty方法封装到objectDefineProperty对象中 var objectDefineProperty = { f: f$2 }; - var createNonEnumerableProperty = descriptors ? function (object, key, value) { - return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value)); + // 根据是否支持descriptors来创建一个不可枚举的属性(如果支持则使用Object.defineProperty创建,否则直接给对象添加属性) + var createNonEnumerableProperty = descriptors? function (object, key, value) { + return objectDefineProperty.f(object, key, createPropertyDescriptor(1, value)); } : function (object, key, value) { - object[key] = value; - return object; + object[key] = value; + return object; }; + // 尝试在全局对象上创建一个不可枚举的属性(如果失败则直接给全局对象添加该属性),最后返回该属性的值 var setGlobal = function (key, value) { - try { - createNonEnumerableProperty(global_1, key, value); - } catch (error) { - global_1[key] = value; - } return value; + try { + createNonEnumerableProperty(global_1, key, value); + } catch (error) { + global_1[key] = value; + } + return value; }; + // 定义一个用于共享数据的全局对象的属性名,获取全局对象上该属性对应的共享存储对象(如果不存在则创建并赋值) var SHARED = '__core-js_shared__'; var store = global_1[SHARED] || setGlobal(SHARED, {}); + // 将共享存储对象赋值给sharedStore,方便后续使用 var sharedStore = store; + // 获取函数的字符串表示形式(通过调用Function.toString方法) var functionToString = Function.toString; - // this helper broken in `3.4.1-3.4.4`, so we can't use `shared` helper - if (typeof sharedStore.inspectSource != 'function') { - sharedStore.inspectSource = function (it) { - return functionToString.call(it); - }; + // 如果共享存储对象没有inspectSource方法,则给它添加一个用于获取函数字符串表示形式的方法 + if (typeof sharedStore.inspectSource!= 'function') { + sharedStore.inspectSource = function (it) { + return functionToString.call(it); + }; } + // 获取共享存储对象的inspectSource方法(用于获取函数的字符串表示形式) var inspectSource = sharedStore.inspectSource; + // 获取全局的WeakMap对象(如果存在的话),用于检测是否原生支持WeakMap var WeakMap = global_1.WeakMap; - var nativeWeakMap = typeof WeakMap === 'function' && /native code/.test(inspectSource(WeakMap)); + // 创建一个共享模块,用于管理一些共享的数据(比如版本信息等) + // 这里定义了一个名为'versions'的共享数据,初始值为一个空数组,并往其中添加了一个版本相关的对象信息 var shared = createCommonjsModule(function (module) { - (module.exports = function (key, value) { - return sharedStore[key] || (sharedStore[key] = value !== undefined ? value : {}); - })('versions', []).push({ - version: '3.6.0', - mode: 'global', - copyright: '© 2019 Denis Pushkarev (zloirock.ru)' + (module.exports = function (key, value) { + return sharedStore[key] || (sharedStore[key] = value!== undefined? value : {}); + })('versions', []).push({ + version: '3.6.0', + mode: 'global', + copyright: '© 2019 Denis Pushkarev (zloirock.ru)' + }); }); - }); - + // 初始化一个标识符变量,初始值为0,用于生成唯一标识时进行自增计数 var id = 0; +// 生成一个随机数后缀,用于和自增的id组合来让生成的唯一标识更具随机性 var postfix = Math.random(); +// 定义一个函数uid,用于生成唯一标识(类似Symbol的作用,但可能是自定义的一种实现方式) +// 它接受一个可选的键名参数key,如果key未定义则使用空字符串 +// 通过将传入的键名、自增的id以及随机后缀组合并转换为36进制字符串来生成唯一标识 var uid = function (key) { - return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id + postfix).toString(36); + return 'Symbol(' + String(key === undefined? '' : key) + ')_' + (++id + postfix).toString(36); }; +// 获取共享的keys对象(这个共享机制可能在代码其他地方有定义,用于存储一些共享的数据结构) +// 通过调用shared函数(具体功能在前面代码中应该有定义,可能是根据传入的键获取对应共享值的函数)传入'keys'来获取 var keys = shared('keys'); +// 定义一个函数sharedKey,用于获取或创建一个共享的键 +// 它会先尝试从keys对象中获取传入的键key对应的键值,如果不存在则调用uid函数生成一个新的唯一键并存储到keys对象中,然后返回这个键值 var sharedKey = function (key) { - return keys[key] || (keys[key] = uid(key)); + return keys[key] || (keys[key] = uid(key)); }; +// 创建一个空对象hiddenKeys,用于存储一些不想被外部轻易访问或枚举到的键名(后续可能会往里面添加内容) var hiddenKeys = {}; +// 获取全局的WeakMap对象(WeakMap是一种弱引用的映射数据结构,用于存储键值对,键是弱引用的,便于垃圾回收) var WeakMap$1 = global_1.WeakMap; +// 定义三个变量set、get、has$1,用于后续根据是否原生支持WeakMap来赋予不同的操作函数 var set, get, has$1; +// 定义一个函数enforce,用于获取对象的相关状态信息(通过has$1判断是否存在相关状态,如果存在则通过get获取,不存在则通过set初始化一个空状态并返回) var enforce = function (it) { - return has$1(it) ? get(it) : set(it, {}); + return has$1(it)? get(it) : set(it, {}); }; +// 定义一个函数getterFor,它返回一个新的函数 +// 这个新函数用于获取传入对象it的内部状态,首先判断传入的对象是否是合法对象以及其内部状态的类型是否符合期望的TYPE类型 +// 如果不符合则抛出TypeError异常提示类型不兼容,符合则返回对象的内部状态信息 var getterFor = function (TYPE) { - return function (it) { - var state; - if (!isObject(it) || (state = get(it)).type !== TYPE) { - throw TypeError('Incompatible receiver, ' + TYPE + ' required'); - } return state; - }; + return function (it) { + var state; + if (!isObject(it) || (state = get(it)).type!== TYPE) { + throw TypeError('Incompatible receiver, ' + TYPE + 'required'); + } + return state; + }; }; +// 根据是否原生支持WeakMap来分别定义set、get、has$1这三个操作函数的具体实现逻辑 if (nativeWeakMap) { - var store$1 = new WeakMap$1(); - var wmget = store$1.get; - var wmhas = store$1.has; - var wmset = store$1.set; - set = function (it, metadata) { - wmset.call(store$1, it, metadata); - return metadata; - }; - get = function (it) { - return wmget.call(store$1, it) || {}; - }; - has$1 = function (it) { - return wmhas.call(store$1, it); - }; + // 如果原生支持WeakMap,则创建一个WeakMap实例store$1 + var store$1 = new WeakMap$1(); + // 获取WeakMap实例的get方法,用于从WeakMap中获取对应键的值 + var wmget = store$1.get; + // 获取WeakMap实例的has方法,用于判断WeakMap中是否存在指定的键 + var wmhas = store$1.has; + // 获取WeakMap实例的set方法,用于向WeakMap中设置键值对 + var wmset = store$1.set; + + // 定义set函数,用于向WeakMap中设置键值对(通过调用WeakMap实例的set方法来实现,并返回设置的元数据metadata) + set = function (it, metadata) { + wmset.call(store$1, it, metadata); + return metadata; + }; + + // 定义get函数,用于从WeakMap中获取对应键的值(通过调用WeakMap实例的get方法获取,如果不存在则返回一个空对象) + get = function (it) { + return wmget.call(store$1, it) || {}; + }; + + // 定义has$1函数,用于判断WeakMap中是否存在指定的键(通过调用WeakMap实例的has方法来判断) + has$1 = function (it) { + return wmhas.call(store$1, it); + }; } else { - var STATE = sharedKey('state'); - hiddenKeys[STATE] = true; - set = function (it, metadata) { - createNonEnumerableProperty(it, STATE, metadata); - return metadata; - }; - get = function (it) { - return has(it, STATE) ? it[STATE] : {}; - }; - has$1 = function (it) { - return has(it, STATE); - }; + // 如果不原生支持WeakMap,则通过自定义的方式来模拟相关功能 + + // 通过sharedKey函数获取一个名为'state'的共享键,并将其标记到hiddenKeys对象中,表示这是一个隐藏的键 + var STATE = sharedKey('state'); + hiddenKeys[STATE] = true; + + // 定义set函数,用于给对象设置一个不可枚举的属性(通过调用createNonEnumerableProperty函数来实现,属性名为STATE,值为传入的metadata) + // 最后返回设置的元数据metadata + set = function (it, metadata) { + createNonEnumerableProperty(it, STATE, metadata); + return metadata; + }; + + // 定义get函数,用于获取对象的内部状态(通过判断对象是否有STATE属性来获取其对应的值,如果不存在则返回一个空对象) + get = function (it) { + return has(it, STATE)? it[STATE] : {}; + }; + + // 定义has$1函数,用于判断对象是否有STATE属性(即是否存在对应的内部状态) + has$1 = function (it) { + return has(it, STATE); + }; } +// 创建一个名为internalState的对象,将上述定义的set、get、has、enforce、getterFor函数作为其属性 +// 方便后续统一管理和使用这些与对象内部状态操作相关的函数 var internalState = { - set: set, - get: get, - has: has$1, - enforce: enforce, - getterFor: getterFor + set: set, + get: get, + has: has$1, + enforce: enforce, + getterFor: getterFor }; +// 定义一个名为redefine的CommonJS模块(通过createCommonjsModule函数来创建模块结构) var redefine = createCommonjsModule(function (module) { - var getInternalState = internalState.get; - var enforceInternalState = internalState.enforce; - var TEMPLATE = String(String).split('String'); - - (module.exports = function (O, key, value, options) { - var unsafe = options ? !!options.unsafe : false; - var simple = options ? !!options.enumerable : false; - var noTargetGet = options ? !!options.noTargetGet : false; - if (typeof value == 'function') { - if (typeof key == 'string' && !has(value, 'name')) createNonEnumerableProperty(value, 'name', key); - enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string' ? key : ''); - } - if (O === global_1) { - if (simple) O[key] = value; - else setGlobal(key, value); - return; - } else if (!unsafe) { - delete O[key]; - } else if (!noTargetGet && O[key]) { - simple = true; - } - if (simple) O[key] = value; - else createNonEnumerableProperty(O, key, value); - // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative - })(Function.prototype, 'toString', function toString() { - return typeof this == 'function' && getInternalState(this).source || inspectSource(this); + // 获取internalState对象中的get函数,用于获取对象内部状态 + var getInternalState = internalState.get; + // 获取internalState对象中的enforce函数,用于获取或初始化对象内部状态 + var enforceInternalState = internalState.enforce; + // 通过将字符串'String'进行分割得到一个包含空字符串的数组(这里的用法比较奇怪,可能后续用于拼接字符串等特殊操作) + var TEMPLATE = String(String).split('String'); + + // 定义模块的导出内容,是一个函数,接受对象O、键名key、值value以及一个可选的配置对象options作为参数 + (module.exports = function (O, key, value, options) { + // 如果传入了options对象,则获取其中的unsafe属性,否则默认为false + var unsafe = options?!!options.unsafe : false; + // 如果传入了options对象,则获取其中的enumerable属性,否则默认为false + // 这个属性可能用于控制设置的属性是否可枚举 + var simple = options?!!options.enumerable : false; + // 如果传入了options对象,则获取其中的noTargetGet属性,否则默认为false + var noTargetGet = options?!!options.noTargetGet : false; + + // 如果传入的值value是一个函数 + if (typeof value == 'function') { + // 如果键名key是字符串类型且传入的函数没有name属性(函数的name属性通常用于表示函数的名称) + // 则通过调用createNonEnumerableProperty函数给函数设置一个不可枚举的name属性,值为键名key + if (typeof key == 'string' &&!has(value, 'name')) createNonEnumerableProperty(value, 'name', key); + // 通过调用enforceInternalState函数获取函数的内部状态,并设置其source属性为根据键名key拼接的字符串(通过TEMPLATE数组进行拼接) + enforceInternalState(value).source = TEMPLATE.join(typeof key == 'string'? key : ''); + } + + // 如果对象O是全局对象(global_1可能是前面代码中定义的全局对象的引用) + if (O === global_1) { + // 如果simple为true,则直接将值value赋给全局对象的键名key对应的属性(相当于设置一个可枚举的属性) + if (simple) O[key] = value; + // 如果simple为false,则通过调用setGlobal函数(前面应该有定义,可能用于设置全局的不可枚举属性)来设置属性 + else setGlobal(key, value); + return; + } else if (!unsafe) { + // 如果不是全局对象且unsafe为false,则删除对象O中键名key对应的属性 + delete O[key]; + } else if (!noTargetGet && O[key]) { + // 如果unsafe为true且对象O中已经存在键名key对应的属性,则将simple设置为true(可能后续会按照可枚举属性的方式进行处理) + simple = true; + } + + // 如果simple为true,则直接将值value赋给对象O的键名key对应的属性(设置为可枚举属性) + if (simple) O[key] = value; + // 如果simple为false,则通过调用createNonEnumerableProperty函数给对象O设置一个不可枚举的属性,键名是key,值是value + else createNonEnumerableProperty(O, key, value); + + // 以下是一个注释,提到添加一个伪造的Function#toString方法,用于在处理包装方法、构造函数以及类似LoDash的isNative方法等情况时能正确工作 + // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative + })(Function.prototype, 'toString', function toString() { + // 重定义Function.prototype.toString方法的逻辑 + // 如果当前对象this是一个函数,则通过调用getInternalState函数获取其内部状态,并返回内部状态的source属性值(如果存在) + // 如果不存在内部状态的source属性值,则调用inspectSource函数(前面应该有定义,可能用于获取函数的原始字符串表示形式)来返回函数的字符串表示形式 + return typeof this == 'function' && getInternalState(this).source || inspectSource(this); + }); }); - }); - +// 将前面定义的全局对象(global_1)赋值给path变量,后续可能基于这个变量去获取一些全局作用域下的内容 var path = global_1; +// 定义一个函数aFunction,用于判断传入的变量是否为函数类型 +// 如果是函数类型,则返回该变量本身,否则返回undefined var aFunction = function (variable) { - return typeof variable == 'function' ? variable : undefined; + return typeof variable == 'function'? variable : undefined; }; +// 定义一个函数getBuiltIn,用于获取指定命名空间下的内置函数或方法 +// 如果传入的参数个数小于2(即只传入了命名空间,没有指定具体方法名),则尝试从path对象和global_1对象中获取该命名空间对应的函数并返回(优先从path中获取,如果不存在则从global_1中获取) +// 如果传入了两个参数(命名空间和具体方法名),则尝试从path对象和global_1对象中获取对应命名空间下的指定方法并返回(同样优先从path中获取,如果不存在则从global_1中获取) var getBuiltIn = function (namespace, method) { - return arguments.length < 2 ? aFunction(path[namespace]) || aFunction(global_1[namespace]) - : path[namespace] && path[namespace][method] || global_1[namespace] && global_1[namespace][method]; + return arguments.length < 2? aFunction(path[namespace]) || aFunction(global_1[namespace]) + : path[namespace] && path[namespace][method] || global_1[namespace] && global_1[namespace][method]; }; +// 获取JavaScript内置的向上取整函数Math.ceil,并赋值给ceil变量,方便后续使用 var ceil = Math.ceil; +// 获取JavaScript内置的向下取整函数Math.floor,并赋值给floor变量,方便后续使用 var floor = Math.floor; - // `ToInteger` abstract operation - // https://tc39.github.io/ecma262/#sec-tointeger +// 实现 `ToInteger` 抽象操作(按照ECMAScript规范中的定义来将传入的参数转换为整数) +// 首先尝试将参数转换为数值(通过前置 + 操作符),如果转换后是NaN,则返回0 +// 如果转换后的数值大于0,则使用floor函数向下取整;如果小于等于0,则使用ceil函数向上取整 var toInteger = function (argument) { - return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor : ceil)(argument); + return isNaN(argument = +argument)? 0 : (argument > 0? floor : ceil)(argument); }; +// 获取JavaScript内置的取最小值函数Math.min,并赋值给min变量,方便后续使用 var min = Math.min; - // `ToLength` abstract operation - // https://tc39.github.io/ecma262/#sec-tolength +// 实现 `ToLength` 抽象操作(按照ECMAScript规范中的定义将传入的参数转换为合适的长度值) +// 如果传入的参数大于0,则先将其转换为整数(通过调用toInteger函数),然后取该整数与0x1FFFFFFFFFFFFF(2 ** 53 - 1,JavaScript中能安全表示的最大正整数长度值)中的较小值作为结果返回 +// 如果传入的参数小于等于0,则直接返回0 var toLength = function (argument) { - return argument > 0 ? min(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991 + return argument > 0? min(toInteger(argument), 0x1FFFFFFFFFFFFF) : 0; }; +// 获取JavaScript内置的取最大值函数Math.max,并赋值给max变量,方便后续使用 var max = Math.max; +// 获取JavaScript内置的取最小值函数Math.min,并赋值给min$1变量(这里min和min$1可能是为了区分不同使用场景下的取最小值操作,虽然功能一样但避免变量名冲突) var min$1 = Math.min; - // Helper for a popular repeating case of the spec: - // Let integer be ? ToInteger(index). - // If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length). +// 定义一个辅助函数toAbsoluteIndex,用于根据给定的索引值和数组长度来计算一个合法的绝对索引值 +// 首先将传入的索引值index转换为整数(通过调用toInteger函数) +// 如果转换后的整数小于0,则计算 (length + integer) 和 0 中的较大值作为结果返回(相当于处理负数索引,将其转换为从数组末尾往前数的对应正数索引) +// 如果转换后的整数大于等于0,则取该整数和数组长度length中的较小值作为结果返回(确保索引不会超出数组范围) var toAbsoluteIndex = function (index, length) { - var integer = toInteger(index); - return integer < 0 ? max(integer + length, 0) : min$1(integer, length); + var integer = toInteger(index); + return integer < 0? max(integer + length, 0) : min$1(integer, length); }; - // `Array.prototype.{ indexOf, includes }` methods implementation +// 定义一个函数createMethod,用于创建 `Array.prototype.indexOf` 或 `Array.prototype.includes` 方法的自定义实现逻辑 +// 它接受一个布尔值参数IS_INCLUDES,用于区分是创建 `includes` 方法还是 `indexOf` 方法的逻辑 var createMethod = function (IS_INCLUDES) { - return function ($this, el, fromIndex) { - var O = toIndexedObject($this); - var length = toLength(O.length); - var index = toAbsoluteIndex(fromIndex, length); - var value; - // Array#includes uses SameValueZero equality algorithm - // eslint-disable-next-line no-self-compare - if (IS_INCLUDES && el != el) while (length > index) { - value = O[index++]; - // eslint-disable-next-line no-self-compare - if (value != value) return true; - // Array#indexOf ignores holes, Array#includes - not - } else for (;length > index; index++) { - if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0; - } return !IS_INCLUDES && -1; - }; + return function ($this, el, fromIndex) { + // 将传入的数组对象$this转换为索引对象(可能是为了统一处理不同类型的类似数组对象,保证可以正确遍历属性等,调用了前面定义的toIndexedObject函数) + var O = toIndexedObject($this); + // 获取转换后对象的长度,并通过调用toLength函数确保长度值是合法的长度表示(按照规范进行处理) + var length = toLength(O.length); + // 根据传入的起始索引fromIndex和数组长度计算出实际要开始查找的索引位置(调用toAbsoluteIndex函数进行计算) + var index = toAbsoluteIndex(fromIndex, length); + var value; + + // 如果是创建 `Array.prototype.includes` 方法的逻辑(IS_INCLUDES为true),并且查找元素el与自身不相等(这里用于处理特殊的NaN情况,在SameValueZero相等算法下,NaN不等于自身) + // 则通过循环遍历数组(从计算出的索引位置开始,直到数组末尾) + if (IS_INCLUDES && el!= el) while (length > index) { + value = O[index++]; + // 如果当前遍历到的元素也不等于自身(同样是处理NaN情况),则表示找到了符合条件的元素(因为按照SameValueZero算法,NaN与NaN相等),返回true + if (value!= value) return true; + } + // 如果是创建 `Array.prototype.indexOf` 方法的逻辑(IS_INCLUDES为false)或者是 `Array.prototype.includes` 方法且当前元素不是NaN情况 + else for (; length > index; index++) { + // 判断当前索引位置是否在对象中存在(对于 `indexOf` 方法会忽略数组中的空洞情况,而 `includes` 方法会严格按照索引顺序判断;这里通过 IS_INCLUDES || index in O 来体现这种差异) + // 并且当前位置的元素与要查找的元素el严格相等(使用 === 进行比较) + // 如果满足条件,则根据是 `includes` 方法还是 `indexOf` 方法返回相应的值( `includes` 方法返回true或者当前索引值(如果索引不为0), `indexOf` 方法返回当前索引值) + if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0; + } + + // 如果遍历完整个数组都没有找到符合条件的元素,则根据是 `includes` 方法还是 `indexOf` 方法返回相应的值( `includes` 方法返回false, `indexOf` 方法返回 -1) + return!IS_INCLUDES && -1; + }; }; +// 创建一个名为arrayIncludes的对象,将自定义实现的 `Array.prototype.includes` 和 `Array.prototype.indexOf` 方法挂载到该对象上 +// 通过调用createMethod函数并传入不同的参数来分别创建这两个方法的实现逻辑 var arrayIncludes = { - // `Array.prototype.includes` method - // https://tc39.github.io/ecma262/#sec-array.prototype.includes - includes: createMethod(true), - // `Array.prototype.indexOf` method - // https://tc39.github.io/ecma262/#sec-array.prototype.indexof - indexOf: createMethod(false) + // `Array.prototype.includes` 方法的自定义实现,调用createMethod函数并传入true来创建符合 `includes` 方法逻辑的函数 + includes: createMethod(true), + // `Array.prototype.indexOf` 方法的自定义实现,调用createMethod函数并传入false来创建符合 `indexOf` 方法逻辑的函数 + indexOf: createMethod(false) }; - +// 获取之前在 `arrayIncludes` 对象中自定义实现的 `indexOf` 方法,并赋值给 `indexOf` 变量,方便后续直接使用该方法进行元素查找等操作 var indexOf = arrayIncludes.indexOf; - +// 定义一个函数 `objectKeysInternal`,用于获取对象的键名列表,它接收一个对象 `object` 和一个可选的键名数组 `names` 参数 var objectKeysInternal = function (object, names) { - var O = toIndexedObject(object); - var i = 0; - var result = []; - var key; - for (key in O) !has(hiddenKeys, key) && has(O, key) && result.push(key); - // Don't enum bug & hidden keys - while (names.length > i) if (has(O, key = names[i++])) { - ~indexOf(result, key) || result.push(key); - } - return result; + // 首先将传入的 `object` 转换为索引对象(调用 `toIndexedObject` 函数进行转换,确保可以正确遍历其属性,前面代码应该有对该函数的定义) + var O = toIndexedObject(object); + var i = 0; + var result = []; + var key; + + // 遍历对象 `O` 的可枚举属性(通过 `for...in` 循环),同时进行一些条件判断 + // 检查当前属性键 `key` 不在 `hiddenKeys` 集合中(`hiddenKeys` 可能用于标记一些不想被枚举或特殊处理的键,前面代码有定义)并且对象 `O` 自身确实拥有该属性(通过 `has` 函数判断,前面也有定义) + // 如果满足条件,则将该属性键 `key` 添加到 `result` 数组中 + for (key in O)!has(hiddenKeys, key) && has(O, key) && result.push(key); + + // 处理可能存在的 “Don't enum bug”(不可枚举属性的相关问题,可能是在某些旧浏览器等环境下存在的问题)以及隐藏键的情况 + // 遍历传入的 `names` 数组(如果有的话),从索引 `i` 开始(初始为0) + while (names.length > i) if (has(O, key = names[i++])) { + // 使用位非运算符 `~` 结合 `indexOf` 方法来判断 `key` 是否已经在 `result` 数组中(位非运算符用于将 `indexOf` 返回的 -1 转换为 0,其他值转换为非 0,方便进行逻辑判断) + // 如果 `key` 不在 `result` 数组中(`~indexOf(result, key)` 为真),则将其添加到 `result` 数组中 + ~indexOf(result, key) || result.push(key); + } + + // 最后返回包含对象 `O` 符合条件的键名的数组 `result` + return result; }; - // IE8- don't enum bug keys +// 定义一个数组 `enumBugKeys`,包含了在 IE8 及以下版本浏览器中存在的与对象属性枚举相关的一些“问题键” +// 这些键在某些情况下可能不会按照预期被枚举,比如 `constructor`、`hasOwnProperty` 等方法属性 var enumBugKeys = [ - 'constructor', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'toLocaleString', - 'toString', - 'valueOf' + 'constructor', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'toLocaleString', + 'toString', + 'valueOf' ]; +// 创建一个新的数组 `hiddenKeys$1`,将 `enumBugKeys` 数组中的键名与 `length` 和 `prototype` 两个键名合并在一起 +// 这个数组可能用于后续标记更多不想被轻易枚举或者需要特殊处理的键名情况 var hiddenKeys$1 = enumBugKeys.concat('length', 'prototype'); - // `Object.getOwnPropertyNames` method - // https://tc39.github.io/ecma262/#sec-object.getownpropertynames +// 定义一个变量 `f$3`,用于获取对象的自有属性名列表 +// 首先尝试获取原生的 `Object.getOwnPropertyNames` 方法,如果不存在(可能在某些不支持的环境中),则使用自定义的 `objectKeysInternal` 函数来获取 +// 传入当前要获取属性名的对象 `O` 和前面定义的 `hiddenKeys$1` 数组作为参数,以此来获取对象的属性名(包含了处理特殊键名情况的逻辑) var f$3 = Object.getOwnPropertyNames || function getOwnPropertyNames(O) { - return objectKeysInternal(O, hiddenKeys$1); + return objectKeysInternal(O, hiddenKeys$1); }; +// 创建一个名为 `objectGetOwnPropertyNames` 的对象,将 `f$3` 函数作为其 `f` 属性挂载上去 +// 这样可以通过 `objectGetOwnPropertyNames.f` 的方式方便地调用获取对象自有属性名的函数逻辑 var objectGetOwnPropertyNames = { f: f$3 }; +// 获取原生的 `Object.getOwnPropertySymbols` 方法(用于获取对象的符号属性,在 ES6 中引入了符号类型作为属性名的一种特殊情况),并赋值给 `f$4` 变量 var f$4 = Object.getOwnPropertySymbols; +// 创建一个名为 `objectGetOwnPropertySymbols` 的对象,将 `f$4` 函数作为其 `f` 属性挂载上去 +// 方便后续通过 `objectGetOwnPropertySymbols.f` 的方式调用获取对象符号属性的函数逻辑 var objectGetOwnPropertySymbols = { f: f$4 }; - // all object keys, includes non-enumerable and symbols +// 定义一个函数 `ownKeys`,用于获取对象的所有键(包括自有属性键、非自有属性键、符号属性键等所有情况) +// 首先尝试获取原生的 `Reflect.ownKeys` 方法(`Reflect` 是 ES6 中新增的一个内置对象,提供了一些操作对象的反射方法),如果不存在则使用自定义的逻辑来获取 +// 自定义逻辑是先通过调用 `objectGetOwnPropertyNames.f` 函数(前面定义的获取对象自有属性名的方式)获取对象的自有属性名列表 `keys` +// 然后获取 `objectGetOwnPropertySymbols.f` 函数(用于获取符号属性的函数,如果存在的话) +// 如果能获取到获取符号属性的函数(即 `getOwnPropertySymbols` 不为 `null`),则将符号属性列表与自有属性名列表合并起来作为最终结果返回;否则直接返回自有属性名列表 `keys` var ownKeys = getBuiltIn('Reflect', 'ownKeys') || function ownKeys(it) { - var keys = objectGetOwnPropertyNames.f(anObject(it)); - var getOwnPropertySymbols = objectGetOwnPropertySymbols.f; - return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys; + var keys = objectGetOwnPropertyNames.f(anObject(it)); + var getOwnPropertySymbols = objectGetOwnPropertySymbols.f; + return getOwnPropertySymbols? keys.concat(getOwnPropertySymbols(it)) : keys; }; +// 定义一个函数 `copyConstructorProperties`,用于将一个对象(`source`)的属性复制到另一个对象(`target`)上 +// 首先获取 `source` 对象的所有键(通过调用 `ownKeys` 函数),然后获取用于定义对象属性的 `defineProperty` 函数(通过 `objectDefineProperty.f`,前面代码应该有相关定义) +// 以及获取对象属性描述符的 `getOwnPropertyDescriptor` 函数(通过 `objectGetOwnPropertyDescriptor.f`,前面也有定义) +// 接着遍历 `source` 对象的所有键,对于 `target` 对象中不存在的键(通过 `has` 函数判断),则将 `source` 对象对应键的属性描述符复制到 `target` 对象上(通过调用 `defineProperty` 函数) var copyConstructorProperties = function (target, source) { - var keys = ownKeys(source); - var defineProperty = objectDefineProperty.f; - var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f; - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (!has(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key)); - } + var keys = ownKeys(source); + var defineProperty = objectDefineProperty.f; + var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f; + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + if (!has(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key)); + } }; +// 定义一个正则表达式 `replacement`,用于匹配字符串中的 `#` 字符或者 `.prototype.` 字符串片段 +// 可能后续用于对某些字符串进行规范化处理,替换相关内容 var replacement = /#|\.prototype\./; +// 定义一个函数 `isForced`,用于判断某个功能特性(`feature`)是否需要强制使用 polyfill(垫片代码) +// 首先从 `data` 对象中根据规范化后的功能特性名称(通过 `normalize` 函数处理后的名称,后面有定义)获取对应的值 `value` +// 然后根据 `value` 的值进行判断,如果是 `POLYFILL`(前面应该有定义,表示需要使用 polyfill)则返回 `true` +// 如果是 `NATIVE`(表示原生支持,不需要 polyfill)则返回 `false` +// 如果传入的 `detection` 参数是一个函数,则通过调用 `fails` 函数(前面代码有定义,用于检测函数执行是否失败)来判断是否需要 polyfill(可能根据函数执行情况来决定) +// 如果 `detection` 不是函数,则直接将其转换为布尔值作为判断结果(可能是直接传入一个布尔值来表示是否强制使用 polyfill 的情况) var isForced = function (feature, detection) { - var value = data[normalize(feature)]; - return value == POLYFILL ? true - : value == NATIVE ? false - : typeof detection == 'function' ? fails(detection) - : !!detection; + var value = data[normalize(feature)]; + return value == POLYFILL? true + : value == NATIVE? false + : typeof detection == 'function'? fails(detection) + :!!detection; }; +// 定义 `normalize` 函数,它是 `isForced` 函数的一个属性(通过这种方式将规范化功能与 `isForced` 关联起来) +// 用于将传入的字符串 `string` 进行规范化处理,将其中的 `#` 字符或者 `.prototype.` 字符串片段替换为 `.`,然后转换为小写形式并返回 var normalize = isForced.normalize = function (string) { - return String(string).replace(replacement, '.').toLowerCase(); + return String(string).replace(replacement, '.').toLowerCase(); }; +// 创建一个空对象 `data`,用于存储功能特性相关的数据(可能存储每个功能特性是否需要 polyfill 等信息),并将其挂载到 `isForced` 函数上作为 `data` 属性 var data = isForced.data = {}; +// 定义一个常量 `NATIVE`,值为 `'N'`,用于在 `data` 对象中标记某个功能特性是原生支持的情况,同样挂载到 `isForced` 函数上方便统一使用 var NATIVE = isForced.NATIVE = 'N'; +// 定义一个常量 `POLYFILL`,值为 `'P'`,用于在 `data` 对象中标记某个功能特性需要使用 polyfill 的情况,也挂载到 `isForced` 函数上便于使用 var POLYFILL = isForced.POLYFILL = 'P'; +// 将 `isForced` 函数赋值给 `isForced_1` 变量,可能是为了方便后续在其他地方使用这个判断功能时使用不同的变量名进行引用,避免命名冲突等情况 var isForced_1 = isForced; +// 获取 `objectGetOwnPropertyDescriptor.f` 函数(前面定义的用于获取对象属性描述符的函数),并赋值给 `getOwnPropertyDescriptor$1` 变量,方便后续直接使用该函数获取属性描述符 var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f; - - - - /* options.target - name of the target object options.global - target is the global object @@ -493,939 +665,1062 @@ options.enumerable - export as enumerable property options.noTargetGet - prevent calling a getter on target */ + // 定义一个名为 `_export` 的函数,用于将一个对象(`source`)的属性按照一定规则导出到另一个目标对象(`target`)上,接受 `options` 和 `source` 两个参数 var _export = function (options, source) { - var TARGET = options.target; - var GLOBAL = options.global; - var STATIC = options.stat; - var FORCED, target, key, targetProperty, sourceProperty, descriptor; - if (GLOBAL) { - target = global_1; - } else if (STATIC) { - target = global_1[TARGET] || setGlobal(TARGET, {}); - } else { - target = (global_1[TARGET] || {}).prototype; - } - if (target) for (key in source) { - sourceProperty = source[key]; - if (options.noTargetGet) { - descriptor = getOwnPropertyDescriptor$1(target, key); - targetProperty = descriptor && descriptor.value; - } else targetProperty = target[key]; - FORCED = isForced_1(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced); - // contained in target - if (!FORCED && targetProperty !== undefined) { - if (typeof sourceProperty === typeof targetProperty) continue; - copyConstructorProperties(sourceProperty, targetProperty); - } - // add a flag to not completely full polyfills - if (options.sham || (targetProperty && targetProperty.sham)) { - createNonEnumerableProperty(sourceProperty, 'sham', true); - } - // extend global - redefine(target, key, sourceProperty, options); - } + // 从 `options` 对象中获取 `target` 属性值,并赋值给 `TARGET` 变量,可能用于指定目标对象的相关标识或名称 + var TARGET = options.target; + // 从 `options` 对象中获取 `global` 属性值,并赋值给 `GLOBAL` 变量,可能用于判断是否将属性导出到全局对象上 + var GLOBAL = options.global; + // 从 `options` 对象中获取 `stat` 属性值,并赋值给 `STATIC` 变量,其作用可能与是否是静态属性等相关(结合后续代码判断) + var STATIC = options.stat; + // 定义几个变量,`FORCED` 可能用于标记某个属性是否被强制处理,`target` 用于存储最终的目标对象,`key` 用于遍历属性时的键名,`targetProperty` 和 `sourceProperty` 分别用于存储目标对象和源对象的属性值,`descriptor` 用于存储属性描述符 + var FORCED, target, key, targetProperty, sourceProperty, descriptor; + + // 根据 `GLOBAL` 的值来确定目标对象 `target` + // 如果 `GLOBAL` 为 `true`,则将全局对象(`global_1`,前面代码应该有定义)赋值给 `target`,表示要将属性导出到全局对象上 + if (GLOBAL) { + target = global_1; + } + // 如果 `STATIC` 为 `true`,则尝试从全局对象中获取以 `TARGET` 为名的属性值作为目标对象,如果不存在则通过 `setGlobal` 函数(前面应该有定义,可能用于创建全局属性)创建一个空对象并赋值给 `target` + // 这种情况可能是处理静态属性的导出,将属性添加到全局对象下特定的一个命名空间(以 `TARGET` 标识)中 + else if (STATIC) { + target = global_1[TARGET] || setGlobal(TARGET, {}); + } + // 如果 `GLOBAL` 和 `STATIC` 都不为 `true`,则尝试从全局对象中获取以 `TARGET` 为名的属性对象的原型对象(通过访问 `prototype` 属性)作为目标对象,如果不存在则使用一个空对象作为目标对象的原型 + // 这可能是将属性添加到某个对象的原型链上的情况,用于实现继承等相关功能 + else { + target = (global_1[TARGET] || {}).prototype; + } + + // 如果成功确定了目标对象 `target`,则开始遍历源对象 `source` 的属性 + if (target) for (key in source) { + // 获取源对象 `source` 中当前键 `key` 对应的属性值,并赋值给 `sourceProperty` + sourceProperty = source[key]; + + // 根据 `options` 中的 `noTargetGet` 属性值来决定如何获取目标对象 `target` 中对应键 `key` 的属性值(`targetProperty`) + // 如果 `noTargetGet` 为 `true`,则通过调用 `getOwnPropertyDescriptor$1` 函数(前面代码有定义,用于获取对象属性描述符)获取属性描述符,再从描述符中获取 `value` 属性作为 `targetProperty` + if (options.noTargetGet) { + descriptor = getOwnPropertyDescriptor$1(target, key); + targetProperty = descriptor && descriptor.value; + } + // 如果 `noTargetGet` 不为 `true`,则直接通过键名 `key` 从目标对象 `target` 中获取属性值赋值给 `targetProperty` + else targetProperty = target[key]; + + // 通过调用 `isForced_1` 函数(前面代码有定义,用于判断某个功能特性是否需要强制使用 polyfill 等情况)来判断当前属性是否需要被强制处理 + // 根据 `GLOBAL` 的值来决定传入 `isForced_1` 函数的第一个参数(如果 `GLOBAL` 为 `true`,则传入键名 `key`;否则传入由 `TARGET`、特定分隔符(根据 `STATIC` 判断是 `.` 还是 `#`)以及键名 `key` 组成的字符串) + // 同时传入 `options.forced` 作为第二个参数(其具体作用可能与强制处理的具体条件相关) + FORCED = isForced_1(GLOBAL? key : TARGET + (STATIC? '.' : '#') + key, options.forced); + + // 如果当前属性不需要被强制处理(`FORCED` 为 `false`)并且目标对象 `target` 中已经存在该属性(`targetProperty` 不为 `undefined`) + if (!FORCED && targetProperty!== undefined) { + // 比较源对象和目标对象中对应属性的类型,如果类型相同则跳过当前属性的处理(可能认为不需要重复设置相同类型的属性) + if (typeof sourceProperty === typeof targetProperty) continue; + // 如果类型不同,则调用 `copyConstructorProperties` 函数(前面代码有定义,用于复制属性的相关操作)将源对象属性的相关属性描述符等复制到目标对象属性上 + copyConstructorProperties(sourceProperty, targetProperty); + } + + // 如果 `options` 中有 `sham` 属性并且其值为 `true`,或者目标对象属性(`targetProperty`)存在且其自身有 `sham` 属性并且值为 `true` + // 则通过调用 `createNonEnumerableProperty` 函数(前面代码有定义,用于创建不可枚举属性)给源对象属性添加一个名为 `sham` 的不可枚举属性,值为 `true` + // 这里的 `sham` 可能用于标记某些属性是一种 “伪” 实现或者不完全的填充(polyfill)等特殊情况 + if (options.sham || (targetProperty && targetProperty.sham)) { + createNonEnumerableProperty(sourceProperty, 'sham', true); + } + + // 调用 `redefine` 函数(前面代码有定义,涉及对象属性的重新定义等操作),按照 `options` 中的配置以及当前的键名 `key` 和源对象属性值 `sourceProperty` 来重新定义目标对象 `target` 中的属性 + redefine(target, key, sourceProperty, options); + } }; - var nativeSymbol = !!Object.getOwnPropertySymbols && !fails(function () { - // Chrome 38 Symbol has incorrect toString conversion - // eslint-disable-next-line no-undef - return !String(Symbol()); +// 判断当前环境是否原生支持 `Symbol`(通过检查是否存在 `Object.getOwnPropertySymbols` 方法并且尝试创建一个 `Symbol` 实例并转换为字符串时不会出错来判断) +// 如果满足条件,则 `nativeSymbol` 为 `true`,表示原生支持 `Symbol`;否则为 `false` + var nativeSymbol =!!Object.getOwnPropertySymbols &&!fails(function () { + // Chrome 38 Symbol has incorrect toString conversion + // eslint-disable-next-line no-undef + return!String(Symbol()); }); +// 根据一些条件判断是否可以使用 `Symbol` 作为唯一标识符(`uid`) +// 首先要求原生支持 `Symbol`(`nativeSymbol` 为 `true`),然后要求 `Symbol` 没有 `sham` 属性(可能表示是完全原生的,不是模拟的情况)并且创建的 `Symbol` 实例确实是 `symbol` 类型(通过 `typeof` 判断) +// 如果满足这些条件,则 `useSymbolAsUid` 为 `true`,表示可以使用 `Symbol` 作为唯一标识符;否则为 `false` var useSymbolAsUid = nativeSymbol - // eslint-disable-next-line no-undef - && !Symbol.sham - // eslint-disable-next-line no-undef - && typeof Symbol() == 'symbol'; - - // `IsArray` abstract operation - // https://tc39.github.io/ecma262/#sec-isarray + // eslint-disable-next-line no-undef + &&!Symbol.sham + // eslint-disable-next-line no-undef + && typeof Symbol() == 'symbol'; + +// 实现 `IsArray` 抽象操作(按照 ECMAScript 规范中的定义来判断传入的参数是否为数组) +// 首先尝试获取原生的 `Array.isArray` 方法,如果存在则直接使用;如果不存在,则通过自定义的逻辑判断(通过调用 `classofRaw` 函数(前面代码有定义,用于获取对象的类名)判断是否为 `'Array'` 类来确定是否为数组) +// 并将判断函数赋值给 `isArray` 变量,方便后续直接使用该函数判断是否为数组 var isArray = Array.isArray || function isArray(arg) { - return classofRaw(arg) == 'Array'; + return classofRaw(arg) == 'Array'; }; - // `ToObject` abstract operation - // https://tc39.github.io/ecma262/#sec-toobject +// 实现 `ToObject` 抽象操作(按照 ECMAScript 规范中的定义将传入的参数转换为对象) +// 通过调用 `Object` 函数并传入经过 `requireObjectCoercible` 函数(前面代码有定义,用于确保参数可以转换为对象并进行必要的错误处理)处理后的参数,将其转换为对象并返回 var toObject = function (argument) { - return Object(requireObjectCoercible(argument)); + return Object(requireObjectCoercible(argument)); }; - // `Object.keys` method - // https://tc39.github.io/ecma262/#sec-object.keys +// 实现 `Object.keys` 方法(用于获取对象自身可枚举的属性名组成的数组) +// 首先尝试获取原生的 `Object.keys` 方法,如果存在则直接使用;如果不存在,则通过调用自定义的 `objectKeysInternal` 函数(前面代码有定义,涉及对象属性名获取并处理一些特殊情况)传入对象 `O` 和 `enumBugKeys` 数组(前面代码有定义,包含一些特殊的键名)来获取对象的属性名数组 +// 并将获取属性名的函数赋值给 `objectKeys` 变量,方便后续直接使用该函数获取对象的属性名 var objectKeys = Object.keys || function keys(O) { - return objectKeysInternal(O, enumBugKeys); + return objectKeysInternal(O, enumBugKeys); }; - // `Object.defineProperties` method - // https://tc39.github.io/ecma262/#sec-object.defineproperties - var objectDefineProperties = descriptors ? Object.defineProperties : function defineProperties(O, Properties) { - anObject(O); - var keys = objectKeys(Properties); - var length = keys.length; - var index = 0; - var key; - while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]); - return O; +// 实现 `Object.defineProperties` 方法(用于同时定义对象的多个属性) +// 根据是否支持 `descriptors`(前面代码有相关定义,用于判断是否支持某些对象属性描述符相关的原生特性)来选择不同的实现方式 +// 如果支持 `descriptors`,则直接使用原生的 `Object.defineProperties` 方法;如果不支持,则通过自定义逻辑来实现 +// 自定义逻辑是先确保传入的对象 `O` 是合法的对象(通过调用 `anObject` 函数(前面代码有定义)进行判断),然后获取要定义的属性对象 `Properties` 的属性名数组(通过调用 `objectKeys` 函数) +// 接着遍历属性名数组,通过调用 `objectDefineProperty.f` 函数(前面代码有定义,用于定义对象的单个属性)依次将 `Properties` 中对应属性名的属性定义到对象 `O` 上,最后返回定义好属性后的对象 `O` + var objectDefineProperties = descriptors? Object.defineProperties : function defineProperties(O, Properties) { + anObject(O); + var keys = objectKeys(Properties); + var length = keys.length; + var index = 0; + var key; + while (length > index) objectDefineProperty.f(O, key = keys[index++], Properties[key]); + return O; }; +// 获取全局文档对象(`document`)中的文档根元素(`documentElement`),并赋值给 `html` 变量(可能后续会基于这个元素进行一些与 HTML 相关的操作,不过这里只是简单获取一下) var html = getBuiltIn('document', 'documentElement'); +// 定义几个常量,分别表示 HTML 中的大于号(`>`)、小于号(`<`)、原型(`prototype`)、脚本(`script`)以及一个共享的键名(`IE_PROTO`,通过调用 `sharedKey` 函数(前面代码有定义)生成,可能用于特定的与 IE 浏览器相关或者其他需要共享的属性标记等情况) var GT = '>'; var LT = '<'; var PROTOTYPE = 'prototype'; var SCRIPT = 'script'; var IE_PROTO = sharedKey('IE_PROTO'); +// 定义一个空的构造函数 `EmptyConstructor`,函数体为空,可能用于后续继承或者创建对象实例等情况时作为一个基础的构造函数模板(具体用途还需结合更多上下文判断) var EmptyConstructor = function () { /* empty */ }; +// 定义一个函数 `scriptTag`,用于生成一个简单的 HTML 脚本标签内容 +// 它接受一个参数 `content`,表示要放在脚本标签内部的内容(比如 JavaScript 代码等) +// 通过拼接 HTML 标签的开始部分(``)来生成完整的脚本标签内容字符串并返回 var scriptTag = function (content) { - return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT; + return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT; }; + // Create object with fake `null` prototype: use ActiveX Object with cleared prototype + // Function to create an object with a 'null' prototype using ActiveX in IE var NullProtoObjectViaActiveX = function (activeXDocument) { - activeXDocument.write(scriptTag('')); - activeXDocument.close(); - var temp = activeXDocument.parentWindow.Object; - activeXDocument = null; // avoid memory leak - return temp; + activeXDocument.write(scriptTag('')); // Write an empty script to ActiveX document + activeXDocument.close(); // Close the ActiveX document + var temp = activeXDocument.parentWindow.Object; // Get the Object from the parent window (from ActiveX) + activeXDocument = null; // Avoid memory leak + return temp; // Return the fake Object with a null prototype }; - // Create object with fake `null` prototype: use iframe Object with cleared prototype +// Function to create an object with a 'null' prototype using an iframe var NullProtoObjectViaIFrame = function () { - // Thrash, waste and sodomy: IE GC bug - var iframe = documentCreateElement('iframe'); - var JS = 'java' + SCRIPT + ':'; - var iframeDocument; - iframe.style.display = 'none'; - html.appendChild(iframe); - // https://github.com/zloirock/core-js/issues/475 - iframe.src = String(JS); - iframeDocument = iframe.contentWindow.document; - iframeDocument.open(); - iframeDocument.write(scriptTag('document.F=Object')); - iframeDocument.close(); - return iframeDocument.F; + // Thrash and waste method due to IE garbage collector bug + var iframe = documentCreateElement('iframe'); // Create an iframe element + var JS = 'java' + SCRIPT + ':'; // Create a script URL + var iframeDocument; + iframe.style.display = 'none'; // Hide the iframe + html.appendChild(iframe); // Append iframe to the HTML body + iframe.src = String(JS); // Set the source of the iframe to the script URL + iframeDocument = iframe.contentWindow.document; // Get the document inside the iframe + iframeDocument.open(); // Open the document + iframeDocument.write(scriptTag('document.F=Object')); // Write a script inside the iframe that sets `document.F` to Object + iframeDocument.close(); // Close the iframe document + return iframeDocument.F; // Return the Object with a null prototype }; - // Check for document.domain and active x support - // No need to use active x approach when document.domain is not set - // see https://github.com/es-shims/es5-shim/issues/150 - // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346 - // avoid IE GC bug +// Main function to create an object with a 'null' prototype var activeXDocument; var NullProtoObject = function () { - try { - /* global ActiveXObject */ - activeXDocument = document.domain && new ActiveXObject('htmlfile'); - } catch (error) { /* ignore */ } - NullProtoObject = activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : NullProtoObjectViaIFrame(); - var length = enumBugKeys.length; - while (length--) delete NullProtoObject[PROTOTYPE][enumBugKeys[length]]; - return NullProtoObject(); + try { + /* global ActiveXObject */ + activeXDocument = document.domain && new ActiveXObject('htmlfile'); // Check if ActiveX is available + } catch (error) { /* ignore */ } + // If ActiveX is supported, use the ActiveX approach, otherwise use iframe + NullProtoObject = activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : NullProtoObjectViaIFrame(); + var length = enumBugKeys.length; + while (length--) delete NullProtoObject[PROTOTYPE][enumBugKeys[length]]; // Delete enumerated bug keys + return NullProtoObject(); // Return the object created }; +// Mark hidden keys to avoid property name collisions in the prototype hiddenKeys[IE_PROTO] = true; - // `Object.create` method - // https://tc39.github.io/ecma262/#sec-object.create +// Polyfill for `Object.create` method var objectCreate = Object.create || function create(O, Properties) { - var result; - if (O !== null) { - EmptyConstructor[PROTOTYPE] = anObject(O); - result = new EmptyConstructor(); - EmptyConstructor[PROTOTYPE] = null; - // add "__proto__" for Object.getPrototypeOf polyfill - result[IE_PROTO] = O; - } else result = NullProtoObject(); - return Properties === undefined ? result : objectDefineProperties(result, Properties); + var result; + if (O !== null) { + EmptyConstructor[PROTOTYPE] = anObject(O); // Set the prototype of an empty constructor to O + result = new EmptyConstructor(); // Create a new instance of the empty constructor + EmptyConstructor[PROTOTYPE] = null; // Reset the prototype to null + result[IE_PROTO] = O; // Add the prototype reference to the created object for `Object.getPrototypeOf` + } else result = NullProtoObject(); // If O is null, use the NullProtoObject method + return Properties === undefined ? result : objectDefineProperties(result, Properties); // If Properties is defined, add them to the result object }; +// Native method to get the own property names of an object var nativeGetOwnPropertyNames = objectGetOwnPropertyNames.f; - var toString$1 = {}.toString; - +// Get the window names (properties) for a given object var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames - ? Object.getOwnPropertyNames(window) : []; + ? Object.getOwnPropertyNames(window) // If `Object.getOwnPropertyNames` is supported, use it + : []; +// Function to get the names of properties on a window object var getWindowNames = function (it) { - try { - return nativeGetOwnPropertyNames(it); - } catch (error) { - return windowNames.slice(); - } + try { + return nativeGetOwnPropertyNames(it); // Try to get the own property names + } catch (error) { + return windowNames.slice(); // If error occurs, return a copy of windowNames + } }; - // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window +// Fallback for buggy `Object.getOwnPropertyNames` in IE11 with iframe and window var f$5 = function getOwnPropertyNames(it) { - return windowNames && toString$1.call(it) == '[object Window]' - ? getWindowNames(it) - : nativeGetOwnPropertyNames(toIndexedObject(it)); + return windowNames && toString$1.call(it) == '[object Window]' + ? getWindowNames(it) // If the object is a window, use the getWindowNames function + : nativeGetOwnPropertyNames(toIndexedObject(it)); // Otherwise, use the native method }; +// Object for external use of `getOwnPropertyNames` method var objectGetOwnPropertyNamesExternal = { f: f$5 }; +// Store for Well-Known Symbols var WellKnownSymbolsStore = shared('wks'); var Symbol$1 = global_1.Symbol; - var createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : uid; + var createWellKnownSymbol = useSymbolAsUid ? Symbol$1 : uid; // Use Symbol as UID if supported +// Function to get or create a well-known symbol var wellKnownSymbol = function (name) { - if (!has(WellKnownSymbolsStore, name)) { - if (nativeSymbol && has(Symbol$1, name)) WellKnownSymbolsStore[name] = Symbol$1[name]; - else WellKnownSymbolsStore[name] = createWellKnownSymbol('Symbol.' + name); - } return WellKnownSymbolsStore[name]; + if (!has(WellKnownSymbolsStore, name)) { // If the symbol doesn't exist in the store + if (nativeSymbol && has(Symbol$1, name)) WellKnownSymbolsStore[name] = Symbol$1[name]; // Use the native Symbol if available + else WellKnownSymbolsStore[name] = createWellKnownSymbol('Symbol.' + name); // Otherwise, create a new one + } + return WellKnownSymbolsStore[name]; // Return the symbol from the store }; +// Wrapper for the well-known symbol function var f$6 = wellKnownSymbol; +// Define property for well-known symbols var wrappedWellKnownSymbol = { f: f$6 }; +// Define property method var defineProperty = objectDefineProperty.f; +// Function to define a well-known symbol on the global `Symbol` object var defineWellKnownSymbol = function (NAME) { - var Symbol = path.Symbol || (path.Symbol = {}); - if (!has(Symbol, NAME)) defineProperty(Symbol, NAME, { - value: wrappedWellKnownSymbol.f(NAME) - }); + var Symbol = path.Symbol || (path.Symbol = {}); // Get or create the global Symbol object + if (!has(Symbol, NAME)) defineProperty(Symbol, NAME, { // If the symbol is not defined + value: wrappedWellKnownSymbol.f(NAME) // Create and assign the symbol + }); }; +// Define property for symbols var defineProperty$1 = objectDefineProperty.f; - - +// Define the `toStringTag` symbol for setting the tag on objects var TO_STRING_TAG = wellKnownSymbol('toStringTag'); +// Set the `toStringTag` symbol on an object or prototype var setToStringTag = function (it, TAG, STATIC) { - if (it && !has(it = STATIC ? it : it.prototype, TO_STRING_TAG)) { - defineProperty$1(it, TO_STRING_TAG, { configurable: true, value: TAG }); - } + if (it && !has(it = STATIC ? it : it.prototype, TO_STRING_TAG)) { + defineProperty$1(it, TO_STRING_TAG, { configurable: true, value: TAG }); // Define the `toStringTag` property + } }; - +// 确保传入的参数是一个函数,如果不是则抛出 TypeError var aFunction$1 = function (it) { - if (typeof it != 'function') { - throw TypeError(String(it) + ' is not a function'); - } return it; + if (typeof it != 'function') { + throw TypeError(String(it) + ' 不是一个函数'); + } + return it; }; - // optional / simple context binding +// 可选的/简单的上下文绑定函数 var bindContext = function (fn, that, length) { - aFunction$1(fn); - if (that === undefined) return fn; - switch (length) { - case 0: return function () { - return fn.call(that); - }; - case 1: return function (a) { - return fn.call(that, a); - }; - case 2: return function (a, b) { - return fn.call(that, a, b); - }; - case 3: return function (a, b, c) { - return fn.call(that, a, b, c); - }; - } - return function (/* ...args */) { - return fn.apply(that, arguments); - }; + aFunction$1(fn); // 确保 fn 是一个函数 + if (that === undefined) return fn; // 如果没有传入上下文(that),直接返回原函数 + // 根据参数个数,返回一个绑定了上下文的函数 + switch (length) { + case 0: return function () { + return fn.call(that); // 调用时绑定上下文 + }; + case 1: return function (a) { + return fn.call(that, a); + }; + case 2: return function (a, b) { + return fn.call(that, a, b); + }; + case 3: return function (a, b, c) { + return fn.call(that, a, b, c); + }; + } + return function (/* ...args */) { + return fn.apply(that, arguments); // 对剩余的参数使用 apply 进行调用 + }; }; - var SPECIES = wellKnownSymbol('species'); + var SPECIES = wellKnownSymbol('species'); // 使用 wellKnownSymbol 获取 "species" 符号,用于数组的原生构造函数 - // `ArraySpeciesCreate` abstract operation - // https://tc39.github.io/ecma262/#sec-arrayspeciescreate +// `ArraySpeciesCreate` 抽象操作 +// https://tc39.github.io/ecma262/#sec-arrayspeciescreate var arraySpeciesCreate = function (originalArray, length) { - var C; - if (isArray(originalArray)) { - C = originalArray.constructor; - // cross-realm fallback - if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined; - else if (isObject(C)) { - C = C[SPECIES]; - if (C === null) C = undefined; - } - } return new (C === undefined ? Array : C)(length === 0 ? 0 : length); + var C; + if (isArray(originalArray)) { + C = originalArray.constructor; // 获取原数组的构造函数 + // 跨域处理 + if (typeof C == 'function' && (C === Array || isArray(C.prototype))) C = undefined; + else if (isObject(C)) { + C = C[SPECIES]; // 获取 `species` 属性 + if (C === null) C = undefined; + } + } + // 如果 C 为 undefined,使用默认的 Array 构造函数创建新数组 + return new (C === undefined ? Array : C)(length === 0 ? 0 : length); }; - var push = [].push; + var push = [].push; // 简单的数组 push 方法引用 - // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex }` methods implementation +// `Array.prototype.{ forEach, map, filter, some, every, find, findIndex }` 方法的实现 var createMethod$1 = function (TYPE) { - var IS_MAP = TYPE == 1; - var IS_FILTER = TYPE == 2; - var IS_SOME = TYPE == 3; - var IS_EVERY = TYPE == 4; - var IS_FIND_INDEX = TYPE == 6; - var NO_HOLES = TYPE == 5 || IS_FIND_INDEX; - return function ($this, callbackfn, that, specificCreate) { - var O = toObject($this); - var self = indexedObject(O); - var boundFunction = bindContext(callbackfn, that, 3); - var length = toLength(self.length); - var index = 0; - var create = specificCreate || arraySpeciesCreate; - var target = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined; - var value, result; - for (;length > index; index++) if (NO_HOLES || index in self) { - value = self[index]; - result = boundFunction(value, index, O); - if (TYPE) { - if (IS_MAP) target[index] = result; // map - else if (result) switch (TYPE) { - case 3: return true; // some - case 5: return value; // find - case 6: return index; // findIndex - case 2: push.call(target, value); // filter - } else if (IS_EVERY) return false; // every - } - } - return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target; - }; + // 判断类型,用于区分是 map, filter, some, every 等方法 + var IS_MAP = TYPE == 1; + var IS_FILTER = TYPE == 2; + var IS_SOME = TYPE == 3; + var IS_EVERY = TYPE == 4; + var IS_FIND_INDEX = TYPE == 6; + var NO_HOLES = TYPE == 5 || IS_FIND_INDEX; // 如果是 findIndex 或 filter,排除空洞 + return function ($this, callbackfn, that, specificCreate) { + var O = toObject($this); // 将目标对象转换为对象 + var self = indexedObject(O); // 获取目标对象的索引对象 + var boundFunction = bindContext(callbackfn, that, 3); // 绑定上下文 + var length = toLength(self.length); // 获取数组长度 + var index = 0; + var create = specificCreate || arraySpeciesCreate; // 使用具体的创建函数或默认的 arraySpeciesCreate + var target = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined; + var value, result; + // 遍历数组 + for (;length > index; index++) if (NO_HOLES || index in self) { + value = self[index]; + result = boundFunction(value, index, O); // 执行绑定的回调函数 + if (TYPE) { + if (IS_MAP) target[index] = result; // map 方法 + else if (result) switch (TYPE) { + case 3: return true; // some 方法 + case 5: return value; // find 方法 + case 6: return index; // findIndex 方法 + case 2: push.call(target, value); // filter 方法 + } else if (IS_EVERY) return false; // every 方法 + } + } + return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target; // 返回结果 + }; }; +// 定义一个包含多种数组操作方法的对象 var arrayIteration = { - // `Array.prototype.forEach` method - // https://tc39.github.io/ecma262/#sec-array.prototype.foreach - forEach: createMethod$1(0), - // `Array.prototype.map` method - // https://tc39.github.io/ecma262/#sec-array.prototype.map - map: createMethod$1(1), - // `Array.prototype.filter` method - // https://tc39.github.io/ecma262/#sec-array.prototype.filter - filter: createMethod$1(2), - // `Array.prototype.some` method - // https://tc39.github.io/ecma262/#sec-array.prototype.some - some: createMethod$1(3), - // `Array.prototype.every` method - // https://tc39.github.io/ecma262/#sec-array.prototype.every - every: createMethod$1(4), - // `Array.prototype.find` method - // https://tc39.github.io/ecma262/#sec-array.prototype.find - find: createMethod$1(5), - // `Array.prototype.findIndex` method - // https://tc39.github.io/ecma262/#sec-array.prototype.findIndex - findIndex: createMethod$1(6) + // `Array.prototype.forEach` 方法 + // https://tc39.github.io/ecma262/#sec-array.prototype.foreach + forEach: createMethod$1(0), + // `Array.prototype.map` 方法 + // https://tc39.github.io/ecma262/#sec-array.prototype.map + map: createMethod$1(1), + // `Array.prototype.filter` 方法 + // https://tc39.github.io/ecma262/#sec-array.prototype.filter + filter: createMethod$1(2), + // `Array.prototype.some` 方法 + // https://tc39.github.io/ecma262/#sec-array.prototype.some + some: createMethod$1(3), + // `Array.prototype.every` 方法 + // https://tc39.github.io/ecma262/#sec-array.prototype.every + every: createMethod$1(4), + // `Array.prototype.find` 方法 + // https://tc39.github.io/ecma262/#sec-array.prototype.find + find: createMethod$1(5), + // `Array.prototype.findIndex` 方法 + // https://tc39.github.io/ecma262/#sec-array.prototype.findIndex + findIndex: createMethod$1(6) }; - +// 引入 `arrayIteration.forEach` 方法,用于数组的遍历操作 var $forEach = arrayIteration.forEach; - var HIDDEN = sharedKey('hidden'); - var SYMBOL = 'Symbol'; - var PROTOTYPE$1 = 'prototype'; - var TO_PRIMITIVE = wellKnownSymbol('toPrimitive'); - var setInternalState = internalState.set; - var getInternalState = internalState.getterFor(SYMBOL); - var ObjectPrototype = Object[PROTOTYPE$1]; - var $Symbol = global_1.Symbol; - var $stringify = getBuiltIn('JSON', 'stringify'); - var nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f; - var nativeDefineProperty$1 = objectDefineProperty.f; - var nativeGetOwnPropertyNames$1 = objectGetOwnPropertyNamesExternal.f; - var nativePropertyIsEnumerable$1 = objectPropertyIsEnumerable.f; - var AllSymbols = shared('symbols'); - var ObjectPrototypeSymbols = shared('op-symbols'); - var StringToSymbolRegistry = shared('string-to-symbol-registry'); - var SymbolToStringRegistry = shared('symbol-to-string-registry'); - var WellKnownSymbolsStore$1 = shared('wks'); - var QObject = global_1.QObject; - // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173 +// 定义一些常量和符号 + var HIDDEN = sharedKey('hidden'); // 用于存储隐藏的符号 + var SYMBOL = 'Symbol'; // 符号常量 + var PROTOTYPE$1 = 'prototype'; // 原型常量 + var TO_PRIMITIVE = wellKnownSymbol('toPrimitive'); // 转换为原始值的符号 + var setInternalState = internalState.set; // 设置内部状态的方法 + var getInternalState = internalState.getterFor(SYMBOL); // 获取符号的内部状态的方法 + var ObjectPrototype = Object[PROTOTYPE$1]; // 获取 Object 的原型 + var $Symbol = global_1.Symbol; // 获取全局的 Symbol 对象 + var $stringify = getBuiltIn('JSON', 'stringify'); // 获取 JSON.stringify 方法 + var nativeGetOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f; // 获取对象的属性描述符 + var nativeDefineProperty$1 = objectDefineProperty.f; // 定义对象属性 + var nativeGetOwnPropertyNames$1 = objectGetOwnPropertyNamesExternal.f; // 获取对象的所有属性名 + var nativePropertyIsEnumerable$1 = objectPropertyIsEnumerable.f; // 判断对象的属性是否可枚举 + var AllSymbols = shared('symbols'); // 存储所有符号的共享对象 + var ObjectPrototypeSymbols = shared('op-symbols'); // 存储 Object.prototype 的符号 + var StringToSymbolRegistry = shared('string-to-symbol-registry'); // 字符串到符号的注册表 + var SymbolToStringRegistry = shared('symbol-to-string-registry'); // 符号到字符串的注册表 + var WellKnownSymbolsStore$1 = shared('wks'); // 存储知名符号的共享对象 + var QObject = global_1.QObject; // 获取 Qt 对象 + +// 针对 Qt Script 做的处理,避免使用 setter var USE_SETTER = !QObject || !QObject[PROTOTYPE$1] || !QObject[PROTOTYPE$1].findChild; - // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687 +// 针对旧版 Android 浏览器的回退处理 var setSymbolDescriptor = descriptors && fails(function () { - return objectCreate(nativeDefineProperty$1({}, 'a', { - get: function () { return nativeDefineProperty$1(this, 'a', { value: 7 }).a; } - })).a != 7; + return objectCreate(nativeDefineProperty$1({}, 'a', { + get: function () { return nativeDefineProperty$1(this, 'a', { value: 7 }).a; } + })).a != 7; }) ? function (O, P, Attributes) { - var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype, P); - if (ObjectPrototypeDescriptor) delete ObjectPrototype[P]; - nativeDefineProperty$1(O, P, Attributes); - if (ObjectPrototypeDescriptor && O !== ObjectPrototype) { - nativeDefineProperty$1(ObjectPrototype, P, ObjectPrototypeDescriptor); - } + var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$1(ObjectPrototype, P); + if (ObjectPrototypeDescriptor) delete ObjectPrototype[P]; + nativeDefineProperty$1(O, P, Attributes); + if (ObjectPrototypeDescriptor && O !== ObjectPrototype) { + nativeDefineProperty$1(ObjectPrototype, P, ObjectPrototypeDescriptor); + } } : nativeDefineProperty$1; +// 包装符号并设置内部状态 var wrap = function (tag, description) { - var symbol = AllSymbols[tag] = objectCreate($Symbol[PROTOTYPE$1]); - setInternalState(symbol, { - type: SYMBOL, - tag: tag, - description: description - }); - if (!descriptors) symbol.description = description; - return symbol; + var symbol = AllSymbols[tag] = objectCreate($Symbol[PROTOTYPE$1]); + setInternalState(symbol, { + type: SYMBOL, + tag: tag, + description: description + }); + if (!descriptors) symbol.description = description; // 如果没有 descriptors,则直接设置描述 + return symbol; }; +// 检查是否是符号类型 var isSymbol = nativeSymbol && typeof $Symbol.iterator == 'symbol' ? function (it) { - return typeof it == 'symbol'; + return typeof it == 'symbol'; // 如果原生支持 Symbol,则直接检查类型 } : function (it) { - return Object(it) instanceof $Symbol; + return Object(it) instanceof $Symbol; // 否则检查对象是否是 Symbol 的实例 }; +// 自定义 defineProperty 方法 var $defineProperty = function defineProperty(O, P, Attributes) { - if (O === ObjectPrototype) $defineProperty(ObjectPrototypeSymbols, P, Attributes); - anObject(O); - var key = toPrimitive(P, true); - anObject(Attributes); - if (has(AllSymbols, key)) { - if (!Attributes.enumerable) { - if (!has(O, HIDDEN)) nativeDefineProperty$1(O, HIDDEN, createPropertyDescriptor(1, {})); - O[HIDDEN][key] = true; - } else { - if (has(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false; - Attributes = objectCreate(Attributes, { enumerable: createPropertyDescriptor(0, false) }); - } return setSymbolDescriptor(O, key, Attributes); - } return nativeDefineProperty$1(O, key, Attributes); + if (O === ObjectPrototype) $defineProperty(ObjectPrototypeSymbols, P, Attributes); // 如果是 Object.prototype,则特殊处理 + anObject(O); // 确保 O 是一个对象 + var key = toPrimitive(P, true); // 将 P 转换为原始值 + anObject(Attributes); // 确保属性描述符是对象 + if (has(AllSymbols, key)) { // 如果属性是符号 + if (!Attributes.enumerable) { // 如果不可枚举 + if (!has(O, HIDDEN)) nativeDefineProperty$1(O, HIDDEN, createPropertyDescriptor(1, {})); // 确保对象有隐藏属性 + O[HIDDEN][key] = true; // 将符号标记为隐藏 + } else { + if (has(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false; // 如果是可枚举,移除隐藏标记 + Attributes = objectCreate(Attributes, { enumerable: createPropertyDescriptor(0, false) }); // 修改属性描述符,确保不可枚举 + } + return setSymbolDescriptor(O, key, Attributes); // 设置符号描述符 + } + return nativeDefineProperty$1(O, key, Attributes); // 否则使用原生 defineProperty 方法 }; +// 自定义 defineProperties 方法 var $defineProperties = function defineProperties(O, Properties) { - anObject(O); - var properties = toIndexedObject(Properties); - var keys = objectKeys(properties).concat($getOwnPropertySymbols(properties)); - $forEach(keys, function (key) { - if (!descriptors || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]); - }); - return O; + anObject(O); // 确保 O 是一个对象 + var properties = toIndexedObject(Properties); // 将 Properties 转换为索引对象 + var keys = objectKeys(properties).concat($getOwnPropertySymbols(properties)); // 获取属性键,包括符号 + $forEach(keys, function (key) { + if (!descriptors || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]); // 遍历键,定义属性 + }); + return O; }; +// 自定义 create 方法 var $create = function create(O, Properties) { - return Properties === undefined ? objectCreate(O) : $defineProperties(objectCreate(O), Properties); + return Properties === undefined ? objectCreate(O) : $defineProperties(objectCreate(O), Properties); // 如果没有 Properties 参数,直接创建一个对象,否则使用 defineProperties 定义属性 }; +// 自定义 propertyIsEnumerable 方法 var $propertyIsEnumerable = function propertyIsEnumerable(V) { - var P = toPrimitive(V, true); - var enumerable = nativePropertyIsEnumerable$1.call(this, P); - if (this === ObjectPrototype && has(AllSymbols, P) && !has(ObjectPrototypeSymbols, P)) return false; - return enumerable || !has(this, P) || !has(AllSymbols, P) || has(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true; + var P = toPrimitive(V, true); // 将 V 转换为原始值 + var enumerable = nativePropertyIsEnumerable$1.call(this, P); // 使用原生方法检查是否可枚举 + if (this === ObjectPrototype && has(AllSymbols, P) && !has(ObjectPrototypeSymbols, P)) return false; // 如果是 Object.prototype 并且符号不可枚举,则返回 false + return enumerable || !has(this, P) || !has(AllSymbols, P) || has(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true; // 返回最终结果 }; +// 自定义 getOwnPropertyDescriptor 方法 var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) { - var it = toIndexedObject(O); - var key = toPrimitive(P, true); - if (it === ObjectPrototype && has(AllSymbols, key) && !has(ObjectPrototypeSymbols, key)) return; - var descriptor = nativeGetOwnPropertyDescriptor$1(it, key); - if (descriptor && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key])) { - descriptor.enumerable = true; - } - return descriptor; + var it = toIndexedObject(O); // 将 O 转换为索引对象 + var key = toPrimitive(P, true); // 将 P 转换为原始值 + if (it === ObjectPrototype && has(AllSymbols, key) && !has(ObjectPrototypeSymbols, key)) return; // 如果是 Object.prototype 且符号不可枚举,则返回 undefined + var descriptor = nativeGetOwnPropertyDescriptor$1(it, key); // 获取属性描述符 + if (descriptor && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key])) { // 如果是符号并且不是隐藏的符号 + descriptor.enumerable = true; // 设置可枚举 + } + return descriptor; }; +// 自定义 getOwnPropertyNames 方法 var $getOwnPropertyNames = function getOwnPropertyNames(O) { - var names = nativeGetOwnPropertyNames$1(toIndexedObject(O)); - var result = []; - $forEach(names, function (key) { - if (!has(AllSymbols, key) && !has(hiddenKeys, key)) result.push(key); - }); - return result; + var names = nativeGetOwnPropertyNames$1(toIndexedObject(O)); // 获取对象的属性名 + var result = []; + $forEach(names, function (key) { + if (!has(AllSymbols, key) && !has(hiddenKeys, key)) result.push(key); // 如果不是符号且不在 hiddenKeys 中,加入结果数组 + }); + return result; }; +// 自定义 getOwnPropertySymbols 方法 var $getOwnPropertySymbols = function getOwnPropertySymbols(O) { - var IS_OBJECT_PROTOTYPE = O === ObjectPrototype; - var names = nativeGetOwnPropertyNames$1(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O)); - var result = []; - $forEach(names, function (key) { - if (has(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has(ObjectPrototype, key))) { - result.push(AllSymbols[key]); - } - }); - return result; + var IS_OBJECT_PROTOTYPE = O === ObjectPrototype; + var names = nativeGetOwnPropertyNames$1(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject(O)); // 获取对象的属性名 + var result = []; + $forEach(names, function (key) { + if (has(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has(ObjectPrototype, key))) { + result.push(AllSymbols[key]); // 如果是符号,加入结果数组 + } + }); + return result; }; // `Symbol` constructor // https://tc39.github.io/ecma262/#sec-symbol-constructor + // 如果浏览器原生不支持 Symbol(即 nativeSymbol 为 false) if (!nativeSymbol) { - $Symbol = function Symbol() { - if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor'); - var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]); - var tag = uid(description); - var setter = function (value) { - if (this === ObjectPrototype) setter.call(ObjectPrototypeSymbols, value); - if (has(this, HIDDEN) && has(this[HIDDEN], tag)) this[HIDDEN][tag] = false; - setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value)); - }; - if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype, tag, { configurable: true, set: setter }); - return wrap(tag, description); - }; - - redefine($Symbol[PROTOTYPE$1], 'toString', function toString() { - return getInternalState(this).tag; - }); - - objectPropertyIsEnumerable.f = $propertyIsEnumerable; - objectDefineProperty.f = $defineProperty; - objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor; - objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames; - objectGetOwnPropertySymbols.f = $getOwnPropertySymbols; - - if (descriptors) { - // https://github.com/tc39/proposal-Symbol-description - nativeDefineProperty$1($Symbol[PROTOTYPE$1], 'description', { - configurable: true, - get: function description() { - return getInternalState(this).description; - } - }); - { - redefine(ObjectPrototype, 'propertyIsEnumerable', $propertyIsEnumerable, { unsafe: true }); - } - } + // 定义 Symbol 构造函数 + $Symbol = function Symbol() { + if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor'); // 防止将 Symbol 当做构造函数使用 + var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]); // 如果没有传入描述,则设为 undefined + var tag = uid(description); // 生成唯一的标签(标识符) + var setter = function (value) { + if (this === ObjectPrototype) setter.call(ObjectPrototypeSymbols, value); // 如果是 Object.prototype,调用 ObjectPrototypeSymbols 的 setter + if (has(this, HIDDEN) && has(this[HIDDEN], tag)) this[HIDDEN][tag] = false; // 如果符号已经存在,标记为不可见 + setSymbolDescriptor(this, tag, createPropertyDescriptor(1, value)); // 设置符号的属性描述符 + }; + + if (descriptors && USE_SETTER) setSymbolDescriptor(ObjectPrototype, tag, { configurable: true, set: setter }); // 设置 setter 方法 + return wrap(tag, description); // 包装并返回符号 + }; + + // 为 Symbol.prototype 添加 toString 方法,返回符号的标签 + redefine($Symbol[PROTOTYPE$1], 'toString', function toString() { + return getInternalState(this).tag; + }); + + // 定义各种 Object 方法的符号实现 + objectPropertyIsEnumerable.f = $propertyIsEnumerable; + objectDefineProperty.f = $defineProperty; + objectGetOwnPropertyDescriptor.f = $getOwnPropertyDescriptor; + objectGetOwnPropertyNames.f = objectGetOwnPropertyNamesExternal.f = $getOwnPropertyNames; + objectGetOwnPropertySymbols.f = $getOwnPropertySymbols; + + if (descriptors) { + // 为 Symbol.prototype 添加 description 属性的 getter 方法 + nativeDefineProperty$1($Symbol[PROTOTYPE$1], 'description', { + configurable: true, + get: function description() { + return getInternalState(this).description; + } + }); + + // 为 Object.prototype 的 propertyIsEnumerable 方法添加符号支持 + { + redefine(ObjectPrototype, 'propertyIsEnumerable', $propertyIsEnumerable, { unsafe: true }); + } + } } +// 如果不使用 Symbol 作为唯一标识符(useSymbolAsUid 为 false),则创建 well-known 符号的包装器 if (!useSymbolAsUid) { - wrappedWellKnownSymbol.f = function (name) { - return wrap(wellKnownSymbol(name), name); - }; + wrappedWellKnownSymbol.f = function (name) { + return wrap(wellKnownSymbol(name), name); + }; } +// 导出 Symbol 构造函数,确保其全局可用 _export({ global: true, wrap: true, forced: !nativeSymbol, sham: !nativeSymbol }, { - Symbol: $Symbol + Symbol: $Symbol }); +// 遍历 WellKnownSymbolsStore$1 对象,定义每个知名符号 $forEach(objectKeys(WellKnownSymbolsStore$1), function (name) { - defineWellKnownSymbol(name); + defineWellKnownSymbol(name); }); +// 导出 `Symbol.for` 和 `Symbol.keyFor` 方法 _export({ target: SYMBOL, stat: true, forced: !nativeSymbol }, { - // `Symbol.for` method - // https://tc39.github.io/ecma262/#sec-symbol.for - 'for': function (key) { - var string = String(key); - if (has(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string]; - var symbol = $Symbol(string); - StringToSymbolRegistry[string] = symbol; - SymbolToStringRegistry[symbol] = string; - return symbol; - }, - // `Symbol.keyFor` method - // https://tc39.github.io/ecma262/#sec-symbol.keyfor - keyFor: function keyFor(sym) { - if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol'); - if (has(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym]; - }, - useSetter: function () { USE_SETTER = true; }, - useSimple: function () { USE_SETTER = false; } + // `Symbol.for` 方法:根据键查找或创建一个符号 + // https://tc39.github.io/ecma262/#sec-symbol.for + 'for': function (key) { + var string = String(key); // 将键转换为字符串 + if (has(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string]; // 如果注册表中已有此符号,则返回它 + var symbol = $Symbol(string); // 否则创建一个新符号 + StringToSymbolRegistry[string] = symbol; // 将符号添加到注册表 + SymbolToStringRegistry[symbol] = string; // 将符号映射到字符串 + return symbol; + }, + // `Symbol.keyFor` 方法:根据符号查找对应的键 + // https://tc39.github.io/ecma262/#sec-symbol.keyfor + keyFor: function keyFor(sym) { + if (!isSymbol(sym)) throw TypeError(sym + ' is not a symbol'); // 如果传入的不是符号,抛出错误 + if (has(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym]; // 如果符号存在于注册表中,返回其对应的键 + }, + useSetter: function () { USE_SETTER = true; }, // 设置 USE_SETTER 为 true + useSimple: function () { USE_SETTER = false; } // 设置 USE_SETTER 为 false }); +// 导出 Object 的符号支持方法 _export({ target: 'Object', stat: true, forced: !nativeSymbol, sham: !descriptors }, { - // `Object.create` method - // https://tc39.github.io/ecma262/#sec-object.create - create: $create, - // `Object.defineProperty` method - // https://tc39.github.io/ecma262/#sec-object.defineproperty - defineProperty: $defineProperty, - // `Object.defineProperties` method - // https://tc39.github.io/ecma262/#sec-object.defineproperties - defineProperties: $defineProperties, - // `Object.getOwnPropertyDescriptor` method - // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptors - getOwnPropertyDescriptor: $getOwnPropertyDescriptor + // `Object.create` 方法:使用符号创建对象 + // https://tc39.github.io/ecma262/#sec-object.create + create: $create, + // `Object.defineProperty` 方法:使用符号定义对象属性 + // https://tc39.github.io/ecma262/#sec-object.defineproperty + defineProperty: $defineProperty, + // `Object.defineProperties` 方法:使用符号定义多个对象属性 + // https://tc39.github.io/ecma262/#sec-object.defineproperties + defineProperties: $defineProperties, + // `Object.getOwnPropertyDescriptor` 方法:获取对象属性描述符 + // https://tc39.github.io/ecma262/#sec-object.getownpropertydescriptors + getOwnPropertyDescriptor: $getOwnPropertyDescriptor }); +// 导出 Object 的符号支持方法 _export({ target: 'Object', stat: true, forced: !nativeSymbol }, { - // `Object.getOwnPropertyNames` method - // https://tc39.github.io/ecma262/#sec-object.getownpropertynames - getOwnPropertyNames: $getOwnPropertyNames, - // `Object.getOwnPropertySymbols` method - // https://tc39.github.io/ecma262/#sec-object.getownpropertysymbols - getOwnPropertySymbols: $getOwnPropertySymbols + // `Object.getOwnPropertyNames` 方法:获取对象的属性名 + // https://tc39.github.io/ecma262/#sec-object.getownpropertynames + getOwnPropertyNames: $getOwnPropertyNames, + // `Object.getOwnPropertySymbols` 方法:获取对象的符号属性 + // https://tc39.github.io/ecma262/#sec-object.getownpropertysymbols + getOwnPropertySymbols: $getOwnPropertySymbols }); - // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives - // https://bugs.chromium.org/p/v8/issues/detail?id=3443 +// 解决 Chrome 38 和 39 中 `Object.getOwnPropertySymbols` 在原始值上的失败问题 +// https://bugs.chromium.org/p/v8/issues/detail?id=3443 _export({ target: 'Object', stat: true, forced: fails(function () { objectGetOwnPropertySymbols.f(1); }) }, { - getOwnPropertySymbols: function getOwnPropertySymbols(it) { - return objectGetOwnPropertySymbols.f(toObject(it)); - } + getOwnPropertySymbols: function getOwnPropertySymbols(it) { + return objectGetOwnPropertySymbols.f(toObject(it)); // 确保 it 是一个对象 + } }); - // `JSON.stringify` method behavior with symbols - // https://tc39.github.io/ecma262/#sec-json.stringify +// 处理 JSON.stringify 方法与符号的兼容性问题 +// https://tc39.github.io/ecma262/#sec-json.stringify if ($stringify) { - var FORCED_JSON_STRINGIFY = !nativeSymbol || fails(function () { - var symbol = $Symbol(); - // MS Edge converts symbol values to JSON as {} - return $stringify([symbol]) != '[null]' - // WebKit converts symbol values to JSON as null - || $stringify({ a: symbol }) != '{}' - // V8 throws on boxed symbols - || $stringify(Object(symbol)) != '{}'; - }); - - _export({ target: 'JSON', stat: true, forced: FORCED_JSON_STRINGIFY }, { - // eslint-disable-next-line no-unused-vars - stringify: function stringify(it, replacer, space) { - var args = [it]; - var index = 1; - var $replacer; - while (arguments.length > index) args.push(arguments[index++]); - $replacer = replacer; - if (!isObject(replacer) && it === undefined || isSymbol(it)) return; // IE8 returns string on undefined - if (!isArray(replacer)) replacer = function (key, value) { - if (typeof $replacer == 'function') value = $replacer.call(this, key, value); - if (!isSymbol(value)) return value; - }; - args[1] = replacer; - return $stringify.apply(null, args); - } - }); + var FORCED_JSON_STRINGIFY = !nativeSymbol || fails(function () { + var symbol = $Symbol(); + // 检查 MS Edge 和 WebKit 对符号的处理 + return $stringify([symbol]) != '[null]' // Edge 将符号值转换为 {} + || $stringify({ a: symbol }) != '{}' // WebKit 将符号值转换为 null + || $stringify(Object(symbol)) != '{}'; // V8 在符号被包装时抛出异常 + }); + + // 强制覆盖 `JSON.stringify` 方法 + _export({ target: 'JSON', stat: true, forced: FORCED_JSON_STRINGIFY }, { + stringify: function stringify(it, replacer, space) { + var args = [it]; + var index = 1; + var $replacer; + while (arguments.length > index) args.push(arguments[index++]); // 收集所有参数 + $replacer = replacer; + if (!isObject(replacer) && it === undefined || isSymbol(it)) return; // 如果是 undefined 或符号,则跳过 + if (!isArray(replacer)) replacer = function (key, value) { + if (typeof $replacer == 'function') value = $replacer.call(this, key, value); // 如果 replacer 是函数,调用它 + if (!isSymbol(value)) return value; // 如果值不是符号,则返回 + }; + args[1] = replacer; // 更新 replacer + return $stringify.apply(null, args); // 调用原始的 JSON.stringify 方法 + } + }); } - // `Symbol.prototype[@@toPrimitive]` method - // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@toprimitive +// 如果 Symbol.prototype 没有实现 `@@toPrimitive` 方法,则添加该方法 +// https://tc39.github.io/ecma262/#sec-symbol.prototype-@@toprimitive if (!$Symbol[PROTOTYPE$1][TO_PRIMITIVE]) { - createNonEnumerableProperty($Symbol[PROTOTYPE$1], TO_PRIMITIVE, $Symbol[PROTOTYPE$1].valueOf); + createNonEnumerableProperty($Symbol[PROTOTYPE$1], TO_PRIMITIVE, $Symbol[PROTOTYPE$1].valueOf); } - // `Symbol.prototype[@@toStringTag]` property - // https://tc39.github.io/ecma262/#sec-symbol.prototype-@@tostringtag + +// 设置 Symbol 类型的 toStringTag +// https://tc39.github.io/ecma262/#sec-symbol.prototype-@@tostringtag setToStringTag($Symbol, SYMBOL); +// 将 HIDDEN 属性添加到 hiddenKeys 中 hiddenKeys[HIDDEN] = true; +// 处理原生 Symbol 的描述符 var defineProperty$2 = objectDefineProperty.f; - +// 如果浏览器原生支持 Symbol,且存在描述符属性问题,则进行修复 var NativeSymbol = global_1.Symbol; - if (descriptors && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) || - // Safari 12 bug - NativeSymbol().description !== undefined + // Safari 12 bug + NativeSymbol().description !== undefined )) { - var EmptyStringDescriptionStore = {}; - // wrap Symbol constructor for correct work with undefined description - var SymbolWrapper = function Symbol() { - var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]); - var result = this instanceof SymbolWrapper - ? new NativeSymbol(description) - // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)' - : description === undefined ? NativeSymbol() : NativeSymbol(description); - if (description === '') EmptyStringDescriptionStore[result] = true; - return result; - }; - copyConstructorProperties(SymbolWrapper, NativeSymbol); - var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype; - symbolPrototype.constructor = SymbolWrapper; - - var symbolToString = symbolPrototype.toString; - var native = String(NativeSymbol('test')) == 'Symbol(test)'; - var regexp = /^Symbol\((.*)\)[^)]+$/; - defineProperty$2(symbolPrototype, 'description', { - configurable: true, - get: function description() { - var symbol = isObject(this) ? this.valueOf() : this; - var string = symbolToString.call(symbol); - if (has(EmptyStringDescriptionStore, symbol)) return ''; - var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1'); - return desc === '' ? undefined : desc; - } - }); - - _export({ global: true, forced: true }, { - Symbol: SymbolWrapper - }); + var EmptyStringDescriptionStore = {}; + // 包装原生 Symbol 构造函数,确保正确处理空字符串描述符 + var SymbolWrapper = function Symbol() { + var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]); + var result = this instanceof SymbolWrapper + ? new NativeSymbol(description) + : description === undefined ? NativeSymbol() : NativeSymbol(description); + if (description === '') EmptyStringDescriptionStore[result] = true; + return result; + }; + copyConstructorProperties(SymbolWrapper, NativeSymbol); + var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype; + symbolPrototype.constructor = SymbolWrapper; + + // 修复 Symbol.prototype 的 description 属性 + var symbolToString = symbolPrototype.toString; + var native = String(NativeSymbol('test')) == 'Symbol(test)'; + var regexp = /^Symbol\((.*)\)[^)]+$/; + defineProperty$2(symbolPrototype, 'description', { + configurable: true, + get: function description() { + var symbol = isObject(this) ? this.valueOf() : this; + var string = symbolToString.call(symbol); + if (has(EmptyStringDescriptionStore, symbol)) return ''; + var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1'); + return desc === '' ? undefined : desc; + } + }); + + _export({ global: true, forced: true }, { + Symbol: SymbolWrapper // 使用包装后的 Symbol + }); } + // `Symbol.iterator` well-known symbol // https://tc39.github.io/ecma262/#sec-symbol.iterator + // 定义一个知名符号 'iterator',表示可以用于迭代操作的符号 defineWellKnownSymbol('iterator'); +// 创建一个辅助函数,用于在对象上定义属性 var createProperty = function (object, key, value) { - var propertyKey = toPrimitive(key); - if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value)); - else object[propertyKey] = value; + var propertyKey = toPrimitive(key); // 将键转换为原始值 + if (propertyKey in object) objectDefineProperty.f(object, propertyKey, createPropertyDescriptor(0, value)); // 如果属性已经存在,使用 `Object.defineProperty` 设置属性描述符 + else object[propertyKey] = value; // 否则直接给对象添加属性 }; - var userAgent = getBuiltIn('navigator', 'userAgent') || ''; +// 获取浏览器的 userAgent,用于浏览器版本判断 + var userAgent = getBuiltIn('navigator', 'userAgent') || ''; // 获取浏览器的 userAgent 字符串 - var process = global_1.process; - var versions = process && process.versions; - var v8 = versions && versions.v8; + var process = global_1.process; // 获取 Node.js 环境的 process 对象 + var versions = process && process.versions; // 获取版本信息 + var v8 = versions && versions.v8; // 获取 V8 引擎的版本 var match, version; +// 检查 V8 引擎的版本,如果存在 v8 版本号,则提取并拼接出版本号 if (v8) { - match = v8.split('.'); - version = match[0] + match[1]; + match = v8.split('.'); // 将 v8 版本号拆分成数组 + version = match[0] + match[1]; // 拼接出一个版本号,例如 '60' 表示 v8 6.0 } else if (userAgent) { - match = userAgent.match(/Edge\/(\d+)/); - if (!match || match[1] >= 74) { - match = userAgent.match(/Chrome\/(\d+)/); - if (match) version = match[1]; - } + // 如果 V8 版本信息不存在,检查 userAgent 字符串中的浏览器信息 + match = userAgent.match(/Edge\/(\d+)/); // 匹配 Edge 浏览器的版本号 + if (!match || match[1] >= 74) { + match = userAgent.match(/Chrome\/(\d+)/); // 如果 Edge 版本低于 74,则匹配 Chrome 浏览器的版本号 + if (match) version = match[1]; // 提取 Chrome 的版本号 + } } +// 将版本号转换为数字 var v8Version = version && +version; +// 定义 `@@species` 符号,用于支持 ES6 中的 `species` 属性 var SPECIES$1 = wellKnownSymbol('species'); +// 检测数组方法是否支持 `species` 属性 var arrayMethodHasSpeciesSupport = function (METHOD_NAME) { - // We can't use this feature detection in V8 since it causes - // deoptimization and serious performance degradation - // https://github.com/zloirock/core-js/issues/677 - return v8Version >= 51 || !fails(function () { - var array = []; - var constructor = array.constructor = {}; - constructor[SPECIES$1] = function () { - return { foo: 1 }; - }; - return array[METHOD_NAME](Boolean).foo !== 1; - }); + // 在 V8 中,使用这种特性检测会导致性能问题,因此无法在 V8 中使用此检测 + // https://github.com/zloirock/core-js/issues/677 + return v8Version >= 51 || !fails(function () { + var array = []; + var constructor = array.constructor = {}; // 构造一个伪造的数组构造函数 + constructor[SPECIES$1] = function () { // 为数组的构造函数添加 species 属性 + return { foo: 1 }; + }; + return array[METHOD_NAME](Boolean).foo !== 1; // 检查 `concat` 方法是否能够正确使用 `species` + }); }; +// 定义 `@@isConcatSpreadable` 符号,用于支持 `Array.prototype.concat` 中的展开操作 var IS_CONCAT_SPREADABLE = wellKnownSymbol('isConcatSpreadable'); - var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF; - var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded'; + var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF; // JavaScript 中的最大安全整数值 + var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded'; // 超过最大索引值的错误信息 - // We can't use this feature detection in V8 since it causes - // deoptimization and serious performance degradation - // https://github.com/zloirock/core-js/issues/679 +// 检测 `@@isConcatSpreadable` 是否在当前环境中得到支持 var IS_CONCAT_SPREADABLE_SUPPORT = v8Version >= 51 || !fails(function () { - var array = []; - array[IS_CONCAT_SPREADABLE] = false; - return array.concat()[0] !== array; + var array = []; + array[IS_CONCAT_SPREADABLE] = false; // 给数组添加 isConcatSpreadable 属性 + return array.concat()[0] !== array; // 检查展开操作是否正确处理了 `isConcatSpreadable` }); +// 检测 `Array.prototype.concat` 方法是否支持 `@@species` 属性 var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('concat'); +// 检查一个对象是否是可展开的 var isConcatSpreadable = function (O) { - if (!isObject(O)) return false; - var spreadable = O[IS_CONCAT_SPREADABLE]; - return spreadable !== undefined ? !!spreadable : isArray(O); + if (!isObject(O)) return false; // 如果 O 不是对象,返回 false + var spreadable = O[IS_CONCAT_SPREADABLE]; // 获取对象的 isConcatSpreadable 属性 + return spreadable !== undefined ? !!spreadable : isArray(O); // 如果有 isConcatSpreadable 属性,则返回它的布尔值,否则判断它是否是数组 }; +// 强制标记需要修复的地方 var FORCED = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT; - // `Array.prototype.concat` method - // https://tc39.github.io/ecma262/#sec-array.prototype.concat - // with adding support of @@isConcatSpreadable and @@species +// 导出 Array.prototype.concat 方法,加入对 `@@isConcatSpreadable` 和 `@@species` 的支持 +// 规范文档:https://tc39.github.io/ecma262/#sec-array.prototype.concat _export({ target: 'Array', proto: true, forced: FORCED }, { - concat: function concat(arg) { // eslint-disable-line no-unused-vars - var O = toObject(this); - var A = arraySpeciesCreate(O, 0); - var n = 0; - var i, k, length, len, E; - for (i = -1, length = arguments.length; i < length; i++) { - E = i === -1 ? O : arguments[i]; - if (isConcatSpreadable(E)) { - len = toLength(E.length); - if (n + len > MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED); - for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]); - } else { - if (n >= MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED); - createProperty(A, n++, E); - } - } - A.length = n; - return A; - } + concat: function concat(arg) { // eslint-disable-line no-unused-vars + var O = toObject(this); // 将当前数组转换为对象 + var A = arraySpeciesCreate(O, 0); // 创建一个新数组 + var n = 0; // 初始化新数组的长度 + var i, k, length, len, E; + for (i = -1, length = arguments.length; i < length; i++) { + E = i === -1 ? O : arguments[i]; // 如果是第一个参数,使用当前数组 O + if (isConcatSpreadable(E)) { // 如果 E 是可展开的 + len = toLength(E.length); // 获取 E 的长度 + if (n + len > MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED); // 检查是否超过最大安全整数 + for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]); // 将 E 中的元素添加到新数组 A + } else { // 如果 E 不是可展开的 + if (n >= MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED); // 检查新数组长度是否超过最大安全整数 + createProperty(A, n++, E); // 直接将 E 添加到新数组 A + } + } + A.length = n; // 设置新数组的长度 + return A; // 返回新数组 + } }); +// 定义 `Array.prototype.filter` 方法的迭代器支持 var $filter = arrayIteration.filter; - - +// 检测 `Array.prototype.filter` 是否支持 `species` 属性 var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('filter'); - // Edge 14- issue + +// 在 Edge 14 中存在的问题 var USES_TO_LENGTH = HAS_SPECIES_SUPPORT && !fails(function () { - [].filter.call({ length: -1, 0: 1 }, function (it) { throw it; }); + [].filter.call({ length: -1, 0: 1 }, function (it) { throw it; }); // 检测当数组长度为负数时,filter 方法的行为 }); + // `Array.prototype.filter` method // https://tc39.github.io/ecma262/#sec-array.prototype.filter // with adding support of @@species + // 导出自定义的 `Array.prototype.filter` 方法,增加了 `callbackfn` 和 `thisArg` 参数 _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT || !USES_TO_LENGTH }, { - filter: function filter(callbackfn /* , thisArg */) { - return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); - } + filter: function filter(callbackfn /* , thisArg */) { + // 调用内置的 `$filter` 方法 + return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); + } }); +// 定义 `@@unscopables` 符号,用于处理与数组的“不可解构”操作相关的特性 var UNSCOPABLES = wellKnownSymbol('unscopables'); var ArrayPrototype = Array.prototype; - // Array.prototype[@@unscopables] - // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables +// `Array.prototype[@@unscopables]` - 将 `@@unscopables` 符号绑定到 `Array.prototype` +// 该符号用于指定哪些数组方法不可被解构(例如 `find`、`findIndex` 等) if (ArrayPrototype[UNSCOPABLES] == undefined) { - objectDefineProperty.f(ArrayPrototype, UNSCOPABLES, { - configurable: true, - value: objectCreate(null) - }); + objectDefineProperty.f(ArrayPrototype, UNSCOPABLES, { + configurable: true, + value: objectCreate(null) // 设置 `@@unscopables` 为一个空对象 + }); } - // add a key to Array.prototype[@@unscopables] +// 将指定的键添加到 `Array.prototype[@@unscopables]` 对象中 var addToUnscopables = function (key) { - ArrayPrototype[UNSCOPABLES][key] = true; + ArrayPrototype[UNSCOPABLES][key] = true; // 将 key 标记为不可解构 }; +// 定义 `find` 方法并导出,支持对数组的查找操作 var $find = arrayIteration.find; - - var FIND = 'find'; var SKIPS_HOLES = true; - // Shouldn't skip holes +// 检测 `find` 方法是否跳过数组中的“孔”(即空项) if (FIND in []) Array(1)[FIND](function () { SKIPS_HOLES = false; }); - // `Array.prototype.find` method - // https://tc39.github.io/ecma262/#sec-array.prototype.find +// 导出自定义的 `Array.prototype.find` 方法 _export({ target: 'Array', proto: true, forced: SKIPS_HOLES }, { - find: function find(callbackfn /* , that = undefined */) { - return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); - } + find: function find(callbackfn /* , that = undefined */) { + // 调用内置的 `$find` 方法 + return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); + } }); - // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables +// 将 `find` 方法添加到 `@@unscopables` 中,避免解构时被提取 addToUnscopables(FIND); +// 定义 `findIndex` 方法并导出,返回数组中符合条件元素的索引 var $findIndex = arrayIteration.findIndex; - - var FIND_INDEX = 'findIndex'; var SKIPS_HOLES$1 = true; - // Shouldn't skip holes +// 检测 `findIndex` 方法是否跳过数组中的“孔” if (FIND_INDEX in []) Array(1)[FIND_INDEX](function () { SKIPS_HOLES$1 = false; }); - // `Array.prototype.findIndex` method - // https://tc39.github.io/ecma262/#sec-array.prototype.findindex +// 导出自定义的 `Array.prototype.findIndex` 方法 _export({ target: 'Array', proto: true, forced: SKIPS_HOLES$1 }, { - findIndex: function findIndex(callbackfn /* , that = undefined */) { - return $findIndex(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); - } + findIndex: function findIndex(callbackfn /* , that = undefined */) { + // 调用内置的 `$findIndex` 方法 + return $findIndex(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); + } }); - // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables +// 将 `findIndex` 方法添加到 `@@unscopables` 中,避免解构时被提取 addToUnscopables(FIND_INDEX); +// 定义并导出 `Array.prototype.includes` 方法,用于检查元素是否在数组中 var $includes = arrayIncludes.includes; - - - // `Array.prototype.includes` method - // https://tc39.github.io/ecma262/#sec-array.prototype.includes _export({ target: 'Array', proto: true }, { - includes: function includes(el /* , fromIndex = 0 */) { - return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined); - } + includes: function includes(el /* , fromIndex = 0 */) { + // 调用内置的 `$includes` 方法 + return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined); + } }); - // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables +// 将 `includes` 方法添加到 `@@unscopables` 中,避免解构时被提取 addToUnscopables('includes'); +// 定义一个函数 `sloppyArrayMethod`,用于检查某个数组方法是否存在问题 var sloppyArrayMethod = function (METHOD_NAME, argument) { - var method = [][METHOD_NAME]; - return !method || !fails(function () { - // eslint-disable-next-line no-useless-call,no-throw-literal - method.call(null, argument || function () { throw 1; }, 1); - }); + var method = [][METHOD_NAME]; + return !method || !fails(function () { + // 测试方法是否正常工作 + method.call(null, argument || function () { throw 1; }, 1); + }); }; +// 定义并导出 `Array.prototype.indexOf` 方法,检查数组中是否包含某个元素 var $indexOf = arrayIncludes.indexOf; - - var nativeIndexOf = [].indexOf; - var NEGATIVE_ZERO = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0; - var SLOPPY_METHOD = sloppyArrayMethod('indexOf'); + var NEGATIVE_ZERO = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0; // 处理负零的情况 + var SLOPPY_METHOD = sloppyArrayMethod('indexOf'); // 检查 `indexOf` 是否存在问题 - // `Array.prototype.indexOf` method - // https://tc39.github.io/ecma262/#sec-array.prototype.indexof +// 导出自定义的 `Array.prototype.indexOf` 方法 _export({ target: 'Array', proto: true, forced: NEGATIVE_ZERO || SLOPPY_METHOD }, { - indexOf: function indexOf(searchElement /* , fromIndex = 0 */) { - return NEGATIVE_ZERO - // convert -0 to +0 - ? nativeIndexOf.apply(this, arguments) || 0 - : $indexOf(this, searchElement, arguments.length > 1 ? arguments[1] : undefined); - } + indexOf: function indexOf(searchElement /* , fromIndex = 0 */) { + return NEGATIVE_ZERO + // 处理负零,将 `-0` 转换为 `+0` + ? nativeIndexOf.apply(this, arguments) || 0 + : $indexOf(this, searchElement, arguments.length > 1 ? arguments[1] : undefined); + } }); +// 检查 `Object.getPrototypeOf` 是否正常工作 +// 该函数检测 `Object.getPrototypeOf` 是否能够正确返回对象的原型 var correctPrototypeGetter = !fails(function () { - function F() { /* empty */ } - F.prototype.constructor = null; - return Object.getPrototypeOf(new F()) !== F.prototype; + function F() { /* empty */ } + F.prototype.constructor = null; + // 如果 `Object.getPrototypeOf` 返回的原型不是传入对象的原型,则返回 false + return Object.getPrototypeOf(new F()) !== F.prototype; }); +// 定义 `IE_PROTO` 键,用于存储对象的原型信息 var IE_PROTO$1 = sharedKey('IE_PROTO'); var ObjectPrototype$1 = Object.prototype; - // `Object.getPrototypeOf` method - // https://tc39.github.io/ecma262/#sec-object.getprototypeof +// `Object.getPrototypeOf` 方法的兼容性处理 +// 该方法用于获取对象的原型,如果浏览器不支持该方法,则自定义实现 var objectGetPrototypeOf = correctPrototypeGetter ? Object.getPrototypeOf : function (O) { - O = toObject(O); - if (has(O, IE_PROTO$1)) return O[IE_PROTO$1]; - if (typeof O.constructor == 'function' && O instanceof O.constructor) { - return O.constructor.prototype; - } return O instanceof Object ? ObjectPrototype$1 : null; + O = toObject(O); // 确保传入的是对象 + if (has(O, IE_PROTO$1)) return O[IE_PROTO$1]; // 如果对象上有 `IE_PROTO`,则返回其值 + if (typeof O.constructor == 'function' && O instanceof O.constructor) { + return O.constructor.prototype; // 如果对象是构造函数的实例,返回构造函数的原型 + } + return O instanceof Object ? ObjectPrototype$1 : null; // 否则返回 `Object.prototype` }; +// 定义一个常量 `ITERATOR`,表示迭代器符号(`Symbol.iterator`) var ITERATOR = wellKnownSymbol('iterator'); - var BUGGY_SAFARI_ITERATORS = false; + var BUGGY_SAFARI_ITERATORS = false; // 用于检测 Safari 8 中的迭代器问题 +// 定义一个函数 `returnThis`,该函数用于返回当前对象 var returnThis = function () { return this; }; - // `%IteratorPrototype%` object - // https://tc39.github.io/ecma262/#sec-%iteratorprototype%-object +// 初始化 `IteratorPrototype` 和其他变量,用于兼容性处理 var IteratorPrototype, PrototypeOfArrayIteratorPrototype, arrayIterator; +// 检查当前环境是否支持数组迭代器,并处理 Safari 8 的特殊问题 if ([].keys) { - arrayIterator = [].keys(); - // Safari 8 has buggy iterators w/o `next` - if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true; - else { - PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator)); - if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype = PrototypeOfArrayIteratorPrototype; - } + arrayIterator = [].keys(); + // 检测 Safari 8 是否存在 bug:迭代器没有 `next` 方法 + if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS = true; + else { + // 获取数组迭代器原型的原型 + PrototypeOfArrayIteratorPrototype = objectGetPrototypeOf(objectGetPrototypeOf(arrayIterator)); + // 如果数组迭代器原型的原型不是 `Object.prototype`,则设置 `IteratorPrototype` + if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype = PrototypeOfArrayIteratorPrototype; + } } +// 如果 `IteratorPrototype` 仍然没有被设置,则将其初始化为空对象 if (IteratorPrototype == undefined) IteratorPrototype = {}; - // 25.1.2.1.1 %IteratorPrototype%[@@iterator]() - if ( !has(IteratorPrototype, ITERATOR)) { - createNonEnumerableProperty(IteratorPrototype, ITERATOR, returnThis); +// 25.1.2.1.1 `%IteratorPrototype%[@@iterator]()` +// 如果 `IteratorPrototype` 没有定义 `@@iterator`,则为其创建该方法 + if (!has(IteratorPrototype, ITERATOR)) { + createNonEnumerableProperty(IteratorPrototype, ITERATOR, returnThis); } +// 将 `IteratorPrototype` 和 `BUGGY_SAFARI_ITERATORS` 作为 `iteratorsCore` 的属性导出 var iteratorsCore = { - IteratorPrototype: IteratorPrototype, - BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS + IteratorPrototype: IteratorPrototype, + BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS }; +// 赋值 `IteratorPrototype$1` 为 `iteratorsCore.IteratorPrototype` var IteratorPrototype$1 = iteratorsCore.IteratorPrototype; +// 创建一个迭代器构造函数,用于构建迭代器对象 var createIteratorConstructor = function (IteratorConstructor, NAME, next) { - var TO_STRING_TAG = NAME + ' Iterator'; - IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, { next: createPropertyDescriptor(1, next) }); - setToStringTag(IteratorConstructor, TO_STRING_TAG, false); - return IteratorConstructor; + var TO_STRING_TAG = NAME + ' Iterator'; + // 设置迭代器的原型,并为其添加 `next` 方法 + IteratorConstructor.prototype = objectCreate(IteratorPrototype$1, { next: createPropertyDescriptor(1, next) }); + // 为迭代器设置 `toStringTag` 属性 + setToStringTag(IteratorConstructor, TO_STRING_TAG, false); + return IteratorConstructor; // 返回构造函数 }; +// 检查并确保可以将对象作为原型设置 var aPossiblePrototype = function (it) { - if (!isObject(it) && it !== null) { - throw TypeError("Can't set " + String(it) + ' as a prototype'); - } return it; + // 如果传入的对象不是一个有效的对象(或者是 `null`),则抛出错误 + if (!isObject(it) && it !== null) { + throw TypeError("Can't set " + String(it) + ' as a prototype'); + } + return it; // 返回对象本身 }; + // `Object.setPrototypeOf` method // https://tc39.github.io/ecma262/#sec-object.setprototypeof // Works with __proto__ only. Old v8 can't work with null proto objects. /* eslint-disable no-proto */ + // 兼容性处理:如果 `Object.setPrototypeOf` 不可用,则使用 `__proto__` 来设置对象原型 var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () { - var CORRECT_SETTER = false; - var test = {}; - var setter; - try { - setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set; - setter.call(test, []); - CORRECT_SETTER = test instanceof Array; - } catch (error) { /* empty */ } - return function setPrototypeOf(O, proto) { - anObject(O); - aPossiblePrototype(proto); - if (CORRECT_SETTER) setter.call(O, proto); - else O.__proto__ = proto; - return O; - }; + var CORRECT_SETTER = false; + var test = {}; + var setter; + try { + // 尝试获取原型的 setter,并验证它是否正确设置对象的原型 + setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set; + setter.call(test, []); // 设置对象的原型为数组 + CORRECT_SETTER = test instanceof Array; // 如果对象原型为数组,则认为 setter 正确 + } catch (error) { /* empty */ } + // 如果 setter 正确,则使用 setter 来设置原型,否则使用 `__proto__` + return function setPrototypeOf(O, proto) { + anObject(O); // 确保第一个参数是对象 + aPossiblePrototype(proto); // 确保 `proto` 是有效的原型 + if (CORRECT_SETTER) setter.call(O, proto); // 使用 setter 设置原型 + else O.__proto__ = proto; // 否则使用 `__proto__` + return O; + }; }() : undefined); +// 从 `iteratorsCore` 获取 `IteratorPrototype` 和 `BUGGY_SAFARI_ITERATORS` var IteratorPrototype$2 = iteratorsCore.IteratorPrototype; var BUGGY_SAFARI_ITERATORS$1 = iteratorsCore.BUGGY_SAFARI_ITERATORS; var ITERATOR$1 = wellKnownSymbol('iterator'); @@ -1433,54 +1728,67 @@ var VALUES = 'values'; var ENTRIES = 'entries'; +// 定义一个返回当前对象的函数 var returnThis$1 = function () { return this; }; +// 定义一个方法 `defineIterator`,用于构建一个迭代器 +// 该方法为迭代对象添加 `@@iterator`(或其他自定义的迭代器方法,如 `keys`, `values`, `entries`) +// 迭代器支持遍历对象的不同部分(键、值或条目),并且支持一些浏览器的兼容性修复 var defineIterator = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) { - createIteratorConstructor(IteratorConstructor, NAME, next); - - var getIterationMethod = function (KIND) { - if (KIND === DEFAULT && defaultIterator) return defaultIterator; - if (!BUGGY_SAFARI_ITERATORS$1 && KIND in IterablePrototype) return IterablePrototype[KIND]; - switch (KIND) { - case KEYS: return function keys() { return new IteratorConstructor(this, KIND); }; - case VALUES: return function values() { return new IteratorConstructor(this, KIND); }; - case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); }; - } return function () { return new IteratorConstructor(this); }; - }; - - var TO_STRING_TAG = NAME + ' Iterator'; - var INCORRECT_VALUES_NAME = false; - var IterablePrototype = Iterable.prototype; - var nativeIterator = IterablePrototype[ITERATOR$1] - || IterablePrototype['@@iterator'] - || DEFAULT && IterablePrototype[DEFAULT]; - var defaultIterator = !BUGGY_SAFARI_ITERATORS$1 && nativeIterator || getIterationMethod(DEFAULT); - var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator; - var CurrentIteratorPrototype, methods, KEY; - - // fix native - if (anyNativeIterator) { - CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable())); - if (IteratorPrototype$2 !== Object.prototype && CurrentIteratorPrototype.next) { - if ( objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype$2) { - if (objectSetPrototypeOf) { - objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype$2); - } else if (typeof CurrentIteratorPrototype[ITERATOR$1] != 'function') { - createNonEnumerableProperty(CurrentIteratorPrototype, ITERATOR$1, returnThis$1); - } - } - // Set @@toStringTag to native iterators - setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true); - } - } - - // fix Array#{values, @@iterator}.name in V8 / FF - if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) { - INCORRECT_VALUES_NAME = true; - defaultIterator = function values() { return nativeIterator.call(this); }; - } - - // define iterator + // 创建迭代器构造函数,并传入相关参数 + createIteratorConstructor(IteratorConstructor, NAME, next); + + // 获取相应的迭代方法:`keys`, `values`, `entries`,如果是默认方法,则使用 `defaultIterator` + var getIterationMethod = function (KIND) { + if (KIND === DEFAULT && defaultIterator) return defaultIterator; + if (!BUGGY_SAFARI_ITERATORS$1 && KIND in IterablePrototype) return IterablePrototype[KIND]; // 如果没有 Safari bug 且已有该方法,则直接返回 + // 根据不同的迭代类型,返回相应的迭代方法 + switch (KIND) { + case KEYS: return function keys() { return new IteratorConstructor(this, KIND); }; + case VALUES: return function values() { return new IteratorConstructor(this, KIND); }; + case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); }; + } + return function () { return new IteratorConstructor(this); }; // 默认返回构造函数 + }; + + var TO_STRING_TAG = NAME + ' Iterator'; // 迭代器的 `toStringTag` + var INCORRECT_VALUES_NAME = false; // 用于标记是否有不正确的 `values` 名称 + var IterablePrototype = Iterable.prototype; // 获取可迭代对象的原型 + var nativeIterator = IterablePrototype[ITERATOR$1] + || IterablePrototype['@@iterator'] // 优先选择 `@@iterator` 或原生迭代器 + || DEFAULT && IterablePrototype[DEFAULT]; // 如果有默认方法,则使用默认方法 + var defaultIterator = !BUGGY_SAFARI_ITERATORS$1 && nativeIterator || getIterationMethod(DEFAULT); // 选择合适的迭代方法 + var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator; // 针对不同类型(如数组)选择迭代方法 + var CurrentIteratorPrototype, methods, KEY; + + // 修复原生迭代器 + if (anyNativeIterator) { + // 获取原生迭代器的原型 + CurrentIteratorPrototype = objectGetPrototypeOf(anyNativeIterator.call(new Iterable())); + if (IteratorPrototype$2 !== Object.prototype && CurrentIteratorPrototype.next) { + // 如果原型链不匹配,并且 `next` 方法存在,则修正原型链 + if (objectGetPrototypeOf(CurrentIteratorPrototype) !== IteratorPrototype$2) { + if (objectSetPrototypeOf) { + objectSetPrototypeOf(CurrentIteratorPrototype, IteratorPrototype$2); // 设置原型 + } else if (typeof CurrentIteratorPrototype[ITERATOR$1] != 'function') { + createNonEnumerableProperty(CurrentIteratorPrototype, ITERATOR$1, returnThis$1); // 创建 `@@iterator` 方法 + } + } + // 为原生迭代器的原型添加 `toStringTag` + setToStringTag(CurrentIteratorPrototype, TO_STRING_TAG, true); + } + } + + // 修复数组的 `values` 方法名称(在 V8 和 Firefox 中可能不正确) + if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) { + INCORRECT_VALUES_NAME = true; // 标记名称不正确 + // 修复 `values` 方法名称 + defaultIterator = function values() { return nativeIterator.call(this); }; + } + + + + // define iterator if ( IterablePrototype[ITERATOR$1] !== defaultIterator) { createNonEnumerableProperty(IterablePrototype, ITERATOR$1, defaultIterator); } @@ -1516,683 +1824,732 @@ // https://tc39.github.io/ecma262/#sec-array.prototype-@@iterator // `CreateArrayIterator` internal method // https://tc39.github.io/ecma262/#sec-createarrayiterator + // 定义一个数组迭代器,支持 keys、values、entries 等方法 var es_array_iterator = defineIterator(Array, 'Array', function (iterated, kind) { - setInternalState$1(this, { - type: ARRAY_ITERATOR, - target: toIndexedObject(iterated), // target - index: 0, // next index - kind: kind // kind - }); - // `%ArrayIteratorPrototype%.next` method - // https://tc39.github.io/ecma262/#sec-%arrayiteratorprototype%.next + // 初始化迭代器的内部状态 + setInternalState$1(this, { + type: ARRAY_ITERATOR, + target: toIndexedObject(iterated), // 设置目标为迭代对象 + index: 0, // 起始索引 + kind: kind // 迭代类型:keys、values 或 entries + }); }, function () { - var state = getInternalState$1(this); - var target = state.target; - var kind = state.kind; - var index = state.index++; - if (!target || index >= target.length) { - state.target = undefined; - return { value: undefined, done: true }; - } - if (kind == 'keys') return { value: index, done: false }; - if (kind == 'values') return { value: target[index], done: false }; - return { value: [index, target[index]], done: false }; - }, 'values'); - - // https://tc39.github.io/ecma262/#sec-array.prototype-@@unscopables + // 迭代器的 `next` 方法,返回当前索引的元素 + var state = getInternalState$1(this); + var target = state.target; + var kind = state.kind; + var index = state.index++; // 增加索引 + if (!target || index >= target.length) { + state.target = undefined; // 如果已到末尾,返回结束信号 + return { value: undefined, done: true }; + } + // 根据 kind 返回不同类型的迭代结果 + if (kind == 'keys') return { value: index, done: false }; // 返回索引 + if (kind == 'values') return { value: target[index], done: false }; // 返回值 + return { value: [index, target[index]], done: false }; // 返回键值对 + }, 'values'); // 默认迭代返回值 + +// `@@unscopables` 标记,确保这些迭代器方法不会被 with 语句影响 addToUnscopables('keys'); addToUnscopables('values'); addToUnscopables('entries'); - var nativeJoin = [].join; +// `Array.prototype.join` 方法的实现 + var nativeJoin = [].join; // 获取原生的 `join` 方法 - var ES3_STRINGS = indexedObject != Object; +// 检查 ES3 字符串和 `join` 方法的兼容性 + var ES3_STRINGS = indexedObject != Object; // 判断 `indexedObject` 是否为 Object var SLOPPY_METHOD$1 = sloppyArrayMethod('join', ','); - // `Array.prototype.join` method - // https://tc39.github.io/ecma262/#sec-array.prototype.join +// 如果存在兼容性问题,强制使用 `join` 方法 _export({ target: 'Array', proto: true, forced: ES3_STRINGS || SLOPPY_METHOD$1 }, { - join: function join(separator) { - return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator); - } + join: function join(separator) { + return nativeJoin.call(toIndexedObject(this), separator === undefined ? ',' : separator); // 使用原生 `join` + } }); +// `Array.prototype.map` 方法的实现 var $map = arrayIteration.map; - - +// 检查 `map` 方法的兼容性,特别是 `@@species` 和 `toLength` 支持 var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport('map'); - // FF49- issue var USES_TO_LENGTH$1 = HAS_SPECIES_SUPPORT$1 && !fails(function () { - [].map.call({ length: -1, 0: 1 }, function (it) { throw it; }); + [].map.call({ length: -1, 0: 1 }, function (it) { throw it; }); // 测试数组的 `map` 方法 }); - // `Array.prototype.map` method - // https://tc39.github.io/ecma262/#sec-array.prototype.map - // with adding support of @@species +// 如果兼容性不支持,则强制使用自定义的 `map` 方法 _export({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$1 || !USES_TO_LENGTH$1 }, { - map: function map(callbackfn /* , thisArg */) { - return $map(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); - } + map: function map(callbackfn /* , thisArg */) { + return $map(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); // 使用 `map` 方法 + } }); +// `Array.prototype.reverse` 方法的实现 var nativeReverse = [].reverse; - var test = [1, 2]; + var test = [1, 2]; // 测试用的数组 - // `Array.prototype.reverse` method - // https://tc39.github.io/ecma262/#sec-array.prototype.reverse - // fix for Safari 12.0 bug - // https://bugs.webkit.org/show_bug.cgi?id=188794 +// 如果浏览器存在 bug,修复数组的 `reverse` 方法 _export({ target: 'Array', proto: true, forced: String(test) === String(test.reverse()) }, { - reverse: function reverse() { - // eslint-disable-next-line no-self-assign - if (isArray(this)) this.length = this.length; - return nativeReverse.call(this); - } + reverse: function reverse() { + // 修复 Safari 12.0 的 bug + if (isArray(this)) this.length = this.length; // 修复数组的长度属性 + return nativeReverse.call(this); // 调用原生 `reverse` + } }); - var SPECIES$2 = wellKnownSymbol('species'); +// `Array.prototype.slice` 方法的实现 + var SPECIES$2 = wellKnownSymbol('species'); // `species` 符号 var nativeSlice = [].slice; var max$1 = Math.max; - // `Array.prototype.slice` method - // https://tc39.github.io/ecma262/#sec-array.prototype.slice - // fallback for not array-like ES3 strings and DOM objects +// 如果不支持 `slice` 方法的 `species` 属性,则强制使用自定义实现 _export({ target: 'Array', proto: true, forced: !arrayMethodHasSpeciesSupport('slice') }, { - slice: function slice(start, end) { - var O = toIndexedObject(this); - var length = toLength(O.length); - var k = toAbsoluteIndex(start, length); - var fin = toAbsoluteIndex(end === undefined ? length : end, length); - // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible - var Constructor, result, n; - if (isArray(O)) { - Constructor = O.constructor; - // cross-realm fallback - if (typeof Constructor == 'function' && (Constructor === Array || isArray(Constructor.prototype))) { - Constructor = undefined; - } else if (isObject(Constructor)) { - Constructor = Constructor[SPECIES$2]; - if (Constructor === null) Constructor = undefined; - } - if (Constructor === Array || Constructor === undefined) { - return nativeSlice.call(O, k, fin); - } - } - result = new (Constructor === undefined ? Array : Constructor)(max$1(fin - k, 0)); - for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]); - result.length = n; - return result; - } + slice: function slice(start, end) { + var O = toIndexedObject(this); // 将 `this` 转换为索引对象 + var length = toLength(O.length); // 获取对象的长度 + var k = toAbsoluteIndex(start, length); // 计算起始索引 + var fin = toAbsoluteIndex(end === undefined ? length : end, length); // 计算结束索引 + var Constructor, result, n; + + // 检查对象是否为数组,如果是则使用原生的 `slice` 方法 + if (isArray(O)) { + Constructor = O.constructor; + // 如果构造函数不是数组或 `Array`,则使用 `Array` 作为默认构造函数 + if (typeof Constructor == 'function' && (Constructor === Array || isArray(Constructor.prototype))) { + Constructor = undefined; + } else if (isObject(Constructor)) { + Constructor = Constructor[SPECIES$2]; // 获取 `species` 属性 + if (Constructor === null) Constructor = undefined; + } + if (Constructor === Array || Constructor === undefined) { + return nativeSlice.call(O, k, fin); // 使用原生 `slice` 方法 + } + } + + // 否则创建新的数组并手动填充 + result = new (Constructor === undefined ? Array : Constructor)(max$1(fin - k, 0)); // 创建新数组 + for (n = 0; k < fin; k++, n++) if (k in O) createProperty(result, n, O[k]); // 手动复制元素 + result.length = n; // 设置数组长度 + return result; // 返回新数组 + } }); +// 处理 `Array.prototype.sort` 方法的兼容性 var test$1 = []; - var nativeSort = test$1.sort; + var nativeSort = test$1.sort; // 获取原生的 `sort` 方法 - // IE8- +// 检查 `sort` 方法是否能处理 `undefined` 和 `null` var FAILS_ON_UNDEFINED = fails(function () { - test$1.sort(undefined); + test$1.sort(undefined); // 检查 undefined 是否有效 }); - // V8 bug var FAILS_ON_NULL = fails(function () { - test$1.sort(null); + test$1.sort(null); // 检查 null 是否有效 }); - // Old WebKit + +// 检查旧版 WebKit(Safari)浏览器中 `sort` 方法的问题 var SLOPPY_METHOD$2 = sloppyArrayMethod('sort'); +// 如果 `sort` 方法存在已知的 bug,则强制使用兼容性修复 var FORCED$1 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || SLOPPY_METHOD$2; - // `Array.prototype.sort` method - // https://tc39.github.io/ecma262/#sec-array.prototype.sort +// `Array.prototype.sort` 方法的修复实现 _export({ target: 'Array', proto: true, forced: FORCED$1 }, { - sort: function sort(comparefn) { - return comparefn === undefined - ? nativeSort.call(toObject(this)) - : nativeSort.call(toObject(this), aFunction$1(comparefn)); - } + sort: function sort(comparefn) { + // 如果没有提供比较函数,使用原生的 `sort` + return comparefn === undefined + ? nativeSort.call(toObject(this)) + // 否则调用提供的比较函数 + : nativeSort.call(toObject(this), aFunction$1(comparefn)); + } }); +// 处理 `Array.prototype.splice` 方法的兼容性 var max$2 = Math.max; var min$2 = Math.min; var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF; var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded'; - // `Array.prototype.splice` method - // https://tc39.github.io/ecma262/#sec-array.prototype.splice - // with adding support of @@species +// `Array.prototype.splice` 方法的修复实现 _export({ target: 'Array', proto: true, forced: !arrayMethodHasSpeciesSupport('splice') }, { - splice: function splice(start, deleteCount /* , ...items */) { - var O = toObject(this); - var len = toLength(O.length); - var actualStart = toAbsoluteIndex(start, len); - var argumentsLength = arguments.length; - var insertCount, actualDeleteCount, A, k, from, to; - if (argumentsLength === 0) { - insertCount = actualDeleteCount = 0; - } else if (argumentsLength === 1) { - insertCount = 0; - actualDeleteCount = len - actualStart; - } else { - insertCount = argumentsLength - 2; - actualDeleteCount = min$2(max$2(toInteger(deleteCount), 0), len - actualStart); - } - if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER$1) { - throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED); - } - A = arraySpeciesCreate(O, actualDeleteCount); - for (k = 0; k < actualDeleteCount; k++) { - from = actualStart + k; - if (from in O) createProperty(A, k, O[from]); - } - A.length = actualDeleteCount; - if (insertCount < actualDeleteCount) { - for (k = actualStart; k < len - actualDeleteCount; k++) { - from = k + actualDeleteCount; - to = k + insertCount; - if (from in O) O[to] = O[from]; - else delete O[to]; - } - for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1]; - } else if (insertCount > actualDeleteCount) { - for (k = len - actualDeleteCount; k > actualStart; k--) { - from = k + actualDeleteCount - 1; - to = k + insertCount - 1; - if (from in O) O[to] = O[from]; - else delete O[to]; - } - } - for (k = 0; k < insertCount; k++) { - O[k + actualStart] = arguments[k + 2]; - } - O.length = len - actualDeleteCount + insertCount; - return A; - } + splice: function splice(start, deleteCount /* , ...items */) { + var O = toObject(this); + var len = toLength(O.length); // 获取数组长度 + var actualStart = toAbsoluteIndex(start, len); // 计算实际的起始索引 + var argumentsLength = arguments.length; + var insertCount, actualDeleteCount, A, k, from, to; + + // 计算插入项的数量和删除项的数量 + if (argumentsLength === 0) { + insertCount = actualDeleteCount = 0; + } else if (argumentsLength === 1) { + insertCount = 0; + actualDeleteCount = len - actualStart; + } else { + insertCount = argumentsLength - 2; + actualDeleteCount = min$2(max$2(toInteger(deleteCount), 0), len - actualStart); + } + + // 检查操作是否超过最大安全整数长度 + if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER$1) { + throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED); + } + + // 创建一个新数组用于存放删除的元素 + A = arraySpeciesCreate(O, actualDeleteCount); + for (k = 0; k < actualDeleteCount; k++) { + from = actualStart + k; + if (from in O) createProperty(A, k, O[from]); // 复制删除的元素 + } + A.length = actualDeleteCount; + + // 如果删除的元素比插入的元素多,移动剩余元素 + if (insertCount < actualDeleteCount) { + for (k = actualStart; k < len - actualDeleteCount; k++) { + from = k + actualDeleteCount; + to = k + insertCount; + if (from in O) O[to] = O[from]; + else delete O[to]; + } + for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1]; + } + // 如果插入的元素比删除的元素多,移动剩余元素 + else if (insertCount > actualDeleteCount) { + for (k = len - actualDeleteCount; k > actualStart; k--) { + from = k + actualDeleteCount - 1; + to = k + insertCount - 1; + if (from in O) O[to] = O[from]; + else delete O[to]; + } + } + + // 将新的元素插入到数组中 + for (k = 0; k < insertCount; k++) { + O[k + actualStart] = arguments[k + 2]; + } + + // 更新数组的长度 + O.length = len - actualDeleteCount + insertCount; + return A; // 返回删除的元素 + } }); - // makes subclassing work correct for wrapped built-ins +// 用于修复和继承子类行为的辅助函数 var inheritIfRequired = function ($this, dummy, Wrapper) { - var NewTarget, NewTargetPrototype; - if ( - // it can work only with native `setPrototypeOf` - objectSetPrototypeOf && - // we haven't completely correct pre-ES6 way for getting `new.target`, so use this - typeof (NewTarget = dummy.constructor) == 'function' && - NewTarget !== Wrapper && - isObject(NewTargetPrototype = NewTarget.prototype) && - NewTargetPrototype !== Wrapper.prototype - ) objectSetPrototypeOf($this, NewTargetPrototype); - return $this; + var NewTarget, NewTargetPrototype; + if ( + // 使用原生的 `setPrototypeOf` 方法进行继承 + objectSetPrototypeOf && + // 检查是否可以正确获取 `new.target` + typeof (NewTarget = dummy.constructor) == 'function' && + NewTarget !== Wrapper && + isObject(NewTargetPrototype = NewTarget.prototype) && + NewTargetPrototype !== Wrapper.prototype + ) objectSetPrototypeOf($this, NewTargetPrototype); // 将子类的原型设置为目标原型 + return $this; }; - // a string of all valid unicode whitespaces - // eslint-disable-next-line max-len +// 定义一个包含所有有效 Unicode 空白字符的字符串 var whitespaces = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF'; +// 用正则表达式去掉字符串两端的空白字符 var whitespace = '[' + whitespaces + ']'; var ltrim = RegExp('^' + whitespace + whitespace + '*'); var rtrim = RegExp(whitespace + whitespace + '*$'); - // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation +// `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` 方法的实现 var createMethod$2 = function (TYPE) { - return function ($this) { - var string = String(requireObjectCoercible($this)); - if (TYPE & 1) string = string.replace(ltrim, ''); - if (TYPE & 2) string = string.replace(rtrim, ''); - return string; - }; + return function ($this) { + var string = String(requireObjectCoercible($this)); // 强制转换为字符串 + if (TYPE & 1) string = string.replace(ltrim, ''); // 去掉开头的空白字符 + if (TYPE & 2) string = string.replace(rtrim, ''); // 去掉结尾的空白字符 + return string; // 返回处理后的字符串 + }; }; +// `stringTrim` 对象包含了修复后的 `trim` 方法 var stringTrim = { - // `String.prototype.{ trimLeft, trimStart }` methods - // https://tc39.github.io/ecma262/#sec-string.prototype.trimstart - start: createMethod$2(1), - // `String.prototype.{ trimRight, trimEnd }` methods - // https://tc39.github.io/ecma262/#sec-string.prototype.trimend - end: createMethod$2(2), - // `String.prototype.trim` method - // https://tc39.github.io/ecma262/#sec-string.prototype.trim - trim: createMethod$2(3) + // `String.prototype.{ trimLeft, trimStart }` 方法 + start: createMethod$2(1), + // `String.prototype.{ trimRight, trimEnd }` 方法 + end: createMethod$2(2), + // `String.prototype.trim` 方法 + trim: createMethod$2(3) }; +// 获取 `Object` 和 `String` 的相关方法 var getOwnPropertyNames = objectGetOwnPropertyNames.f; var getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f; var defineProperty$3 = objectDefineProperty.f; var trim = stringTrim.trim; +// 定义 `Number` 构造函数相关的变量 var NUMBER = 'Number'; - var NativeNumber = global_1[NUMBER]; + var NativeNumber = global_1[NUMBER]; // 获取全局的原生 `Number` var NumberPrototype = NativeNumber.prototype; - // Opera ~12 has broken Object#toString +// Opera 12 和更早版本存在 `Object#toString` 的问题 var BROKEN_CLASSOF = classofRaw(objectCreate(NumberPrototype)) == NUMBER; - // `ToNumber` abstract operation - // https://tc39.github.io/ecma262/#sec-tonumber +// `ToNumber` 抽象操作:将传入的参数转换为数字 var toNumber = function (argument) { - var it = toPrimitive(argument, false); - var first, third, radix, maxCode, digits, length, index, code; - if (typeof it == 'string' && it.length > 2) { - it = trim(it); - first = it.charCodeAt(0); - if (first === 43 || first === 45) { - third = it.charCodeAt(2); - if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix - } else if (first === 48) { - switch (it.charCodeAt(1)) { - case 66: case 98: radix = 2; maxCode = 49; break; // fast equal of /^0b[01]+$/i - case 79: case 111: radix = 8; maxCode = 55; break; // fast equal of /^0o[0-7]+$/i - default: return +it; - } - digits = it.slice(2); - length = digits.length; - for (index = 0; index < length; index++) { - code = digits.charCodeAt(index); - // parseInt parses a string to a first unavailable symbol - // but ToNumber should return NaN if a string contains unavailable symbols - if (code < 48 || code > maxCode) return NaN; - } return parseInt(digits, radix); - } - } return +it; + var it = toPrimitive(argument, false); // 获取参数的原始值 + var first, third, radix, maxCode, digits, length, index, code; + if (typeof it == 'string' && it.length > 2) { + it = trim(it); // 去掉字符串的前后空格 + first = it.charCodeAt(0); + if (first === 43 || first === 45) { // 如果是正负号 + third = it.charCodeAt(2); + if (third === 88 || third === 120) return NaN; // 十六进制数字应该返回 NaN + } else if (first === 48) { // 如果是以0开头的数字 + switch (it.charCodeAt(1)) { + case 66: case 98: radix = 2; maxCode = 49; break; // 二进制 + case 79: case 111: radix = 8; maxCode = 55; break; // 八进制 + default: return +it; // 其他情况转换为数字 + } + digits = it.slice(2); // 去掉前缀部分 + length = digits.length; + for (index = 0; index < length; index++) { + code = digits.charCodeAt(index); + // 如果数字中含有非法字符,返回 NaN + if (code < 48 || code > maxCode) return NaN; + } + return parseInt(digits, radix); // 根据进制解析数字 + } + } + return +it; // 返回数字 }; - // `Number` constructor - // https://tc39.github.io/ecma262/#sec-number-constructor +// 检查 `Number` 构造函数的兼容性 if (isForced_1(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) { - var NumberWrapper = function Number(value) { - var it = arguments.length < 1 ? 0 : value; - var dummy = this; - return dummy instanceof NumberWrapper - // check on 1..constructor(foo) case - && (BROKEN_CLASSOF ? fails(function () { NumberPrototype.valueOf.call(dummy); }) : classofRaw(dummy) != NUMBER) - ? inheritIfRequired(new NativeNumber(toNumber(it)), dummy, NumberWrapper) : toNumber(it); - }; - for (var keys$1 = descriptors ? getOwnPropertyNames(NativeNumber) : ( - // ES3: - 'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' + - // ES2015 (in case, if modules with ES2015 Number statics required before): - 'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' + - 'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger' - ).split(','), j = 0, key; keys$1.length > j; j++) { - if (has(NativeNumber, key = keys$1[j]) && !has(NumberWrapper, key)) { - defineProperty$3(NumberWrapper, key, getOwnPropertyDescriptor$2(NativeNumber, key)); - } - } - NumberWrapper.prototype = NumberPrototype; - NumberPrototype.constructor = NumberWrapper; - redefine(global_1, NUMBER, NumberWrapper); + var NumberWrapper = function Number(value) { + var it = arguments.length < 1 ? 0 : value; + var dummy = this; + return dummy instanceof NumberWrapper + // 检查构造函数中的问题 + && (BROKEN_CLASSOF ? fails(function () { NumberPrototype.valueOf.call(dummy); }) : classofRaw(dummy) != NUMBER) + ? inheritIfRequired(new NativeNumber(toNumber(it)), dummy, NumberWrapper) : toNumber(it); + }; + + // 复制原生 `Number` 的属性到 `NumberWrapper` + for (var keys$1 = descriptors ? getOwnPropertyNames(NativeNumber) : ( + 'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' + + 'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' + + 'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger' + ).split(','), j = 0, key; keys$1.length > j; j++) { + if (has(NativeNumber, key = keys$1[j]) && !has(NumberWrapper, key)) { + defineProperty$3(NumberWrapper, key, getOwnPropertyDescriptor$2(NativeNumber, key)); + } + } + NumberWrapper.prototype = NumberPrototype; + NumberPrototype.constructor = NumberWrapper; + redefine(global_1, NUMBER, NumberWrapper); } +// 检查和修复 `Object.assign` 方法的兼容性 var nativeAssign = Object.assign; var defineProperty$4 = Object.defineProperty; - // `Object.assign` method - // https://tc39.github.io/ecma262/#sec-object.assign var objectAssign = !nativeAssign || fails(function () { - // should have correct order of operations (Edge bug) - if (descriptors && nativeAssign({ b: 1 }, nativeAssign(defineProperty$4({}, 'a', { - enumerable: true, - get: function () { - defineProperty$4(this, 'b', { - value: 3, - enumerable: false - }); - } - }), { b: 2 })).b !== 1) return true; - // should work with symbols and should have deterministic property order (V8 bug) - var A = {}; - var B = {}; - // eslint-disable-next-line no-undef - var symbol = Symbol(); - var alphabet = 'abcdefghijklmnopqrst'; - A[symbol] = 7; - alphabet.split('').forEach(function (chr) { B[chr] = chr; }); - return nativeAssign({}, A)[symbol] != 7 || objectKeys(nativeAssign({}, B)).join('') != alphabet; + // 检查 Edge 浏览器的 bug,确保正确的操作顺序 + if (descriptors && nativeAssign({ b: 1 }, nativeAssign(defineProperty$4({}, 'a', { + enumerable: true, + get: function () { + defineProperty$4(this, 'b', { + value: 3, + enumerable: false + }); + } + }), { b: 2 })).b !== 1) return true; + // 检查 V8 的 bug,确保与符号兼容,并且有确定的属性顺序 + var A = {}; + var B = {}; + var symbol = Symbol(); + var alphabet = 'abcdefghijklmnopqrst'; + A[symbol] = 7; + alphabet.split('').forEach(function (chr) { B[chr] = chr; }); + return nativeAssign({}, A)[symbol] != 7 || objectKeys(nativeAssign({}, B)).join('') != alphabet; }) ? function assign(target, source) { // eslint-disable-line no-unused-vars - var T = toObject(target); - var argumentsLength = arguments.length; - var index = 1; - var getOwnPropertySymbols = objectGetOwnPropertySymbols.f; - var propertyIsEnumerable = objectPropertyIsEnumerable.f; - while (argumentsLength > index) { - var S = indexedObject(arguments[index++]); - var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S); - var length = keys.length; - var j = 0; - var key; - while (length > j) { - key = keys[j++]; - if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key]; - } - } return T; + var T = toObject(target); // 确保目标是对象 + var argumentsLength = arguments.length; + var index = 1; + var getOwnPropertySymbols = objectGetOwnPropertySymbols.f; + var propertyIsEnumerable = objectPropertyIsEnumerable.f; + while (argumentsLength > index) { + var S = indexedObject(arguments[index++]); + var keys = getOwnPropertySymbols ? objectKeys(S).concat(getOwnPropertySymbols(S)) : objectKeys(S); + var length = keys.length; + var j = 0; + var key; + while (length > j) { + key = keys[j++]; + if (!descriptors || propertyIsEnumerable.call(S, key)) T[key] = S[key]; + } + } + return T; // 返回合并后的对象 } : nativeAssign; - // `Object.assign` method - // https://tc39.github.io/ecma262/#sec-object.assign +// `Object.assign` 方法的修复实现 _export({ target: 'Object', stat: true, forced: Object.assign !== objectAssign }, { - assign: objectAssign + assign: objectAssign }); +// `Object.{ entries, values }` 方法的实现 var propertyIsEnumerable = objectPropertyIsEnumerable.f; - // `Object.{ entries, values }` methods implementation var createMethod$3 = function (TO_ENTRIES) { - return function (it) { - var O = toIndexedObject(it); - var keys = objectKeys(O); - var length = keys.length; - var i = 0; - var result = []; - var key; - while (length > i) { - key = keys[i++]; - if (!descriptors || propertyIsEnumerable.call(O, key)) { - result.push(TO_ENTRIES ? [key, O[key]] : O[key]); - } - } - return result; - }; + return function (it) { + var O = toIndexedObject(it); // 转换为索引对象 + var keys = objectKeys(O); // 获取对象的键 + var length = keys.length; + var i = 0; + var result = []; + var key; + while (length > i) { + key = keys[i++]; // 获取每个键 + if (!descriptors || propertyIsEnumerable.call(O, key)) { + result.push(TO_ENTRIES ? [key, O[key]] : O[key]); // 如果是 `entries`,则返回键值对,否则返回值 + } + } + return result; // 返回结果 + }; }; - var objectToArray = { - // `Object.entries` method - // https://tc39.github.io/ecma262/#sec-object.entries - entries: createMethod$3(true), - // `Object.values` method - // https://tc39.github.io/ecma262/#sec-object.values - values: createMethod$3(false) + // `Object.entries` 方法:返回对象自身可枚举属性的键值对数组 + // https://tc39.github.io/ecma262/#sec-object.entries + entries: createMethod$3(true), + + // `Object.values` 方法:返回对象自身可枚举属性的值数组 + // https://tc39.github.io/ecma262/#sec-object.values + values: createMethod$3(false) }; +// 引入 `Object.entries` 方法 var $entries = objectToArray.entries; - // `Object.entries` method - // https://tc39.github.io/ecma262/#sec-object.entries +// 定义 `Object.entries` 方法 +// https://tc39.github.io/ecma262/#sec-object.entries _export({ target: 'Object', stat: true }, { - entries: function entries(O) { - return $entries(O); - } + entries: function entries(O) { + return $entries(O); // 调用 `createMethod$3` 生成的 `entries` 方法 + } }); var TO_STRING_TAG$1 = wellKnownSymbol('toStringTag'); var test$2 = {}; +// 设置 `toStringTag` 属性用于检测 test$2[TO_STRING_TAG$1] = 'z'; +// 检测 `toStringTag` 的支持情况 var toStringTagSupport = String(test$2) === '[object z]'; +// 继续定义 `toStringTag` 用于类型检测 var TO_STRING_TAG$2 = wellKnownSymbol('toStringTag'); - // ES3 wrong here + +// ES3 错误的实现:`Arguments` 类型检测 var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments'; - // fallback for IE11 Script Access Denied error +// `tryGet` 函数:捕获访问属性时可能的错误,避免崩溃 var tryGet = function (it, key) { - try { - return it[key]; - } catch (error) { /* empty */ } + try { + return it[key]; + } catch (error) { /* 空处理 */ } }; - // getting tag from ES6+ `Object.prototype.toString` +// 根据 `toStringTag` 获取对象类型 var classof = toStringTagSupport ? classofRaw : function (it) { - var O, tag, result; - return it === undefined ? 'Undefined' : it === null ? 'Null' - // @@toStringTag case - : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$2)) == 'string' ? tag - // builtinTag case - : CORRECT_ARGUMENTS ? classofRaw(O) - // ES3 arguments fallback - : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result; + var O, tag, result; + return it === undefined ? 'Undefined' : it === null ? 'Null' + // @@toStringTag 类型 + : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$2)) == 'string' ? tag + // 原生类型 + : CORRECT_ARGUMENTS ? classofRaw(O) + // 处理 ES3 中的 `arguments` 对象 + : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result; }; - // `Object.prototype.toString` method implementation - // https://tc39.github.io/ecma262/#sec-object.prototype.tostring +// `Object.prototype.toString` 方法实现 +// https://tc39.github.io/ecma262/#sec-object.prototype.tostring var objectToString = toStringTagSupport ? {}.toString : function toString() { - return '[object ' + classof(this) + ']'; + return '[object ' + classof(this) + ']'; // 返回带有类型标签的字符串 }; - // `Object.prototype.toString` method - // https://tc39.github.io/ecma262/#sec-object.prototype.tostring +// 在不支持 `toStringTag` 的环境中重新定义 `Object.prototype.toString` if (!toStringTagSupport) { - redefine(Object.prototype, 'toString', objectToString, { unsafe: true }); + redefine(Object.prototype, 'toString', objectToString, { unsafe: true }); } var trim$1 = stringTrim.trim; - +// 原生 `parseFloat` 方法 var nativeParseFloat = global_1.parseFloat; + +// 检查 `parseFloat` 的兼容性,处理某些浏览器中的特殊情况 var FORCED$2 = 1 / nativeParseFloat(whitespaces + '-0') !== -Infinity; - // `parseFloat` method - // https://tc39.github.io/ecma262/#sec-parsefloat-string +// `parseFloat` 方法实现 +// https://tc39.github.io/ecma262/#sec-parsefloat-string var _parseFloat = FORCED$2 ? function parseFloat(string) { - var trimmedString = trim$1(String(string)); - var result = nativeParseFloat(trimmedString); - return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result; + var trimmedString = trim$1(String(string)); // 修剪字符串 + var result = nativeParseFloat(trimmedString); // 调用原生 `parseFloat` + return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result; // 修复 -0 的问题 } : nativeParseFloat; - // `parseFloat` method - // https://tc39.github.io/ecma262/#sec-parsefloat-string +// 导出 `parseFloat` 方法,确保其在当前环境中是正确的 _export({ global: true, forced: parseFloat != _parseFloat }, { - parseFloat: _parseFloat + parseFloat: _parseFloat }); var trim$2 = stringTrim.trim; - +// 原生 `parseInt` 方法 var nativeParseInt = global_1.parseInt; - var hex = /^[+-]?0[Xx]/; + var hex = /^[+-]?0[Xx]/; // 检测十六进制数字的正则 + +// 检查 `parseInt` 的兼容性,修复一些特殊情况 var FORCED$3 = nativeParseInt(whitespaces + '08') !== 8 || nativeParseInt(whitespaces + '0x16') !== 22; - // `parseInt` method - // https://tc39.github.io/ecma262/#sec-parseint-string-radix +// `parseInt` 方法实现 +// https://tc39.github.io/ecma262/#sec-parseint-string-radix var _parseInt = FORCED$3 ? function parseInt(string, radix) { - var S = trim$2(String(string)); - return nativeParseInt(S, (radix >>> 0) || (hex.test(S) ? 16 : 10)); + var S = trim$2(String(string)); // 修剪字符串 + return nativeParseInt(S, (radix >>> 0) || (hex.test(S) ? 16 : 10)); // 处理十六进制和其他基数 } : nativeParseInt; - // `parseInt` method - // https://tc39.github.io/ecma262/#sec-parseint-string-radix +// 导出 `parseInt` 方法,确保其在当前环境中是正确的 _export({ global: true, forced: parseInt != _parseInt }, { - parseInt: _parseInt + parseInt: _parseInt }); - // `RegExp.prototype.flags` getter implementation - // https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags +// `RegExp.prototype.flags` 属性获取器实现 +// https://tc39.github.io/ecma262/#sec-get-regexp.prototype.flags var regexpFlags = function () { - var that = anObject(this); - var result = ''; - if (that.global) result += 'g'; - if (that.ignoreCase) result += 'i'; - if (that.multiline) result += 'm'; - if (that.dotAll) result += 's'; - if (that.unicode) result += 'u'; - if (that.sticky) result += 'y'; - return result; + var that = anObject(this); // 获取 `RegExp` 对象 + var result = ''; + if (that.global) result += 'g'; + if (that.ignoreCase) result += 'i'; + if (that.multiline) result += 'm'; + if (that.dotAll) result += 's'; + if (that.unicode) result += 'u'; + if (that.sticky) result += 'y'; + return result; // 返回所有标志的组合 }; - // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError, - // so we use an intermediate function. +// `RegExp` 构造函数 function RE(s, f) { - return RegExp(s, f); + return RegExp(s, f); // 创建一个新的 `RegExp` 对象 } +// 检查 `y` 标志的支持情况 var UNSUPPORTED_Y = fails(function () { - // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError - var re = RE('a', 'y'); - re.lastIndex = 2; - return re.exec('abcd') != null; + // 某些环境不支持 `y` 标志,导致代码抛出语法错误 + var re = RE('a', 'y'); + re.lastIndex = 2; + return re.exec('abcd') != null; }); +// 检查 Firefox 中的已知 bug,Bugzilla ID: 773687 +// 该 bug 会导致在使用 `^` 和 `y` 标志时,`lastIndex` 属性更新不正确。 var BROKEN_CARET = fails(function () { - // https://bugzilla.mozilla.org/show_bug.cgi?id=773687 - var re = RE('^r', 'gy'); - re.lastIndex = 2; - return re.exec('str') != null; + // 创建一个正则表达式,使用 `g` 和 `y` 标志 + var re = RE('^r', 'gy'); + re.lastIndex = 2; + // 在字符串 'str' 上执行 `exec`,如果返回值不为 `null`,则说明存在 bug + return re.exec('str') != null; }); +// 创建一个对象,包含关于正则表达式 `sticky` 标志的兼容性信息 var regexpStickyHelpers = { - UNSUPPORTED_Y: UNSUPPORTED_Y, - BROKEN_CARET: BROKEN_CARET + UNSUPPORTED_Y: UNSUPPORTED_Y, // 如果不支持 `y` 标志 + BROKEN_CARET: BROKEN_CARET // 如果存在 `^` 和 `y` 组合标志的问题 }; +// 获取原生 `RegExp.prototype.exec` 方法 var nativeExec = RegExp.prototype.exec; - // This always refers to the native implementation, because the - // String#replace polyfill uses ./fix-regexp-well-known-symbol-logic.js, - // which loads this file before patching the method. + +// 获取原生 `String.prototype.replace` 方法 var nativeReplace = String.prototype.replace; +// 默认将 `exec` 方法设置为原生 `exec` 方法 var patchedExec = nativeExec; +// 检查浏览器是否存在 `lastIndex` 更新不正确的问题 var UPDATES_LAST_INDEX_WRONG = (function () { - var re1 = /a/; - var re2 = /b*/g; - nativeExec.call(re1, 'a'); - nativeExec.call(re2, 'a'); - return re1.lastIndex !== 0 || re2.lastIndex !== 0; + var re1 = /a/; + var re2 = /b*/g; + // 在两个正则表达式上执行 `exec`,并检查 `lastIndex` 是否被正确更新 + nativeExec.call(re1, 'a'); + nativeExec.call(re2, 'a'); + return re1.lastIndex !== 0 || re2.lastIndex !== 0; })(); +// 检查是否有已知的 `y` 标志问题 var UNSUPPORTED_Y$1 = regexpStickyHelpers.UNSUPPORTED_Y || regexpStickyHelpers.BROKEN_CARET; - // nonparticipating capturing group, copied from es5-shim's String#split patch. +// 检查浏览器是否支持非参与的捕获组(NPCG) var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined; +// 判断是否需要修补 `exec` 方法 var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y$1; +// 如果发现需要修补,定义 `patchedExec` 函数 if (PATCH) { - patchedExec = function exec(str) { - var re = this; - var lastIndex, reCopy, match, i; - var sticky = UNSUPPORTED_Y$1 && re.sticky; - var flags = regexpFlags.call(re); - var source = re.source; - var charsAdded = 0; - var strCopy = str; - - if (sticky) { - flags = flags.replace('y', ''); - if (flags.indexOf('g') === -1) { - flags += 'g'; - } - - strCopy = String(str).slice(re.lastIndex); - // Support anchored sticky behavior. - if (re.lastIndex > 0 && (!re.multiline || re.multiline && str[re.lastIndex - 1] !== '\n')) { - source = '(?: ' + source + ')'; - strCopy = ' ' + strCopy; - charsAdded++; - } - // ^(? + rx + ) is needed, in combination with some str slicing, to - // simulate the 'y' flag. - reCopy = new RegExp('^(?:' + source + ')', flags); - } - - if (NPCG_INCLUDED) { - reCopy = new RegExp('^' + source + '$(?!\\s)', flags); - } - if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex; - - match = nativeExec.call(sticky ? reCopy : re, strCopy); - - if (sticky) { - if (match) { - match.input = match.input.slice(charsAdded); - match[0] = match[0].slice(charsAdded); - match.index = re.lastIndex; - re.lastIndex += match[0].length; - } else re.lastIndex = 0; - } else if (UPDATES_LAST_INDEX_WRONG && match) { - re.lastIndex = re.global ? match.index + match[0].length : lastIndex; - } - if (NPCG_INCLUDED && match && match.length > 1) { - // Fix browsers whose `exec` methods don't consistently return `undefined` - // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/ - nativeReplace.call(match[0], reCopy, function () { - for (i = 1; i < arguments.length - 2; i++) { - if (arguments[i] === undefined) match[i] = undefined; - } - }); - } - - return match; - }; + patchedExec = function exec(str) { + var re = this; // 当前的正则表达式对象 + var lastIndex, reCopy, match, i; + var sticky = UNSUPPORTED_Y$1 && re.sticky; // 检查是否启用了 `y` 标志 + var flags = regexpFlags.call(re); // 获取正则表达式的标志 + var source = re.source; // 获取正则表达式的源代码 + var charsAdded = 0; // 用于调整字符串 + var strCopy = str; // 复制输入字符串 + + if (sticky) { + // 修复 `sticky` 标志的行为,确保正则表达式正确处理 + flags = flags.replace('y', ''); // 移除 `y` 标志 + if (flags.indexOf('g') === -1) { + flags += 'g'; // 添加 `g` 标志 + } + + strCopy = String(str).slice(re.lastIndex); // 切割字符串,从 `lastIndex` 开始 + + // 支持锚定的 `sticky` 行为 + if (re.lastIndex > 0 && (!re.multiline || re.multiline && str[re.lastIndex - 1] !== '\n')) { + source = '(?: ' + source + ')'; // 用非捕获组包裹正则源 + strCopy = ' ' + strCopy; // 在字符串前面添加空格 + charsAdded++; // 记录字符数 + } + + // 使用新的正则表达式副本进行匹配 + reCopy = new RegExp('^(?:' + source + ')', flags); + } + + // 如果支持非参与捕获组(NPCG),则处理特定情况 + if (NPCG_INCLUDED) { + reCopy = new RegExp('^' + source + '$(?!\\s)', flags); + } + + // 如果浏览器的 `exec` 方法存在 `lastIndex` 更新问题,进行修补 + if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex; + + // 调用原生 `exec` 方法执行匹配 + match = nativeExec.call(sticky ? reCopy : re, strCopy); + + if (sticky) { + if (match) { + match.input = match.input.slice(charsAdded); // 更新 `input` 属性 + match[0] = match[0].slice(charsAdded); // 更新匹配结果 + match.index = re.lastIndex; // 更新 `index` + re.lastIndex += match[0].length; // 更新 `lastIndex` + } else { + re.lastIndex = 0; // 如果没有匹配,重置 `lastIndex` + } + } else if (UPDATES_LAST_INDEX_WRONG && match) { + // 如果浏览器存在 `lastIndex` 更新问题,修复它 + re.lastIndex = re.global ? match.index + match[0].length : lastIndex; + } + + if (NPCG_INCLUDED && match && match.length > 1) { + // 修复浏览器中 `exec` 方法不一致地返回 `undefined` 的问题 + nativeReplace.call(match[0], reCopy, function () { + for (i = 1; i < arguments.length - 2; i++) { + if (arguments[i] === undefined) match[i] = undefined; + } + }); + } + + return match; // 返回匹配结果 + }; } +// 定义最终的 `regexpExec`,它会被用作 `RegExp.prototype.exec` 的替代方法 var regexpExec = patchedExec; +// 如果浏览器的 `exec` 方法不符合预期,使用修补的 `exec` 方法替代 _export({ target: 'RegExp', proto: true, forced: /./.exec !== regexpExec }, { - exec: regexpExec + exec: regexpExec }); - +// 定义常量 var TO_STRING = 'toString'; var RegExpPrototype = RegExp.prototype; var nativeToString = RegExpPrototype[TO_STRING]; +// 检查 `RegExp.prototype.toString` 是否是一个通用方法 +// 如果 `nativeToString.call({ source: 'a', flags: 'b' }) != '/a/b'`,则认为不是通用方法 var NOT_GENERIC = fails(function () { return nativeToString.call({ source: 'a', flags: 'b' }) != '/a/b'; }); - // FF44- RegExp#toString has a wrong name +// 检查 `RegExp.prototype.toString` 的方法名称是否正确,某些浏览器会将其命名为其他名称(如 Firefox 44) var INCORRECT_NAME = nativeToString.name != TO_STRING; - // `RegExp.prototype.toString` method - // https://tc39.github.io/ecma262/#sec-regexp.prototype.tostring +// 修复 `RegExp.prototype.toString` 方法 +// 如果原生方法不通用或名称错误,则重新定义它 if (NOT_GENERIC || INCORRECT_NAME) { - redefine(RegExp.prototype, TO_STRING, function toString() { - var R = anObject(this); - var p = String(R.source); - var rf = R.flags; - var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype) ? regexpFlags.call(R) : rf); - return '/' + p + '/' + f; - }, { unsafe: true }); + redefine(RegExp.prototype, TO_STRING, function toString() { + var R = anObject(this); // 获取当前正则对象 + var p = String(R.source); // 获取正则表达式的源 + var rf = R.flags; // 获取正则表达式的标志 + var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype) ? regexpFlags.call(R) : rf); // 处理没有 `flags` 属性的情况 + return '/' + p + '/' + f; // 返回标准的正则表达式字符串 + }, { unsafe: true }); // 使用 `{ unsafe: true }` 选项,允许覆盖原生方法 } var MATCH = wellKnownSymbol('match'); - // `IsRegExp` abstract operation - // https://tc39.github.io/ecma262/#sec-isregexp +// `IsRegExp` 抽象操作,用于判断一个对象是否是正则表达式 +// https://tc39.github.io/ecma262/#sec-isregexp var isRegexp = function (it) { - var isRegExp; - return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp'); + var isRegExp; + return isObject(it) && ((isRegExp = it[MATCH]) !== undefined ? !!isRegExp : classofRaw(it) == 'RegExp'); }; +// `notARegexp` 方法,如果参数是正则表达式,则抛出错误 var notARegexp = function (it) { - if (isRegexp(it)) { - throw TypeError("The method doesn't accept regular expressions"); - } return it; + if (isRegexp(it)) { + throw TypeError("The method doesn't accept regular expressions"); + } return it; }; var MATCH$1 = wellKnownSymbol('match'); +// 修复 `String.prototype.includes` 方法的兼容性 +// 检查当前环境是否支持 `includes` 方法的正确逻辑 var correctIsRegexpLogic = function (METHOD_NAME) { - var regexp = /./; - try { - '/./'[METHOD_NAME](regexp); - } catch (e) { - try { - regexp[MATCH$1] = false; - return '/./'[METHOD_NAME](regexp); - } catch (f) { /* empty */ } - } return false; + var regexp = /./; + try { + // 如果 `String.prototype.includes` 支持正则表达式参数,则返回 `true` + '/./'[METHOD_NAME](regexp); + } catch (e) { + try { + // 如果 `regexp[MATCH$1]` 被设置为 `false`,则可以正常工作 + regexp[MATCH$1] = false; + return '/./'[METHOD_NAME](regexp); + } catch (f) { /* empty */ } + } return false; }; - // `String.prototype.includes` method - // https://tc39.github.io/ecma262/#sec-string.prototype.includes +// 修复 `String.prototype.includes` 方法 +// 如果当前环境不支持正确的 `includes` 方法,则进行修补 _export({ target: 'String', proto: true, forced: !correctIsRegexpLogic('includes') }, { - includes: function includes(searchString /* , position = 0 */) { - return !!~String(requireObjectCoercible(this)) - .indexOf(notARegexp(searchString), arguments.length > 1 ? arguments[1] : undefined); - } + includes: function includes(searchString /* , position = 0 */) { + // 强制将输入对象转为字符串,查找 `searchString` 的位置 + return !!~String(requireObjectCoercible(this)) + .indexOf(notARegexp(searchString), arguments.length > 1 ? arguments[1] : undefined); + } }); - // `String.prototype.{ codePointAt, at }` methods implementation +// `String.prototype.{ codePointAt, at }` 方法的实现 +// 创建方法 `createMethod$4`,用于处理字符编码和字符的位置 var createMethod$4 = function (CONVERT_TO_STRING) { - return function ($this, pos) { - var S = String(requireObjectCoercible($this)); - var position = toInteger(pos); - var size = S.length; - var first, second; - if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined; - first = S.charCodeAt(position); - return first < 0xD800 || first > 0xDBFF || position + 1 === size - || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF - ? CONVERT_TO_STRING ? S.charAt(position) : first - : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000; - }; + return function ($this, pos) { + var S = String(requireObjectCoercible($this)); // 强制转换为字符串 + var position = toInteger(pos); // 将位置转换为整数 + var size = S.length; // 获取字符串的长度 + var first, second; + if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined; // 如果位置不合法,则返回相应值 + first = S.charCodeAt(position); // 获取字符的 Unicode 编码 + return first < 0xD800 || first > 0xDBFF || position + 1 === size + || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF + ? CONVERT_TO_STRING ? S.charAt(position) : first + : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000; // 如果字符是代理对,则返回联合值 + }; }; var stringMultibyte = {