Восприятие интервью, рукописное связывание, применение, вызов

внешний интерфейс

предисловие

Некоторое время назад было телефонное интервью. Я помню, что в нем был контент. Меня спрашивали о вещах, связанных с http. Я тайно почувствовал облегчение. Я дважды прочитал http-диаграмму, и знания в ней были в основном уточнены и записаны. .http?Это не так просто?

  balabala много говорил, от http до https до http2, и добавил некоторые http3 вещи.Балабала много говорил, полный уверенности.Кто знает вопрос может задать мне.

Интервьюер: http2 реализует мультиплексирование, почему нельзя мультиплексировать http1.x?
Я: Я сказал, потому что http1.x должен прийти по порядку.
Интервьюер: Да, но почему http1.x следовать за заказ?
Я: Эм... я не знаю об этом...
Интервьюер: HTTP/1.1 — это протокол, основанный на сегментации и разборе текста, и в нем нет порядкового номера. При мультиплексировании последовательность будет беспорядочной. HTTP2 использует метод кадра, что эквивалентно разрезанию на части. соответствующий серийный номер, поэтому возможно мультиплексирование.

Дело не в том, как этот вопрос, а в том, что этот вопрос заставил меня осознать, что мое исследование недостаточно глубоко, я должен знать, что это такое и почему это так. вчерашнее интервью. Подводя небольшой итог

текст

что это такое?

Подать заявку, вызов, связывание - все встроенные API для функций в JS. Вызов их может указать выполнение этого для функции, а также может передавать параметры.

как использовать?

//apply 
func.apply(thisArg, [argsArray])

//call
fun.call(thisArg, arg1, arg2, ...)

//bind
const newFun = fun.bind(thisArg, arg1, arg2, ...)
newFun()

Apply и call отличаются передачей параметров, но обе являются функциями, которые будут вызываться одновременно при вызове, но bind вернет функцию, связанную с this.

Нам нужно знать еще одну вещь, которая является указателем на this.

указатель на это

Направление this определяется при вызове функции, и его можно условно разделить на пять типов.

1. Привязка по умолчанию

Привязка по умолчанию обычно происходит в функции обратного вызова, и функция вызывается напрямую;

function test() {
    //严格模式下是undefined
    //非严格模式下是window
    console.log(this);
}
setTimeout(function () {
    //setTimeout的比较特殊
    //严格模式和非严格模式下都是window
    console.log(this);
});

arr.forEach(function () {
    //严格模式下是undefined
    //非严格模式下是window
    console.log(this);
});

2. Неявное связывание

Эту популярную мысль можно выразить одним предложением: тот, кто это называет, указывает на кого.

    const obj = {
        name:'joy',
        getName(){
            console.log(this); //obj
            console.log(this.name); //joy
        }
    };
    obj.getName();

3. Показать вызов привязки, применить, привязать

const obj1 = {
    name: 'joy',
    getName() {
        console.log(this); 
        console.log(this.name); 
    }
};

const obj2 = {
    name: 'sam'
};

obj1.getName.call(obj2); //obj2 sam
obj1.getName.apply(obj2); //obj2 sam
const fn = obj1.getName.bind(obj2);
fn();//obj2 sam

4. новая привязка

function Vehicle() {
    this.a = 2
    console.log(this);
}
new Vehicle(); //this指向Vehicle这个new出来的对象

5. Функция стрелки es6

Стрелочная функция es6 особенная.Этот стрелочной функции-это это родительской области, а не это вызова.Вы должны знать, что все первые четыре метода определяются во время вызова, то есть динамический, в то время как this стрелочной функции является статическим. Он определяется при объявлении. Это больше соответствует лексической области видимости js.

window.name = 'win';
const obj = {
    name: 'joy',
    age: 12,
    getName: () => {
        console.log(this); //其父作用域this是window,所以就是window
        console.log(this.name); //win 
    },
    getAge: function () {
        //通过obj.getAge调用,这里面this是指向obj
        setTimeout(() => {
            //所以这里this也是指向obj 所以结果是12
            console.log(this.age); 
        });
    }
};
obj.getName();
obj.getAge();

Поскольку есть 5 способов привязки этого, должен быть приоритетный порядок

