«Интервью должно быть выполнено» рукописные 35 высокочастотных вопросов интервью JS (1)

JavaScript
«Интервью должно быть выполнено» рукописные 35 высокочастотных вопросов интервью JS (1)

предисловие

Во время собеседований часто задают некоторые «рукописные XXX» вопросы интервью.Если мы только владеем этими API, мы всегда должны быть беспомощны, чтобы задавать такие вопросы. На самом деле реализовать рукописный API несложно, но нужно больше тренироватьсяРазорвать реализацию с помощью的能力,千万不要死记硬背。 В последнее время я также совершенствую свои навыки рукописного API, и я обобщил вопросы собеседования по рукописному API, которые часто используются на собеседованиях. Надеюсь, это будет полезно для всех~

Чтобы просмотреть полный код, нажмите:GitHub.com/Ци Руохан/AR…

1. Реализовать вызов/применить

  • Функции:
  1. Можно изменить указатель текущей функции этим
  2. заставить текущую функцию выполняться
  • Применение:
function f1() {
  console.log(1);
}

function f2() {
  console.log(2);
}

// 让 f1 的 this 指向 f2,并且让 f1 执行
f1.call(f2);  // 1

// 如果多个 call,会让 call 方法执行,并把 call 中的 this 指向改变成 fn2
f1.call.call.call(f2);
  • выполнить:
Function.prototype.call = function (context) {
  // 如果 context 存在,使用 context,如果 context 不存在,使用 window;如果 context 是普通类型,转成对象。
  context = context ? Object(context) : window;
  context.fn = this;
  let args = [];
  for(let i = 1; i < arguments.length; i++) {
    args.push('arguments['+i+']');
  }

  let r = eval('context.fn('+args+')');
  delete context.fn;
  return r;
}

Function.prototype.apply = function (context, args) {
  // 如果 context 存在,使用 context,如果 context 不存在,使用 window;如果 context 是普通类型,转成对象。
  context = context ? Object(context) : window;
  context.fn = this;

  if(!args){
    return context.fn();
  }

  let r = eval('context.fn('+args+')');
  delete context.fn;
  return r;
}

2. Реализуйте метод привязки

  • Функции:
  1. Метод bind может связать это, чтобы указать на
  2. Метод bind возвращает связанную функцию
  3. Если связанная функция новая, this текущей функции является текущим экземпляром
  4. Новый экземпляр должен гарантировать, что свойства объекта-прототипа исходной функции не могут быть потеряны.
  • Применение:
// 用法一:
let person = {
  name: "Cherry",
}

function fn(name, age) {
  console.log(this.name+ '养了一只'+ name + '今年' + age + '了'); // Cherry养了一只猫今年2了
}

let bindFn = fn.bind(person, '猫');

bindFn(2);

// 用法二:
let person = {
  name: "Cherry",
}

function fn(name, age) {
  this.say = '说话'
  console.log(this);  // fn {say: "说话"}
}

let bindFn = fn.bind(person, '猫');
let instance = new bindFn(9);

// 用法三:
let person = {
  name: "Cherry",
}

function fn(name, age) {
  this.say = '说话'
}

fn.prototype.flag = '哺乳类';
let bindFn = fn.bind(person, '猫');
let instance = new bindFn(9);
console.log(instance.flag);
  • выполнить:
Function.prototype.bind = function (context) {
  // this表示调用bind的函数
  let that = this;
  let bindArgs = Array.prototype.slice.call(arguments, 1);  //["猫"]
  function Fn() {}
  function fBound() {
    let args = Array.prototype.slice.call(arguments);  //[9] 
    //this instanceof fBound为true表示构造函数的情况。如new bindFn(9);
    return that.apply(this instanceof fBound ? this : context, bindArgs.concat(args));
  }

  fn.prototype = this.prototype;
  fBound.prototype = new Fn();
  return fBound;
}

3. Внедрите новое ключевое слово

  • Функции:
  1. Создайте новый объект, __proto__ этого объекта должен указывать на объект-прототип конструктора.
  2. выполнить конструктор
  3. Возвращаемое значение типа объекта возвращается как возвращаемое значение нового метода, в противном случае возвращается указанный выше новый объект.
  • Применение:
