new 运算符

new 运算符原理
  1. 创建一个全新的对象
  2. 为新创建的对象添加 __proto__ 属模拟实现 new 运算符性并指向构造函数的原型对象
  3. 将新创建的对象作为函数调用的 this
  4. 如果构造函数没有返回对象类型,则返回新创建的对象
模拟实现 new 运算符

instanceof 运算符

instanceof 运算符原理

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

模拟实现 instanceof 运算符

Object.create()

Object.create()

Object.create() 方法创建一个新对象,使用现有的对象来提供新创建的对象的 __proto__

模拟实现 Object.create()

Object.create() —— MDN

Function.prototype.call()

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数

模拟实现 Function.prototype.call()

@tab es6

1Function.prototype.myCall = function (context, ...args) {
2  // 在非严格模式下,传入的 context 为 null 或 undefined 时会自动替换为全局对象
3  // 因此在判断时不能使用 context = context || window
4  if (context == null) {
5    context = window;
6  }
7  // 原始值需要被 Object 包装成对象
8  else {
9    context = Object(context);
10  }
11
12  context.fn = this;
13
14  // 获取 fn 函数调用的返回值
15  const result = context.fn(...args);
16
17  delete context.fn;
18
19  return result;
20};
21
22function get(params) {
23  console.log(this, params);
24
25  return '这是返回值';
26}
27
28const obj = {
29  name: 'h7ml',
30  age: 18,
31};
32
33console.log(`call :>> `, get.call(obj, 'call'));
34console.log(`myCall :>> `, get.myCall(obj, 'myCall'));

@tab es6

1Function.prototype.myCall = function (context) {
2  // 在非严格模式下,传入的 context 为 null 或 undefined 时会自动替换为全局对象
3  // 因此在判断时不能使用 context = context || window
4  if (context == null) {
5    context = window;
6  }
7  // 原始值需要被 Object 包装成对象
8  else {
9    context = Object(context);
10  }
11
12  // 获取调用 call 的函数
13  context.fn = this;
14
15  // 获取传入的参数
16  var args = [];
17  // arguments 是类数组对象,可以使用 for 循环
18  for (var i = 1, len = arguments.length; i < len; i++) {
19    args.push('arguments[' + i + ']');
20  }
21
22  /**
23   * 获取 fn 函数调用的返回值
24   * 此时 args 为 ['arguments[1]', 'arguments[2]', 'arguments[3]']
25   * 但在执行时 args 会自动调用 Array.toString() 转化为 context.fn(arguments[1], arguments[2], arguments[3])
26   **/
27  var result = eval('context.fn(' + args + ')');
28
29  // 删除 fn 函数
30  delete context.fn;
31
32  // 将 fn 函数的返回值返回
33  return result;
34};

Function.prototype.apply()

apply() 方法调用一个具有给定 this 值的函数,以及以一个数组(或类数组对象)的形式提供的参数

Function.prototype.apply()#javascript @tab es6
1/** ES6 实现 **/
2Function.prototype.myApply = function (context, arr) {
3  // 在非严格模式下,传入的 context 为 null 或 undefined 时会自动替换为全局对象
4  // 因此在判断时不能使用 context = context || window
5  if (context == null) {
6    context = window;
7  }
8  // 原始值需要被 Object 包装成对象
9  else {
10    context = Object(context);
11  }
12
13  context.fn = this;
14
15  // 获取函数调用的返回值
16  const result = arr ? context.fn(...arr) : context.fn();
17
18  delete context.fn;
19
20  return result;
21};
22
23function get(params) {
24  console.log(this, params);
25
26  return '这是返回值';
27}
28
29const obj = {
30  name: 'h7ml',
31  age: 18,
32};
33
34console.log(`apply :>> `, get.apply(obj, ['apply']));
35console.log(`myApply :>> `, get.myApply(obj, ['myApply']));

@tab es5

1/** ES5 实现 **/
2Function.prototype.myApply = function (context, arr) {
3  // 在非严格模式下,传入的 context 为 null 或 undefined 时会自动替换为全局对象
4  // 因此在判断时不能使用 context = context || window
5  if (context == null) {
6    context = window;
7  }
8  // 原始值需要被 Object 包装成对象
9  else {
10    context = Object(context);
11  }
12
13  // 获取调用 apply 的函数
14  context.fn = this;
15
16  // 获取 fn 函数调用的返回值
17  var result;
18  if (arr) {
19    // 获取传入的参数
20    var args = [];
21    for (var i = 0, len = arr.length; i < len; i++) {
22      args.push('arr[' + i + ']');
23    }
24
25    result = eval('context.fn(' + args + ')');
26  }
27  // 没有参数直接调用
28  else {
29    result = context.fn();
30  }
31
32  // 删除 fn 函数
33  delete context.fn;
34
35  // 将 fn 的返回值返回
36  return result;
37};

Function.prototype.bind()

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数供调用时使用。

模拟实现 Function.prototype.bind()#javascript @tab es6
1/** ES6 实现 **/
2Function.prototype.myBind = function (context, ...args) {
3  if (typeof this !== 'function') {
4    throw new TypeError('not a function');
5  }
6
7  const self = this;
8
9  return function F(...fArgs) {
10    const params = [...args, ...fArgs];
11    // 当作为构造函数时
12    if (this instanceof F) {
13      return new self(...params);
14    }
15
16    // 当作为普通函数时,将函数的 this 指向 context
17    return self.apply(context, params);
18  };
19};

@tab es5

1/** ES5 实现 **/
2Function.prototype.myBind = function (context) {
3  if (typeof this !== 'function') {
4    throw new Error('not a function');
5  }
6
7  // 获取调用 bind 的函数
8  var self = this;
9
10  // 获取除了 thisArg 外的剩余参数(第二个到最后一个)
11  var args = Array.prototype.slice.call(arguments, 1);
12
13  var fNOP = function () {};
14  var fBound = function () {
15    // 获取返回函数的参数
16    var bindArgs = Array.prototype.slice.call(arguments);
17    return self.apply(
18      // 当作为构造函数时,将绑定函数的 this 实例指向实例
19      // 当作为普通函数时,将绑定函数的 this 指向 context
20      this instanceof fNOP ? this : context,
21      args.concat(bindArgs)
22    );
23  };
24
25  // 存在原型时,修改返回函数的 prototype 为绑定函数的 prototype,使实例可以继承绑定函数原型中的值
26  var prototype = self.prototype;
27  if (prototype) {
28    fNOP.prototype = prototype;
29  }
30
31  fBound.prototype = new fNOP();
32  return fBound;
33};

工具方法系列

debounce 函数防抖

函数防抖

作用: 一个函数在一段时间内多次触发都只执行最后一次 原理: 利用定时器,在函数第一次执行时设定一个定时器,再次调用时如果已经设定过定时器就清空之前的定时器并设定一个新的定时器,当定时器结束后执行传入的回调函数 应用: 搜索输入框获取用户输入的联想结果

实现防抖函数

throttle 函数节流

函数节流

作用: 函数节流指指的是在一段时间内只允许函数执行一次 (例如 3 秒执行一次那么在函数第一次调用后的 3 秒内后面的函数调用将被忽略) 原理: 利用时间戳来判断,记录上次执行的时间戳,在每次触发事件时判断当前时间是否大于上次执行的时间 + 设置的间隔 ,如果是则执行回调并更新上次执行的时间戳 应用: 降低 scroll resize 事件的触发频率

实现节流函数