Стрелочная функция -> новая привязка -> явный вызов привязки/привязка/применение -> неявная привязка -> привязка по умолчанию

Вывод прямо дан здесь, а заинтересованные друзья могут убедиться в этом сами

применить применить

Сначала реализуем применение

  1. Сначала расширьте метод на прототипе функции и получите 2 параметра,
Function.prototype.myApply = function (context, args) {

}
  1. Потому что если контекст не передать, this будет указывать на окно, и аргументы тоже будут отказоустойчивыми.
Function.prototype.myApply = function (context, args) {
    //这里默认不传就是给window,也可以用es6给参数设置默认参数
    context = context || window
    args = args ? args : []
}
  1. Вам нужно вспомнить пять способов привязки this Теперь пришло время привязать this к вызываемой функции. Привязка по умолчанию и new здесь определенно не используются, здесь неявная привязка используется для достижения явной привязки.
Function.prototype.myApply = function (context, args) {
    //这里默认不传就是给window,也可以用es6给参数设置默认参数
    context = context || window
    args = args ? args : []
    //给context新增一个独一无二的属性以免覆盖原有属性
    const key = Symbol()
    context[key] = this
    //通过隐式绑定的方式调用函数
    context[key](...args)
}
  1. Последний шаг — вернуть возвращаемое значение вызова функции и удалить атрибут в контексте, чтобы он не повлиял
Function.prototype.myApply = function (context, args) {
    //这里默认不传就是给window,也可以用es6给参数设置默认参数
    context = context || window
    args = args ? args : []
    //给context新增一个独一无二的属性以免覆盖原有属性
    const key = Symbol()
    context[key] = this
    //通过隐式绑定的方式调用函数
    const result = context[key](...args)
    //删除添加的属性
    delete context[key]
    //返回函数调用的返回值
    return result
}

Такое простое применение реализовано, могут быть какие-то граничные проблемы и неверные суждения, которые нужно дорабатывать, поэтому здесь мы не будем продолжать оптимизацию.

Теперь, когда применение реализовано, вызов также очень прост, в основном потому, что параметры не совпадают.

реализовать вызов

Просто перейдите к коду здесь

//传递参数从一个数组变成逐个传参了,不用...扩展运算符的也可以用arguments代替
Function.prototype.myCall = function (context, ...args) {
    //这里默认不传就是给window,也可以用es6给参数设置默认参数
    context = context || window
    args = args ? args : []
    //给context新增一个独一无二的属性以免覆盖原有属性
    const key = Symbol()
    context[key] = this
    //通过隐式绑定的方式调用函数
    const result = context[key](...args)
    //删除添加的属性
    delete context[key]
    //返回函数调用的返回值
    return result
}

реализовать привязку

Разница между bind и apply в том, что bind это функция связывания.Apply вызывается напрямую.На самом деле я хочу реализовать его тоже очень просто,то есть возвращает функцию,которая выполняет вышеуказанную операцию.Однако есть нужно судить о Point, потому что он возвращает новую функцию, учитывать использование New, а NEW имеет более высокий приоритет, поэтому необходимо судить о вызове New, и одна особенность заключается в том, что вызывается Bind, и новое поколение вновь созданной функции также может быть передано, эффект тот же, поэтому этот кусок должен быть обработан Поскольку приложение уже достигнуто, оно будет заимствовано здесь, а не заимствовано.

Function.prototype.myBind = function (context, ...args) {
    const fn = this
    args = args ? args : []
    return function newFn(...newFnArgs) {
        if (this instanceof newFn) {
            return new fn(...args, ...newFnArgs)
        }
        return fn.apply(context, [...args,...newFnArgs])
    }
}

Обо всех вышеприведенных реализациях можно судить немного больше, например, если вызов не является функцией, то она вернет или выкинет ошибку, я не буду здесь этим заниматься.

Выше приведена реализация apply, call, bind

конец

"Я споткнулся и столкнулся на пути обучения. Я надеюсь становиться все лучше и лучше и как можно скорее стать большой коровой. Думайте больше, обобщайте больше и больше практикуйтесь. Выработайте привычку учиться на протяжении всей жизни. Давай