Array.from()
Array.myFrom = function(target,fn,thisargs){
if(typeof target[Symbol.iterator]!=="function"){
return [];
}
if(typeof fn!=="function"){
fn=false;
}
const it = target[Symbol.iterator](),res=[];
let end = false;
if(!end){
let {value,done} = it.next();
if(!done){
if(fn){
res.push(fn.call(thisargs,value))
}
else{
res.push(value);
}
}
end=done;
}
return res;
}
Array.from()方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
接受三个参数,target:目标对象,fn:如果有,返回回调函数处理后的每个元素,thisargs,指定函数运行的this环境
Array.of()
Array.myOf = function(){
let result = [];
for(let i of arguments){
result.push(i)
}
return result;
}
copyWithin()
if (!Array.prototype.copyWithin) {
Array.prototype.copyWithin = function(target, start/*, end*/) {
// Steps 1-2.
if (this == null) {
throw new TypeError('this is null or not defined');
}
var O = Object(this);
// Steps 3-5.
var len = O.length >>> 0;
// Steps 6-8.
var relativeTarget = target >> 0;
var to = relativeTarget < 0 ?
Math.max(len + relativeTarget, 0) :
Math.min(relativeTarget, len);
// Steps 9-11.
var relativeStart = start >> 0;
var from = relativeStart < 0 ?
Math.max(len + relativeStart, 0) :
Math.min(relativeStart, len);
// Steps 12-14.
var end = arguments[2];
var relativeEnd = end === undefined ? len : end >> 0;
var final = relativeEnd < 0 ?
Math.max(len + relativeEnd, 0) :
Math.min(relativeEnd, len);
// Step 15.
var count = Math.min(final - from, len - to);
// Steps 16-17.
var direction = 1;
if (from < to && to < (from + count)) {
direction = -1;
from += count - 1;
to += count - 1;
}
// Step 18.
while (count > 0) {
if (from in O) {
O[to] = O[from];
} else {
delete O[to];
}
from += direction;
to += direction;
count--;
}
// Step 19.
return O;
};
}
fill()
Array.prototype.myFill = function(value,start,end){
start=start?start<0?start+this.length:start:0; //start不存在默认为0,为负值则加length
end=end?end<0?end+this.length:end:this.length; //end不存在默认为length;
console.log(start,end)
if(end<start){ //end>start不填充
end=start=0;
}
if(end>this.length){ //处理边界超出
end=this.length;
}
if(start>this.length){ //start边界超出,则不管end是什么都应该忽略,不填充
start=end=0;
}
for(let i=start;i<end;i++){
this[i]=value;
}
return this;
}
fill:从start开始填充,到end结束,不包括end。如果start和end超出边界,则忽略。如果start>end,则不填充
sort()
sort()方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的.
如果没有指明 compareFunction ,那么元素会按照转换为的字符串的诸个字符的Unicode位点进行排序。例如 "Banana" 会被排列到 "cherry" 之前。当数字按由小到大排序时,9 出现在 80 之前,但因为(没有指明 compareFunction),比较的数字会先被转换为字符串,所以在Unicode顺序上 "80" 要比 "9" 要靠前。
如果指明了 compareFunction ,那么数组会按照调用该函数的返回值排序。即 a 和 b 是两个将要被比较的元素:
-
如果
compareFunction(a, b)小于 0 ,那么 a 会被排列到 b 之前; -
如果
compareFunction(a, b)等于 0 , a 和 b 的相对位置不变。备注: ECMAScript 标准并不保证这一行为,而且也不是所有浏览器都会遵守(例如 Mozilla 在 2003 年之前的版本); -
如果
compareFunction(a, b)大于 0 , b 会被排列到 a 之前。 -
compareFunction(a, b)必须总是对相同的输入返回相同的比较结果,否则排序的结果将是不确定的。
在chrome的V8源码中,对于数组元素10以内的,使用插入排序,对于大于10的,使用快速排序算法。
为什么是这样,来测试一下
function quickSort(arr) {
var len = arr.length; //结束递归的条件
if (len <= 1) return arr;
var left = [];
var right = []; //中间基数
var midindex = Math.floor(len / 2);
var mid = arr[midindex];
for (var i = 0; i < len; i++) {
if (arr[i] == mid) continue;
else if (arr[i] < mid) left.push(arr[i]);
else right.push(arr[i]);
}
return quickSort(left).concat([mid], quickSort(right));
}
let arr = []
for (let i = 0; i < 100000; i++) {
arr.push(parseInt(Math.random() * 10000))
}
let startTime = performance.now()
quickSort(arr)
let endTime = performance.now()
console.log(endTime - startTime)
function insertSort(arr) {
var len = arr.length;
for (var i = 0; i < len; i++) {
var k = i; //前提: 1 前面必须有内容 //前提: 2 当前这个元素,比左边小,交换1次
while (k - 1 >= 0 && arr[k] < arr[k - 1]) {
var temp = arr[k];
arr[k] = arr[k - 1];
arr[k - 1] = temp;
k--;
}
}
return arr;
}
let arr = []
for (let i = 0; i < 100000; i++) {
arr.push(parseInt(Math.random() * 10000))
}
let startTime = performance.now()
insertSort(arr)
let endTime = performance.now()
console.log(endTime - startTime)
slice()
Array.prototype.mySlice = function(begin,end){
let len = this.length;
const result = [];
let index = 0;
begin = begin?begin<0?len+begin:begin:0; //begin或end为负值,则加len为结果
end = end||end===0?end<0?end+len:end:len; //重点:考虑到end为0或者负值的情况
if(end<begin){
return result; //end<begin则返回空数组
}
for(;begin<end;begin++){
result[index++] = this[begin]; //截取的片段不包括end索引处元素
}
return result;
}
splice()
Array.prototype.mySplice = function(){
let params = Array.prototype.slice.call(arguments)
let start = params.shift();
let deleteCount = params.shift();
start = Math.floor(start-0)||0; //获取start,floor防止小数
if(start<0){
start = this.length+start /start<0,则加length作为结果
}
if(start>this.length-1){ //start>length,说明不删除元素
return [];
}
deleteCount = Math.floor(deleteCount-0)||this.length-start; //防止小数
deleteCount<0?0:deleteCount; //seleteCount<0说明不删除
deleteCount>this.length-start?this.length-start:deleteCount; //如果超出数组上限,就删除start后面所有元素
let i=0,startArr=[],res=[],len=this.length;
for(i=0;i<start+deleteCount;i++){
value=this.shift(); //从头取出数组元素
if(i<start){
startArr.push(value) //start之前的放入一个数组startArr
}
if(i>=start){
res.push(value); //应该删除的元素放入一个数组作为结果res
}
}
while(params.length){
this.unshift(params.pop()); //先从头添加增加的元素
}
while(startArr.length){
this.unshift(startArr.pop()); //然后添加start之前的数组元素startArr
}
return res; //返回删除的元素
}
indexOf()
Array.prototype.myIndexOf = function(target,startIndex){
let len= this.length;
startIndex = startIndex?startIndex<0?startIndex+len<0?0:startIndex+len:startIndex:0;
for(let i = startIndex;i<len;i++){
if(target===this[i])){
return i;;
}
}
return -1;
}
其实和includes几乎相等,只是这里NaN!=NaN,所以不能使用Obejct.is()比较
lastIndexOf()
includes()
Array.prototype.myIncludes = function(target,startIndex){
let len= this.length;
startIndex = startIndex?startIndex<0?startIndex+len<0?0:startIndex+len:startIndex:0;
for(let i = startIndex;i<len;i++){
if(Object.is(target,this[i])){
return true;
}
}
return false;
}
includes的startIndex注意:如果没有传,默认为0,非数字,默认为0。传入负值,则为startIndex+len,如果结果仍然为负值,则为0
find()
Array.prototype.myFind(callback,thisargs){
if(!this instanceof Array){
throw new Error("this is not a array";)
}
if(typeof callback !=="function"){
throw new TypeError("callback is not a function");
}
let context = thisargs||this;
let target = this;
for(let i=0;i<target.length;i++){
if(callback.call(context,target[i],i,target)){
return target[i]
}
}
return undefined;
}
find的第一个参数为回调函数,第二个参数为指定的上下文this,可选。结果返回满足回调函数条件的第一个元素,如果没有,则返回undefined。回调函数接受三个参数:当前元素,索引,数组本身。
array.find(function(currentValue, index, arr),thisValue)
flat()
Array.prototype.myFlat = function(depth=1){
const result = []; // 缓存递归结果
// 开始递归
(function flat(depth) {
// forEach 会自动去除数组空位
this.forEach((item) => {
// 控制递归深度
if (Array.isArray(item) && depth > 0) {
// 递归数组
flat(item, depth - 1)
} else {
// 缓存元素
result.push(item)
}
})
})(depth)
// 返回递归结果
return result;
}
arr.reduce((acc, val) => acc.concat(val), []);
function flatten(input) {
const stack = [...input];
const res = [];
while (stack.length) {
// 使用 pop 从 stack 中取出并移除值
const next = stack.pop();
if (Array.isArray(next)) {
// 使用 push 送回内层数组中的元素,不会改动原始输入
stack.push(...next);
} else {
res.push(next);
}
}
// 反转恢复原数组的顺序
return res.reverse();
}
function* flatten(array) {
for (const item of array) {
if (Array.isArray(item)) {
yield* flatten(item);
} else {
yield item;
}
}
}
reverse()
Array.prototype.myReverse = function(){
if(this.length===0){
return this;
}
let left = Math.floor((this.length/2)-1); //Math.floor解决奇数造成的0.5问题
let y = this.length%2; //判断是奇数还是偶数个元素
let right = left+1+y; //取得右指针
while(left>=0&&right<this.length){
[this[left],this[right]] = [this[right],this[left]]; //双指针法
right++;
left--;
}
return this;
}
concat()
Array.prototype.myConcat = function(){
let target = (this instanceof Array)?this:[];
let args = Array.prototype.slice.call(arguments);
let result = [];
while(target.length){
result.push(target.shift());
}
while(args.length>0){
let value = args.shift();
if(value instanceof Array){ //如果value是数组,则扁平化一层。
for(let item of value){
result.push(item)
}
}
else{
result.push(value) //value不是数组,直接添加
}
}
return result;
}
join
Array.prototype.myJoin = function(char){
let result = this[0]||'';
let len = this.length;
char = char||","; //join不传参数,默认","为分隔符
for(let i = 0;i<length;i++){
result += char + this[i];
}
return result;
}
参数:每个数组方法接受俩个参数:一个为回调函数,一个为参数运行时的上下文this,会影响回调函数中的this指向。回调函数接受三个参数,数组元素,索引,数组本身。
every()
Array.prototype.myEvery = function(callback,newthis){
if(this === undefined){
throw new TypeError('this is null or not defined')
}
if(typeof callback !== 'function'){
throw new TypeError(callback + 'must be a function');
}
const res = [];
const o = Object(this);
let len = o.length;
for(let i = 0;i<len;i++){
if(i in o){
if(!callback.call(newthis,o[i],i,o)){
return false;
}
}
}
return true;
}
some()
Array.prototype.mySome = function(callback,newthis){
if(this === undefined){
throw new TypeError('this is null or not defined')
}
if(typeof callback !== 'function'){
throw new TypeError(callback + 'must be a function');
}
const res = [];
const o = Object(this);
let len = o.length;
for(let i = 0;i<len;i++){
if(i in o){
if(callback.call(newthis,o[i],i,o)){
return true;
}
}
}
return false;
}
map()
Array.prototype.myMap = function(callback,newthis){
if(this === undefined){
throw new TypeError('this is null or not defined')
}
if(typeof callback !== 'function'){
throw new TypeError(callback + 'must be a function');
}
const res = [];
const o = Object(this);
let len = o.length;
for(let i = 0;i<len;i++){
if(i in o){
res[i]=callback.call(newthis,o[i],i,o);
}
}
return res;
}
forEach()
Array.prototype.myForEach = function(callback,newthis){
if(this === undefined){
throw new TypeError('this is null or not defined')
}
if(typeof callback !== 'function'){
throw new TypeError(callback + 'must be a function');
}
const o = Object(this);
let len = o.length;
for(let i = 0;i<len;i++){
if(i in o){
callback.call(newthis,o[i],i,o)
}
}
}
filter()
Array.prototype.myFilter = function(callback,newthis){
if(this === undefined){
throw new TypeError('this is null or not defined')
}
if(typeof callback !== 'function'){
throw new TypeError(callback + 'must be a function');
}
const res = [];
const o = Object(this);
let len = o.length;
for(let i = 0;i<len;i++){
if(i in o){
if(callback.call(newthis,o[i],i,o)){
res.push(o[i])
}
}
}
return res;
}
reduce()
Array.prototype.reduce(callback,initValue){
if(this === undefined){
throw new TypeError('this is null or not defined')
}
if(typeof callback !== 'function'){
throw new TypeError(callback + 'must be a function');
}
let O = Object(this);
let len = O.length;
let accumlator = initValue;
if(accumlator === undefined){
while(k<len&&!(k in O)){
k++;
}
if(k>=len){
throw new TypeError('Reduce of empty array no inital value')
}
accumlator = O[k];
}
while(k<len){
if(k in O){
accumlator = callback.call(undefined,accumlator,O[k],k,O)
}
k++;
}
return accumlator;
}
reduce的第一个参数为回调函数,第二个参数为callback的初始值,可选。回调函数接受四个参数:
初始值(前几项的累计返回值):initValue或者数组的第一个元素,currentValue:正在处理的元素,index:正在处理的索引,array:数组本身(this)