// 用法一:
function Animal(type) {
  this.type = type;   // 实例上的属性
}

Animal.prototype.say = function () {
  console.log('say');
}

let animal = new Animal('哺乳类');

console.log(animal.type); // 哺乳类
animal.say(); // say

// 用法二:
function Animal(type) {
  this.type = type;   // 实例上的属性
  // 如果当前构造函数返回的是一个引用类型,需要直接返回这个对象
  return {name: 'dog'}
}

Animal.prototype.say = function () {
  console.log('say');
}

let animal = new Animal('哺乳类');

console.log(animal); // {name: "dog"}
  • выполнить:
function mockNew() {
  // Constructor => animal,剩余的 arguments 就是其他的参数
  let Constructor = [].shift.call(arguments);
  let obj = {};  //返回的结果
  obj.__proto__ = Constructor.prototype;
  let r = Constructor.apply(obj, arguments);
  return r instanceof Object ? r : obj;
} 

// 测试一下:
function Animal(type) {
  this.type = type;
}

Animal.prototype.say = function () {
  console.log('say');
}

let animal = mockNew(Animal, '哺乳类');

console.log(animal.type); // 哺乳类
animal.say(); // say

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

  • Функции:
  1. Перебрать массив и вернуть новый массив
  2. Функция обратного вызова получает всего 3 параметра, а именно: "значение текущего обрабатываемого элемента, индекс текущего обрабатываемого элемента и проходимый объект коллекции"
  • Применение:
let array = [1, 2, 3].map((item) => {
  return item * 2;
});

console.log(array);  // [2, 4, 6]
  • выполнить:
Array.prototype.map = function(fn) {
  let arr = [];
  for(let i = 0; i < this.length; i++) {
    arr.push(fn(this[i], i, this));
  }
  return arr;
};

В-пятых, используйте ES5 для реализации метода фильтрации массива.

  • Функции:
  1. Метод возвращает новый массив элементов, прошедших проверку, или пустой массив, если элементов, прошедших проверку, нет.
  2. Функция обратного вызова получает всего 3 параметра, как и метод карты. К ним относятся: «Значение текущего обрабатываемого элемента, индекс текущего обрабатываемого элемента, просматриваемый объект коллекции»
  • Применение:
let array = [1, 2, 3].filter((item) => {
  return item > 2;
});

console.log(array); // [3]
  • выполнить:
Array.prototype.filter = function(fn) {
  let arr = [];
  for(let i = 0; i < this.length; i++) {
    fn(this[i]) && arr.push(this[i]);
  }
  return arr;
};

6. Реализовать некоторые методы массивов с ES5

  • Функции:
  1. Найдите в элементе массива, если найти квалификационный элемент, возвращает true, если все элементы не имеют права возвращать false;
  2. Функция обратного вызова получает всего 3 параметра, как и метод карты. Это: «значение текущего обрабатываемого элемента, индекс текущего обрабатываемого элемента, просматриваемый объект коллекции».
  • Применение:
let flag = [1, 2, 3].some((item) => {
  return item > 1;
});

console.log(flag); // true
  • выполнить:
Array.prototype.some = function(fn) {
  for(let i = 0; i < this.length; i++) {
    if (fn(this[i])) {
      return true;
    }
  }
  return false;
};

Семь: используйте ES5 для реализации каждого метода массива.

  • Функции:
  1. Проверить, соответствуют ли элементы массива условиям, вернуть true, если все они соответствуют условиям, и вернуть false, если один из них не соответствует условиям.
  2. Если получен пустой массив, этот метод в любом случае вернет true
  3. Функция обратного вызова получает всего 3 параметра, как и метод карты. К ним относятся: «Значение текущего обрабатываемого элемента, индекс текущего обрабатываемого элемента, просматриваемый объект коллекции»
  • Применение:
let flag = [1, 2, 3].every((item) => {
  return item > 1;
});

console.log(flag); // false
  • выполнить:
Array.prototype.every = function(fn) {
  for(let i = 0; i < this.length; i++) {
    if(!fn(this[i])) {
      return false
    }
  }
  return true;
};

Во-вторых, используйте ES5 для реализации метода поиска массива.

  • Функции:
  1. Найти элемент в массиве, если он находит элемент, удовлетворяющий условию, он возвращает элемент, если нет элемента, удовлетворяющего условию, он возвращает неопределенное значение, и он не будет продолжать поиск после того, как он будет найден.
  2. Функция обратного вызова получает всего 3 параметра, как и метод карты. К ним относятся: «Значение текущего обрабатываемого элемента, индекс текущего обрабатываемого элемента, просматриваемый объект коллекции»
  • Применение:
let item = [1, 2, 3].find((item) => {
  return item > 1;
});

console.log(item); // 2
  • выполнить:
Array.prototype.find = function(fn) {
  for(let i = 0; i < this.length; i++) {
    if (fn(this[i])) return this[i];
  }
};

9. Реализуйте метод forEach массива с помощью ES5.

  • Функции:
  1. Цикл по массиву, метод не имеет возвращаемого значения
  2. Функция обратного вызова получает всего 3 параметра, как и метод карты. К ним относятся: «Значение текущего обрабатываемого элемента, индекс текущего обрабатываемого элемента, просматриваемый объект коллекции»
  • Применение:
[1, 2, 3].forEach((item, index, array) => {
  // 1 0 [1, 2, 3]
  // 2 1 [1, 2, 3]
  // 3 2 [1, 2, 3]
  console.log(item, index, array)  
});
  • выполнить:
Array.prototype.forEach = function(fn) {
  for(let i = 0; i < this.length; i++) {
    fn(this[i], i, this);
  }
};

10. Реализуйте метод сокращения массива с помощью ES5.

  • Функции:
  1. Специальная обработка, когда начальное значение не передано: по умолчанию будет использоваться первый элемент в массиве
  2. Возвращаемый результат функции будет использоваться как предыдущий в следующем цикле.
  3. Функция обратного вызова получает в общей сложности 4 параметра, а именно «значение, возвращаемое при последнем вызове обратного вызова, обрабатываемый элемент, индекс обрабатываемого элемента и просматриваемый объект коллекции».
  • Применение:
let total = [1, 2, 3].reduce((prev, next, currentIndex, array) => {
  return prev + next;
}, 0);

console.log(total); // 6
  • выполнить:
Array.prototype.reduce = function(fn, prev) {
  for(let i = 0; i < this.length; i++) {
    // 初始值不传时的处理
    if (typeof prev === 'undefined') {
      // 明确回调函数的参数都有哪些
      prev = fn(this[i], this[i+1], i+1, this);
      ++i;
    } else {
      prev = fn(prev, this[i], i, this)
    }
  }
  // 函数的返回结果会作为下一次循环的 prev
  return prev;
};

11. Реализуйте метод instanceof

  • Функции:

Просматривайте цепочку прототипов, пока не найдете самую вершину прототипа, т.Object.prototype. Определяет, появляется ли свойство прототипа конструктора в цепочке прототипов объекта экземпляра, и возвращает значение true, если оно найдено, и значение false, если не найдено.

  • Применение:
console.log([] instanceof Array); // true
console.log([] instanceof Object); // true

// 相当于:
console.log([].__proto__ === Array.prototype); // true
console.log([].__proto__.__proto__ === Object.prototype); // true
  • выполнить:
function myInstanceof(left, right) {
  left = left.__proto__;
  while(true) {
    if (left === null) {
      return false;
    }
    if (left === right.prototype) {
      return true;
    }
    left = left.__proto__;
  }
};

class A{};

const a = new A();
console.log(myInstanceof(a, A)); // true
console.log(myInstanceof(a, Object)); // true 
console.log(myInstanceof(a, Array)); // false

12. Реализуйте метод Object.create (часто тестируйте)

  • Функции:

Создайте новый объект, используя существующий объект, чтобы предоставить __proto__ вновь созданного объекта.

  • Применение:
let demo = {
    c : '123'
};
let cc = Object.create(demo);
console.log(cc);
  • выполнить:
function create(proto) {
    function Fn() {};
    // 将Fn的原型指向传入的 proto
    Fn.prototype = proto;
    Fn.prototype.constructor = Fn;
    return new Fn();
};

13. Реализуйте общую функцию каррирования

  • Функции:

Каррирование — это приложение, которое уточняет функцию функции, преобразует функцию, которая принимает «несколько параметров», в функцию, которая принимает «один параметр», и возвращает результат, который принимает «остальные параметры».

  1. Определить, достигают ли переданные параметры количества fn для выполнения функции
  2. Если вы не достигли, продолжайте возвращать новые функции, продолжайте возвращать функции FN и накапливайте оставшиеся параметры.
  3. Когда количество параметров fn достигнуто, передать накопленные параметры в fn для выполнения
  • Применение:
function sum(a, b, c, d, e) {
  return a+b+c+d+e;
};

let a = curring(sum)(1,2)(3,4)(5);
console.log(a); // 15
  • выполнить:
const curring = (fn, arr = []) => {
  let len = fn.length;
  return function (...args) {
    arr = [...arr, ...args];
    if (arr.length < len) {
      return curring(fn, arr);
    } else {
      return fn(...arr);
    }
  };
};

14. Реализуйте функцию защиты от каррирования

  • Функции:

использоватьcall,applyВы можете позволить немассам одолжить некоторые другие виды функций, такие как,Array.prototype.push.call, Array.prototype.slice.call,uncrryingОбобщите эти методы не только для массивов, но и для лучшей семантики.

  • Применение:
// 利用反柯里化创建检测数据类型的函数
let checkType = Object.prototype.toString.uncurring()

checkType(1); // [object Number]
checkType("hello"); // [object String]
checkType(true); // [object Boolean]
  • выполнить:
Function.prototype.uncurring = function () {
  var self = this;
  return function () {
    return Function.prototype.call.apply(self, arguments);
  }
};

15. Реализовать простую функцию дросселя (throttle)

  • Функции:

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

Дросселирование фокусируется на блокировкеflag = false

  • Сценарии применения:

    • прокрутить событие прокрутки, выполнить функцию обратного вызова для каждого конкретного описания
    • Введите поле ввода, отправьте запрос в определенное время или разверните раскрывающийся список, (также доступен анти-встряска)
  • Применение:

const throttleFn = throttle(fn, 300);
  • выполнить:
const throttle = (fn, delay = 500) => {
  let flag = true;
  return (...args) => {
    if (!flag) return;
    flag = false;
    setTimeout(() => {
      fn.apply(this, args);
      flag = true;
    }, delay);
  };
};

16. Реализуйте простую функцию устранения дребезга (debounce)

  • Функции:

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

Anti-shake фокусируется на очисткеclearTimeout(timer)

  • Сценарии применения:

    • Измените размер окна браузера, чтобы избежать слишком частого
    • Кнопки для входа в систему, текстовых сообщений и т. д. позволяют избежать отправки нескольких запросов
    • Текстовый редактор сохраняет в реальном времени
  • Применение:

const debounceFn = debounce(fn, 300);
  • выполнить:
const debounce = (fn, delay) => {
  let timer = null;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
};

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

17. Реализуйте композицию

  • Функции:

Требуется функциональная плитка, необходимая для исполнения NEST, и вложенное выполнение - это возвращаемое значение функции, будет параметром другой функции. Направление вызова функции справа налево (первая сумма выполнения, затем выполнить toupper, а затем выполнить Add)

  • Применение:
function sum(a, b) {
  return a+b;
}

function toUpper(str) {
  return str.toUpperCase();
}

function add(str) {
  return '==='+str+'==='
}

// 使用 compose 之前:
console.log(add(toUpper(sum('cherry', '27')))); // ===CHERRY27===
// 使用 compose 之后:
console.log(compose(add, toUpper, sum)('cherry', '27')); // ===CHERRY27===
  • выполнить:
// 使用 ES5- reduceRight 实现
function compose(...fns) {
  return function (...args) {
    let lastFn = fns.pop();
    return fns.reduceRight((a, b) => {
      return b(a);
    }, lastFn(...args));
  };
}

