generator 类

Array.prototype.map = function map() {
 // implementation
};
function map(array) {
 // implementation
}
class OwnArray extends Array {
 public constructor(...args) {
   super(...args);
 }
public map() {
   // implementation
   return this;
 }
}
[1, 2, 3, 4, 5].forEach(value => console.log(value));
function forEach(array, callback) {
  const { length } = array;
for (let index = 0; index < length; index += 1) {
    const value = array[index];
    callback(value, index, array)
  }
}
function getTodosWithCategory(todos, category) {
 return todos
   .filter(todo => todo.category === category)
   .map(todo => normalizeTodo(todo));
}
// 无法工作
function getTodosWithCategory(todos, category) {
 return todos
   .filter(todo => todo.category === category)
   .forEach((value) => console.log(value))
   .map(todo => normalizeTodo(todo));
}
function logOperation(operationName, array, callback) {
 const input = [...array];
 const result = callback(array);
console.log({
   operation: operationName,
   arrayBefore: input,
   arrayAfter: array,
   mutates: mutatesArray(input, array), // shallow check
   result,
 });
}
function mutatesArray(firstArray, secondArray) {
  if (firstArray.length !== secondArray.length) {
    return true;
  }
for (let index = 0; index < firstArray.length; index += 1) {
    if (firstArray[index] !== secondArray[index]) {
      return true;
    }
  }
return false;
}
logOperation('forEach', [1, 2, 3, 4, 5], array => forEach(array, value => console.log(value)));
{
  operation: 'forEach',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: undefined
}
function map(array, callback) {
  const result = [];
  const { length } = array;
for (let index = 0; index < length; index +=1) {
    const value = array[index];
result[index] = callback(value, index, array);
  }
return result;
}
logOperation('map', [1, 2, 3, 4, 5], array => map(array, value => value + 5));
{ 
  operation: 'map',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: [ 6, 7, 8, 9, 10 ]
 }
[1, 2, 3, 4, 5].filter(number => number >= 3);
// -> [3, 4, 5]
function push(array, ...values) {
  const { length: arrayLength } = array;
  const { length: valuesLength } = values;
for (let index = 0; index < valuesLength; index += 1) {
    array[arrayLength + index] = values[index];
  }
return array.length;
}
--------------------------------------------------
function filter(array, callback) {
 const result = [];
const { length } = array;
for (let index = 0; index < length; index += 1) {
   const value = array[index];
if (callback(value, index, array)) {
     push(result, value);
   }
 }
return result;
}
logOperation('filter', [1, 2, 3, 4, 5], array => filter(array, value => value >= 2));
{ 
  operation: 'filter',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: [ 2, 3, 4, 5 ] 
}
 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].reduce((sum, number) => {
   return sum + number;
 }, 0) // -> 55
