src/seed/lang.fix.js
/**
* 此模块用于修复语言的底层缺陷
*/
import { avalon, ohasOwn, ap, _slice } from './core'
function isNative(fn) {
return /\[native code\]/.test(fn)
}
/* istanbul ignore if*/
if (!isNative('司徒正美'.trim)) {
var rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g
String.prototype.trim = function() {
return this.replace(rtrim, '')
}
}
if (!Object.create) {
Object.create = (function() {
function F() {}
return function(o) {
if (arguments.length != 1) {
throw new Error('Object.create implementation only accepts one parameter.');
}
F.prototype = o;
return new F()
}
})()
}
var hasDontEnumBug = !({
'toString': null
}).propertyIsEnumerable('toString'),
hasProtoEnumBug = (function() {}).propertyIsEnumerable('prototype'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
/* istanbul ignore if*/
if (!isNative(Object.keys)) {
Object.keys = function(object) { //ecma262v5 15.2.3.14
var theKeys = []
var skipProto = hasProtoEnumBug && typeof object === 'function'
if (typeof object === 'string' || (object && object.callee)) {
for (var i = 0; i < object.length; ++i) {
theKeys.push(String(i))
}
} else {
for (var name in object) {
if (!(skipProto && name === 'prototype') &&
ohasOwn.call(object, name)) {
theKeys.push(String(name))
}
}
}
if (hasDontEnumBug) {
var ctor = object.constructor,
skipConstructor = ctor && ctor.prototype === object
for (var j = 0; j < dontEnumsLength; j++) {
var dontEnum = dontEnums[j]
if (!(skipConstructor && dontEnum === 'constructor') && ohasOwn.call(object, dontEnum)) {
theKeys.push(dontEnum)
}
}
}
return theKeys
}
}
/* istanbul ignore if*/
if (!isNative(Array.isArray)) {
Array.isArray = function(a) {
return Object.prototype.toString.call(a) === '[object Array]'
}
}
/* istanbul ignore if*/
if (!isNative(isNative.bind)) {
/* istanbul ignore next*/
Function.prototype.bind = function(scope) {
if (arguments.length < 2 && scope === void 0)
return this
var fn = this,
argv = arguments
return function() {
var args = [],
i
for (i = 1; i < argv.length; i++)
args.push(argv[i])
for (i = 0; i < arguments.length; i++)
args.push(arguments[i])
return fn.apply(scope, args)
}
}
}
//https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
/**
* Shim for "fixing" IE's lack of support (IE < 9) for applying slice
* on host objects like NamedNodeMap, NodeList, and HTMLCollection
* (technically, since host objects have been implementation-dependent,
* at least before ES6, IE hasn't needed to work this way).
* Also works on strings, fixes IE < 9 to allow an explicit undefined
* for the 2nd argument (as in Firefox), and prevents errors when
* called on other DOM objects.
*/
try {
// Can't be used with DOM elements in IE < 9
_slice.call(avalon.document.documentElement)
} catch (e) { // Fails in IE < 9
// This will work for genuine arrays, array-like objects,
// NamedNodeMap (attributes, entities, notations),
// NodeList (e.g., getElementsByTagName), HTMLCollection (e.g., childNodes),
// and will not fail on other DOM objects (as do DOM elements in IE < 9)
/* istanbul ignore next*/
ap.slice = function(begin, end) {
// IE < 9 gets unhappy with an undefined end argument
end = (typeof end !== 'undefined') ? end : this.length
// For native Array objects, we use the native slice function
if (Array.isArray(this)) {
return _slice.call(this, begin, end)
}
// For array like object we handle it ourselves.
var i, cloned = [],
size, len = this.length
// Handle negative value for "begin"
var start = begin || 0
start = (start >= 0) ? start : len + start
// Handle negative value for "end"
var upTo = (end) ? end : len
if (end < 0) {
upTo = len + end
}
// Actual expected size of the slice
size = upTo - start
if (size > 0) {
cloned = new Array(size)
if (this.charAt) {
for (i = 0; i < size; i++) {
cloned[i] = this.charAt(start + i)
}
} else {
for (i = 0; i < size; i++) {
cloned[i] = this[start + i]
}
}
}
return cloned
}
}
/* istanbul ignore next*/
function iterator(vars, body, ret) {
var fun = 'for(var ' + vars + 'i=0,n = this.length; i < n; i++){' +
body.replace('_', '((i in this) && fn.call(scope,this[i],i,this))') +
'}' + ret
/* jshint ignore:start */
return Function('fn,scope', fun)
/* jshint ignore:end */
}
/* istanbul ignore if*/
if (!isNative(ap.map)) {
avalon.shadowCopy(ap, {
//定位操作,返回数组中第一个等于给定参数的元素的索引值。
indexOf: function(item, index) {
var n = this.length,
i = ~~index
if (i < 0)
i += n
for (; i < n; i++)
if (this[i] === item)
return i
return -1
},
//定位操作,同上,不过是从后遍历。
lastIndexOf: function(item, index) {
var n = this.length,
i = index == null ? n - 1 : index
if (i < 0)
i = Math.max(0, n + i)
for (; i >= 0; i--)
if (this[i] === item)
return i
return -1
},
//迭代操作,将数组的元素挨个儿传入一个函数中执行。Prototype.js的对应名字为each。
forEach: iterator('', '_', ''),
//迭代类 在数组中的每个项上运行一个函数,如果此函数的值为真,则此元素作为新数组的元素收集起来,并返回新数组
filter: iterator('r=[],j=0,', 'if(_)r[j++]=this[i]', 'return r'),
//收集操作,将数组的元素挨个儿传入一个函数中执行,然后把它们的返回值组成一个新数组返回。Prototype.js的对应名字为collect。
map: iterator('r=[],', 'r[i]=_', 'return r'),
//只要数组中有一个元素满足条件(放进给定函数返回true),那么它就返回true。Prototype.js的对应名字为any。
some: iterator('', 'if(_)return true', 'return false'),
//只有数组中的元素都满足条件(放进给定函数返回true),它才返回true。Prototype.js的对应名字为all。
every: iterator('', 'if(!_)return false', 'return true')
})
}