js 基础
2023-12-07
JavaScript

for…in 和 for…of

for…in

用来遍历对象除了 Symbol 之外的可枚举属性,包括继承的属性,但不保证迭代顺序。

若不迭代原型链上的属性,可用 hasOwnProperty() 排除之。

for…of

用来遍历可迭代对象,包括 ArrayMapSetStringTypedArrayarguments

二者终止迭代:breakthrowreturn

原型链

js 的所有复杂类型均为 Object

声明一个对象时,该对象会包含一些预定义的属性,其中一个属性名为 prototype,即该对象的原型对象。该原型也有自己的原型,层层上查,直至原型 null,这一连串原型,即为原型链。

call apply bind

三者均可改变 this 指向。callapply 绑定并执行,bind 只绑定不执行。

callapply 有入参之别,前者依次传入之,后者合参数为数据转入之。

手写

思路

对象中方法内的 this 指向该对象,可将待绑定函数设置为对象的属性,则函数中的 this 就改为这个对象

const obj = {
  name: '张三'
}

function showName() {
  console.log(this.name)
}

// eslint-disable-next-line no-extend-native
Function.prototype.myCall = function (ctx, ...args) {
  ctx = ctx || window
  ctx.fn = this // this 为待绑定函数
  const result = ctx.fn(...args)
  delete ctx.fn
  return result
}

// eslint-disable-next-line no-extend-native
Function.prototype.myApply = function (ctx, args) {
  if (!Array.isArray(args)) {
    throw new TypeError('参数必须为数组')
  }
  ctx = ctx || window
  ctx.fn = this
  const result = ctx.fn([...args])
  delete ctx.fn
  return result
}

// eslint-disable-next-line no-extend-native
Function.prototype.myBind = function (ctx, ...args) {
  // eslint-disable-next-line @typescript-eslint/no-this-alias
  const fn = this
  return function F(...args2) {
    if (fn instanceof F) {
      // eslint-disable-next-line new-cap
      return new fn(...args, ...args2)
    }

    return fn.apply(ctx, [...args, ...args2])
  }
}