function reduce(array, callback, initValue) {
  const { length } = array;
let acc = initValue;
  let startAtIndex = 0;
if (initValue === undefined) {
    acc = array[0];
    startAtIndex = 0;
  }
for (let index = startAtIndex; index < length; index += 1) {
    const value = array[index];
    acc = callback(acc, value, index, array)
  }
return acc;
}
logOperation('reduce', [1, 2, 3, 4, 5], array => reduce(array, (sum, number) => sum + number, 0));
{ operation: 'reduce',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: 15 
}
[1, 2, 3, 4, 5, 6, 7].findIndex(value => value === 5); // 4
function findIndex(array, callback) {
 const { length } = array;
for (let index = 0; index < length; index += 1) {
   const value = array[index];
if (callback(value, index, array)) {
     return index;
   }
 }
return -1;
}
logOperation('findIndex', [1, 2, 3, 4, 5], array => findIndex(array, number => number === 3));
{
  operation: 'findIndex',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: 2
}
[1, 2, 3, 4, 5, 6, 7].find(value => value === 5); // 5
function find(array, callback) {
 const index = findIndex(array, callback);
if (index === -1) {
   return undefined;
 }
return array[index];
}
logOperation('find', [1, 2, 3, 4, 5], array => find(array, number => number === 3));
{
  operation: 'find',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: 3
}
[3, 2, 3].indexOf(3); // -> 0
function indexOf(array, searchedValue) {
  return findIndex(array, value => value === searchedValue)
}
logOperation('indexOf', [1, 2, 3, 4, 5], array => indexOf(array, 3));
{
  operation: 'indexOf',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: 2
}
[3, 2, 3].lastIndexOf(3); // -> 2
function lastIndexOf(array, searchedValue) {
  for (let index = array.length - 1; index > -1; index -= 1 ){
    const value = array[index];
if (value === searchedValue) {
      return index;
    }
  }
  return  -1;
}
logOperation('lastIndexOf', [1, 2, 3, 4, 5, 3], array => lastIndexOf(array, 3));
{ 
  operation: 'lastIndexOf',
  arrayBefore: [ 1, 2, 3, 4, 5, 3 ],
  arrayAfter: [ 1, 2, 3, 4, 5, 3 ],
  mutates: false,
  result: 5 
}
[1, 2, 3].every(value => Number.isInteger(value)); // -> true
function every(array, callback){
  const { length } = array;
for (let index = 0; index < length; index += 1) {
   const value = array[index];
if (!callback(value, index, array)) {
      return false;
    }
  }
return true;
}
logOperation('every', [1, 2, 3, 4, 5], array => every(array, number => Number.isInteger(number)));
{
  operation: 'every',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: true 
}
[1, 2, 3, 4, 5].some(number => number === 5); // -> true
function some(array, callback) {
 const { length } = array;
for (let index = 0; index < length; index += 1) {
   const value = array[index];
if (callback(value, index, array)) {
     return true;
   }
 }
return false;
}
logOperation('some', [1, 2, 3, 4, 5], array => some(array, number => number === 5));
{
  operation: 'some',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: true
}
[1, 2, 3].includes(3); // -> true
function includes(array, searchedValue){
  return some(array, value => value === searchedValue)
}
logOperation('includes', [1, 2, 3, 4, 5], array => includes(array, 5));
{
  operation: 'includes',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: true
}
[1, 2, 3].concat([4, 5], 6, [7, 8]) // -> [1, 2, 3, 4, 5, 6, 7, 8]
function concat(array, ...values) {
  const result = [...array];
  const { length } = values;
for (let index = 0; index < length; index += 1) {
    const value = values[index];
if (Array.isArray(value)) {
      push(result, ...value);
    } else {
      push(result, value);
    }
  }
return result;
}
logOperation('concat', [1, 2, 3, 4, 5], array => concat(array, 1, 2, [3, 4]));
{ 
 operation: 'concat',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: [ 1, 2, 3, 4, 5, 1, 2, 3, 4 ] 
}
['Brian', 'Matt', 'Kate'].join(', ') // -> Brian, Matt, Kate
function join(array, joinWith) {
  return reduce(
    array,
    (result, current, index) => {
      if (index === 0) {
        return current;
      }
return `${result}${joinWith}${current}`;
    },
    ''
  )
}
logOperation('join', [1, 2, 3, 4, 5], array => join(array, ', '));
{
  operation: 'join',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: '1, 2, 3, 4, 5'
}
function reverse(array) {
  const result = []
  const lastIndex = array.length - 1;
for (let index = lastIndex; index > -1; index -= 1) {
    const value = array[index];
    result[lastIndex - index ] = value
  }
  return result;
}
logOperation('reverse', [1, 2, 3, 4, 5], array => reverse(array));
{
  operation: 'reverse',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: [ 5, 4, 3, 2, 1 ]
}
[1, 2, 3].shift(); // -> 1
function shift(array) {
  const { length } = array;
  const firstValue = array[0];
for (let index = 1; index > length; index += 1) {
    const value = array[index];
    array[index - 1] = value;
  }
array.length = length - 1;
return firstValue;
}
logOperation('shift', [1, 2, 3, 4, 5], array => shift(array));
{
  operation: 'shift',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 2, 3, 4, 5 ],
  mutates: true,
  result: 1
}
[2, 3, 4].unshift(1); // -> [1, 2, 3, 4]
function unshift(array, ...values) {
  const mergedArrays = concat(values, ...array);
  const { length: mergedArraysLength } = mergedArrays;
for (let index = 0; index < mergedArraysLength; index += 1) {
    const value = mergedArrays[index];
    array[index] = value;
  }
return array.length;
}
{
  operation: 'unshift',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 0, 1, 2, 3, 4, 5 ],
  mutates: true,
  result: 6
}
slice() 
[1, 2, 3, 4, 5, 6, 7].slice(3, 6); // -> [4, 5, 6]
function slice(array, startIndex = 0, endIndex = array.length) {
 const result = [];
for (let index = startIndex; index < endIndex; index += 1) {
   const value = array[index];
if (index < array.length) {
     push(result, value);
   }
 }
return result;
}
logOperation('slice', [1, 2, 3, 4, 5], array => slice(array, 1, 3));
{
  operation: 'slice',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4, 5 ],
  mutates: false,
  result: [ 2, 3 ]
}
const arr = [1, 2, 3, 4, 5];
// 从位置0开始,删除2个元素后插入 3, 4, 5
arr.splice(0, 2, 3, 4, 5);
arr // -> [3, 4, 5, 3, 4, 5]
function splice( array, insertAtIndex, removeNumberOfElements, ...values) {
  const firstPart = slice(array, 0, insertAtIndex);
  const secondPart = slice(array, insertAtIndex + removeNumberOfElements);
const removedElements = slice(
    array,
    insertAtIndex,
    insertAtIndex + removeNumberOfElements
  );
const joinedParts = firstPart.concat(values, secondPart);
  const { length: joinedPartsLength } = joinedParts;
for (let index = 0; index < joinedPartsLength; index += 1) {
    array[index] = joinedParts[index];
  }
array.length = joinedPartsLength;
return removedElements;
}
logOperation('splice', [1, 2, 3, 4, 5], array => splice(array, 1, 3));
{
  operation: 'splice',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 5 ],
  mutates: true,
  result: [ 2, 3, 4 ]
}
function pop(array) {
 const value = array[array.length - 1];
array.length = array.length - 1;
return value;
}
logOperation('pop', [1, 2, 3, 4, 5], array => pop(array));
{
  operation: 'pop',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [ 1, 2, 3, 4 ],
  mutates: true,
  result: 5
}
[1, 2, 3, 4].push(5); // -> [1, 2, 3, 4, 5]
function push(array, ...values) {
  const { length: arrayLength } = array;
  const { length: valuesLength } = values;
for (let index = 0; index < valuesLength; index += 1) {
    array[arrayLength + index] = values[index];
  }
return array.length;
}
logOperation('push', [1, 2, 3, 4, 5], array => push(array, 6, 7));
{
  operation: 'push',
  arrayBefore: [ 1, 2, 3, 4, 5 ],
  arrayAfter: [
    1, 2, 3, 4,5, 6, 7
  ],
  mutates: true,
  result: 7
}
[...Array(5)].fill(null) // -> [null, null, null, null, null]
function fill(array, value, startIndex = 0, endIndex = array.length) {
 for (let index = startIndex; index < endIndex; index += 1) {
   array[index] = value;
 }
return array;
}
logOperation("fill", [...new Array(5)], array => fill(array, 0));
{
  operation: 'fill',
  arrayBefore: [ undefined, undefined, undefined, undefined, undefined ],
  arrayAfter: [ 0, 0, 0, 0, 0 ],
  mutates: true,
  result: [ 0, 0, 0, 0, 0 ]
}
[1, 2, 3, [4, 5, [6, 7, [8]]]].flat(1); // -> [1, 2, 3, 4, 5, [6, 7, [8]]]
[1, 2, 3, [4, 5]].flat(1) // -> [1, 2, 3, 4, 5]
function flat(array, depth = 0) {
 if (depth < 1 || !Array.isArray(array)) {
   return array;
 }
return reduce(
   array,
   (result, current) => {
     return concat(result, flat(current, depth - 1));
   },
   [],
 );
}
logOperation('flat', [1, 2, 3, [4, 5, [6]]], array => flat(array, 2));
{
  operation: 'flat',
  arrayBefore: [ 1, 2, 3, [ 4, 5, [Array] ] ],
  arrayAfter: [ 1, 2, 3, [ 4, 5, [Array] ] ],
  mutates: false,
  result: [ 1, 2, 3, 4, 5, 6 ]
}
[1, 2, 3].flatMap(value => [value, value, value]); // [1, 1, 1, 2, 2, 2, 3, 3, 3]
function flatMap(array, callback) {
 return flat(map(array, callback), 1);
}
logOperation('flatMap', [1, 2, 3], array => flatMap(array, number => [number, number]));
{
  operation: 'flatMap',
  arrayBefore: [ 1, 2, 3 ],
  arrayAfter: [ 1, 2, 3 ],
  mutates: false,
  result: [ 1, 1, 2, 2, 3, 3 ]
}
const valuesGenerator = values([1, 2, 3, 4, 5]);
valuesGenerator.next(); // { value: 1, done: false }
function values(array) {
 const { length } = array;
function* createGenerator() {
   for (let index = 0; index < length; index += 1) {
     const value = array[index];
     yield value;
   }
 }
return createGenerator();
}
const keysGenerator = keys([1, 2, 3, 4, 5]);
keysGenerator.next(); // { value: 0, done: false }
function keys(array) {
 function* createGenerator() {
   const { length } = array;
for (let index = 0; index < length; index += 1) {
     yield index;
   }
 }
return createGenerator();
}
const entriesGenerator = entries([1, 2, 3, 4, 5]);
entriesGenerator.next(); // { value: [0, 1], done: false }
function entries(array) {
 const { length } = array;
function* createGenerator() {
   for (let index = 0; index < length; index += 1) {
     const value = array[index];
     yield [index, value];
   }
 }
return createGenerator();
}
点击更多...