// 使用 ES6 - reduceRight 实现
const compose = (...fns) => (...args) => {
  let lastFn = fns.pop();
  return fns.reduceRight((a, b) => b(a), lastFn(...args));
};

// 使用 ES6 - reduce 一行代码实现:
const compose = (...fns) => fns.reduce((a, b) => (...args) => a(b(...args)));

18. Реализовать трубу

  • Функции:

Функция канала имеет ту же функцию, что и функция составления, и она также мозаично размещает параметры, но в порядке слева направо. (Сначала выполнить splitString, а затем считать)

  • Применение:
function splitString(str) {
  return str.split(' ');
}

function count(array) {
  return array.length;
}

// 使用 pipe 之前:
console.log(count(splitString('hello cherry'))); // 2
// 使用 pipe 之后:
console.log(pipe(splitString, count)('hello cherry')); // 2
  • выполнить:
const pipe = function(){
  const args = [].slice.apply(arguments);
  return function(x) {
    return args.reduce((res, cb) => cb(res), x);
  }
}

// 使用 ES5- reduceRight 实现
function pipe(...fns) {
  return function (...args) {
    let lastFn = fns.shift();
    return fns.reduceRight((a, b) => {
      return b(a);
    }, lastFn(...args));
  };
}

// 使用 ES6 - reduceRight 实现
const pipe = (...fns) => (...args) => {
  let lastFn = fns.shift();
  return fns.reduceRight((a, b) => b(a), lastFn(...args));
};

// 使用 ES6 - reduce 一行代码实现:(redux源码)
const pipe = (...fns) => (...args) => fns.reduce((a, b) => b(a), ...args);

Девятнадцать, внедрить механизм шаблонов

  • Особенности: с синтаксисом + конкатенация строк + новая функция для достижения
  1. Сначала вставьте в строку<%=%>Заменить, расшифровать полученную строку;
  2. повторное использованиеnew Functionспособ выполнить строку и использоватьwithРешить проблему масштаба.
  • Применение:
const ejs = require('ejs');
const path = require('path');

ejs.renderFile(path.resolve(__dirname, 'template.html'),{name: 'Cherry', age: 27, arr: [1, 2, 3]}, function(err, data) {
  console.log(data);
})

// ===== template.html =====
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <%=name%>  <%=age%>
  <%arr.forEach(item =>{%>
      <li><%=item%></li>
  <%})%>
</body>
</html>
  • выполнить:

мы используем{ {} }заменять<%=%>Тег для имитации реализации механизма шаблонов, принцип реализации тот же, основное внимание уделяется принципу реализации.

// ===== my-template.html =====
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  {{name}}  {{age}}
  {%arr.forEach(item => {%}
      <li>{{item}}</li>
  {%})%}
</body>
</html>
const fs = require('fs');
const path = require('path');

const renderFile = (filePath, obj, cb) => {
  fs.readFile(filePath, 'utf8', function(err, html) {
    if(err) {
      return cb(err, html);
    }

    html = html.replace(/\{\{([^}]+)\}\}/g, function() {
      console.log(arguments[1], arguments[2]);
      let key = arguments[1].trim();
      return '${' + key + '}';
    });

    let head = `let str = '';\r\n with(obj){\r\n`;
    head += 'str+=`';
    html = html.replace(/\{\%([^%]+)\%\}/g, function() {
      return '`\r\n' + arguments[1] + '\r\nstr+=`\r\n';
    });
    let tail = '`}\r\n return str;';
    let fn = new Function('obj', head + html + tail);
    cb(err, fn(obj));
  });
};

renderFile(path.resolve(__dirname, 'my-template.html'),{name: 'Cherry', age: 27, arr: [1, 2, 3]}, function(err, data) {
  console.log(data);
});

Статьи по Теме:Обязательный рукописный API для средних и старших интерфейсных инженеров (2)

о

Автор Ци Сяошэнь, фронтенд программы Юань.

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

Нет публики:Большое переднее пространство, обновляйте время от времени, добро пожаловать в игру~