написать впереди
Как начинающий осадный лев переднего плана, необходимо освоить несколько продвинутых навыков программирования. Изучение этих навыков сделает нашу работу по разработке более эффективной и сделает нашу работу более комфортной. В этой статье будут представлены три совета:
-
Применение функций ленивой загрузки
-
Применение функции каррирования
-
выравнивание функции составления вызова
функции ленивой загрузки
В нашем коде должно быть многоif
предложения, этиif
Выполнение оператора занимает некоторое время. Возникает ситуация, когда мы впервые входим вif
В ветке выполняется эта часть кода, а затем эта же ветка выполняется второй раз, поэтому эта часть кода будет выполняться снова. В этом случае выполнение кода определенно будет медленнее, поэтому, если мы позволим коду иметь только одинif
Branch, код будет выполняться быстрее. Если вы заставляете код выполняться быстрее, это применение функций ленивой загрузки.DOM
Пример привязки события:
function emit(element, type, func) {
if(element.addEventListener) {
element.addEventListener(type, func, false)
} else if(element.attachEvent) { // IE6、7、8
element.attachEvent("on" + type, func)
} else {
element["on" + type] = func;
}
}
В приведенном выше примере, чтобы определить, поддерживает ли браузер каждый метод, введите разные ветки для связывания событий разными способами. Если вы выполните привязку несколько раз, вы войдете в одно и то жеif
Код выполнения ветки, фактически, в одной и той же среде браузера, привязывается несколько раз, нужно судить только один раз, чтобы выполнить цель. Поэтому вам нужно применить функцию ленивой загрузки в это время.
function emit(element, type, func) {
if(element.addEventListener) {
emit = function(element, type, func) {
element.addEventListener(type, func, false)
}
} else if(element.attachEvent) {
emit = function(element, type, func) {
element.attachEvent("on" + type, func)
}
} else {
emit = function(element, type, func) {
element["on" + type] = func;
}
}
emit(element, type, func);
}
В оптимизированном коде после первого выполнения входит ветку для выполнения этой части кода, функцияemit
будет переназначен, что гарантирует наличие только одного вызова для нескольких вызововif
Execute, выполнение кода становится быстрее.
Применение функции каррирования
Для каррирования функций наиболее популярно понимание: большая функция возвращает маленькую функцию В «Продвинутом программировании на JavaScript» каррирование функций объясняется следующим образом:Темой, тесно связанной с привязкой функций, является каррирование функций, которое используется для создания функций с одним или несколькими уже установленными параметрами. Основной подход к каррированию функций такой же, как и к связыванию функций: используйте замыкание для возврата функции.Сначала рассмотрим пример:
function add(num1, num2) {
return num1 + num2;
}
function curried(num2) {
return add(5, num2);
}
console.log(curried(2)); // 7
Этот код имеет две функции,add
Функция возвращает сумму двух параметров,curried
Функция вернула вызовadd
после функции5
и сумма полученных аргументов. этоcurried
Функция — это то, что мы называем большой функцией, которая возвращает маленькую функцию, но это не каррированная функция.
Каррированные функции обычно создаются динамически: вызовите другую функцию и передайте ей каррируемую функцию и необходимые параметры.Далее общий способ написания каррированной функции
function curry(fn) {
var args = Array.prototype.slice.call(arguments, 1); // 获取第一个参数之后的参数
return function() {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(null, finalArgs); // 执行传入函数fn
}
}
function add(num1, num2) {
return num1 + num2;
}
console.log(curry(add, 5, 12)()); // 17
console.log(curry(add, 6, 7)()); // 13
Каррирующие функции также можно использовать для построенияbind()
в функции
/**
* @params
* fn: 要执行的函数
* context: 需要改变的this指向
*/
function bind(fn, context) {
context = context || window; // 如果没传context参数,就让其为window
var args = Array.prototype.slice.call(arguments, 2); // 获取第二个参数之后的参数
return function() {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(context, finalArgs);
}
}
Взгляните на эффект:
var obj = {
x: 1
}
function fn() {
return this.x + 2;
}
btn.onclick = function() {
console.log(bind(fn, obj)()) // 3
}
bind
функция будет успешнойthis
Укажите на Изменено наobj
. Но мы хотим назвать время иFunction
на прототипеbind
Мол, мы напишем свойbind
написано в прототипе
(function(proto) {
function bind(context) {
context = context || window; // 如果没传context参数,就让其为window
var args = Array.prototype.slice.call(arguments, 1); // 获取第二个参数之后的参数
return function() {
var innerArgs = Array.prototype.slice.call(arguments);
var finalArgs = args.concat(innerArgs);
return fn.apply(context, finalArgs);
}
}
proto.bind = bind;
})(Function.prototype)
Давайте посмотрим на эффект
var obj = {
x: 1
}
function fn(y) {
return this.x + y;
}
btn.onclick = function() {
console.log(fn.bind(obj, 3)()) // 4
}
Выше приведена функция приложения, каррирующая рукописную реализацию.bind
. Кроме того, некоторый исходный код также использует каррирование функций, напримерredux
Ждать.
Теперь давайте посмотрим на вопрос интервью: Реализацияadd
функция
add(1); //1
add(1)(2); //3
add(1)(2)(3); //6
add(1)(2,3); //6
add(1,2)(3); //6
add(1,2,3); //6
function currying(anonymous, length) {
return function add(...args) { // 返回add,接收参数...args
// 如果接收的参数长度大于函数参数的个数,则直接执行接收函数
if (args.length >= length) {
return anonymous(...args);
}
// 否则,递归调用currying,返回新的anonymous函数和新的length
return currying(anonymous.bind(null, ...args), length - args.length);
}
}
// count参数为传进参数的总个数,每次调用此函数时都需要修改
let add = currying(function anonymous(...args) {
return args.reduce((x, y) => x + y);
}, count);
Давайте посмотрим на эффект:
console.log(add(1)); // 修改count参数为1, 输出结果为1
console.log(add(1)(2)); // 修改count参数为2, 输出结果为3
console.log(add(1)(2)(3)); // 修改count参数为3, 输出结果为6
console.log(add(1)(2,3)); // 修改count参数为3, 输出结果为6
console.log(add(1,2)(3)); // 修改count参数为3, 输出结果为6
console.log(add(1,2,3)); // 修改count参数为3, 输出结果为6
console.log(add(5, 6, 7, 8)) // 修改count参数为4, 输出结果为26
В общем, мы закончилиadd
Написание функций, не обязательно есть только одно решение проблемы, это одна и та же проблема, есть много решений, добро пожаловать на обсуждение в области комментариев~
выравнивание функции составления вызова
Раньше мы слышали о выравнивании массива. Сведение массива — это преобразование многоуровневого массива в один слой. Точно так же сведение функции вызова — преобразование функции вызова глубокого уровня в один слой. Давайте рассмотрим пример.
var fn1 = function(x) {
return x + 5;
}
var fn2 = function(x) {
return x + 6;
}
var fn3 = function(x) {
return x + 7;
}
console.log(fn3(fn2(fn1(5)))); // 23
В приведенном выше примере функцияfn1
Возвращаемый результат передаетсяfn2
, а потомfn2
Возвращаемый результат передаетсяfn3
, окончательный выводfn3
результат. Такие слои вложенных вызовов выглядят не так удобно и не так удобны в использовании, поэтому мы хотим этого добитьсяcompose
функция:
compose(fn1, fn2, fn3)(5) // 等价于fn3(fn2(fn1(5)))
Приступаем к реализации:
function compose() {
var funcs = Array.prototype.slice.call(arguments);
return function() {
var args = Array.prototype.slice.call(arguments);
var len = funcs.length;
if(len === 0){
return args[0];
}
if(len === 1) {
return funcs[0](...args)
}
return funcs.reduce(function(x, y) {
return typeof x === "function" ? y(x(...args)) : y(x)
})
}
}
Взгляните на эффект:
console.log(compose(fn1, fn2, fn3)(5)); // 23
console.log(compose(fn1)(5)); // 10
console.log(compose()(5)); // 5
Выходные результаты согласуются с нашими ожидаемыми результатами, указывая на то, что мы инкапсулировалиcompose
функция правильная. ноcompose
Это не единственный способ инкапсуляции функций, давайте посмотримredux
серединаcompose
функция
export default function compose(...funcs) {
if (funcs.length === 0) { // 当传入的函数个数为0时,直接返回参数
return arg => arg
}
if (funcs.length === 1) { // 当传入函数个数为1时,直接执行函数
return funcs[0]
}
// 当传入函数个数不为0和1时,按函数传入从后向前的顺序依次执行函数
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
Оба пути могут быть достигнутыcompose
Функция, первый способ выглядит простым для понимания ~ второй способ выглядит проще, что также требует от нас серьезного обдумывания логики ее выполнения, улучшения наших мыслительных способностей и позволяет нам писать лучший код ~
наконец
Продвинутые навыки программирования обязательны при разработке, а овладение ими еще более полезно.Если вы считаете, что статья полезна для вас, вы можете поставить ей лайк.Если в статье что-то не так, я надеюсь, вы укажете на это из. Давайте учиться вместе. , добиваться прогресса вместе
Наконец, поделитесь моим публичным аккаунтом «веб-дневник фронтенда» ~ вы можете обратить внимание на волну ~