Анализ исходного кода API массива JS

внешний интерфейс исходный код JavaScript Underscore.js

Это"JS на простом языке"Часть конспекта лекций к уроку 8

Основное содержание сегодняшнего урока

  1. Реализация семи API для массивов
  2. Как читать исходный код Underscore (функция throttling и anti-shake, дедупликация массива видны в исходном коде)

join

Начнем с простейших операций с массивами:

var array = ['a','b','c']
array.join('-') // 结果是 'a-b-c'

Нарисуем карту памяти:

内存分图

  1. array.join на самом деле является соответствующей функцией Array.prototype.join (array.join === Array.prototype.join === ADDR401)
  2. array.join('-') эквивалентен array.join.call(array, '-')
  3. Функция соединения может получить два значения массива и '-' через this и arguments[0]

Таким образом, мы можем смело предположить, что исходный код array.join, вероятно, такой

Array.prototype.join = function(char){
  let result = this[0] || ''
  let length = this.length
  for(let i=1; i< length; i++){
      result += char + this[i]
  }
  return result
}

это массив, потому что вы использовали array.join('-') для вызова соединения (которое неявно указывает это)

slice

Далее изучите вторую операцию массива

array.slice(beginIndex, endIndex)

Очевидно, легко догадаться, исходный код, вероятно, такой

Array.prototype.slice = function(begin, end){
    let result = []
    begin = begin || 0
    end = end || this.length
    for(let i = begin; i< end; i++){
        result.push(this[i])
    }
    return result
}

Так много интерфейсов используют слайсы для преобразования псевдомассивов в массивы.

array = Array.prototye.slice.call(arrayLike)
或者
array = [].slice.call(arrayLike)

ES 6 не выдерживает этого дрянного метода конвертации и имеет новый API

array = Array.from(arrayLike)

Специально используется для преобразования псевдомассивов в реальные массивы.

P.S. Отличие псевдомассива от реального массива в том, что в цепочке прототипов псевдомассива нет Array.prototype, а в цепочке прототипов реального массива есть Array.prototype. Таким образом, псевдомассивы не имеют таких свойств, как pop, join и т. д.

sort

Я слышал, что метод сортировки, встроенный в большинство языков, представляет собой алгоритм быстрой сортировки. Упростим его до сортировки выбором.

Array.prototype.sort = function(fn){
    fn = fn || (a,b)=> a-b
    let roundCount = this.length - 1 // 比较的轮数
    for(let i = 0; i < roundCount; i++){
        let minIndex = this[i]
        for(let k = i+1; k < this.length; k++){
            if( fn.call(null, this[k],this[i]) < 0 ){
                [ this[i], this[k] ] = [ this[k], this[i] ]
            }
        }
    }
}

fn.call(null, this[k], this[i]) определяет отношение до и после (величина) между элементом k и элементом i.

Что означает fn для (a,b) => a-b? fn is (a,b) => b-a Что это значит?

Это не имеет значения, потому что если первое не соответствует вашим потребностям, то второе должно удовлетворить ваши потребности.Вам нужно только попробовать оба, чтобы узнать, какой из них использовать.

forEach, отображать, фильтровать и уменьшать

Array.prototype.forEach = function(fn){
    for(let i=0;i<this.length; i++){
        if(i in this){
            fn.call(undefined, this[i], i, this)
        }
    }
}

Есть два основных различия между forEach и for:

  1. forEach не может сломаться
  2. forEach использует функции, поэтому каждая итерация будет иметь новую область видимости функции, в то время как циклы for имеют только одну область видимости (это исследуется в известном вопросе интервью с фронтендом).
Array.prototype.map = function(fn){
    let result = []
    for(let i=0;i<this.length; i++){
        if(i in this) {
            result[i] = fn.call(undefined, this[i], i, this)
        }
    }
    return result
}

Функции map и forEach похожи, разница только в возвращаемом значении. Далее идет фильтр

Arra.prototype.filter = function(fn){
    let result = []
    let temp
    for(let i=0;i<this.length; i++){
        if(i in this) {
            if(temp = fn.call(undefined, this[i], i, this) ){
                result.push(this[i])
            }
        }
    }
    return result
}

Если fn.call() возвращает истинное значение, нажимает на возвращаемое значение, а если не возвращает истинное значение, не нажимает. Далее идет уменьшение

Arra.prototype.reduce = function(fn, init){
    let result = init
    for(let i=0;i<this.length; i++){
        if(i in this) {
            result = fn.call(undefined, result, this[i], i, this)
        }
    }
    return result
}

Разница между картой, фильтром и уменьшением:

区别

Подключение карты, фильтра и уменьшения:

  1. карта может быть представлена ​​сокращением
    array2 = array.map( (v) => v+1 )
    可以写成 
    array2 = array.reduce( (result, v)=> {
        result.push(v + 1)
        return result
    }, [ ] )
    
  2. фильтр может быть представлен сокращением
    array2 = array.filter( (v) => v % 2 === 0 )
    可以写成
    array2 = array.reduce( (result, v)=> {
        if(v % 2 === 0){ result.push(v) }
        return result
    }, [])
    

Underscore.js

Underscore — это библиотека для работы с множествами (в то время в JS не было Set, поэтому множество относится к массивам и объектам). Существует шесть основных типов API:

  1. API коллекции
  2. API-интерфейс массива
  3. API объекта
  4. Функциональный API
  5. Разное API
  6. цепная операция

Подчеркивание рекомендаций по чтению исходного кода

  1. Найдите аннотированный подчеркиванием исходный код, нажмите
  2. Найдите интересующие вас API, например _.uniq.
  3. Посмотрите на код, просматривая документацию

Последующие лекции требуют платного просмотра. Есть также два классических вопроса интервью после занятий.

Добро пожаловать на покупкуJS на простом языке".