new、apply、bind、call实现的底层逻辑

64 阅读2分钟

new、apply、bind、call实现的底层逻辑

思考

  1. 用什么样的思路可以实现 new 关键字
  2. apply、call、bind 这三个方法之间有什么区别?
  3. 怎样实现一个 apply 或者 call 的方法

new

new 关键字的主要作用 : 就是执行一个构造函数,返回一个实例对象,根据构造函数的情况,来确定是否可以接受参数的传递

function Person() {
  this.name = 'Jack'
}
const p = new Person()
console.log(p.name); // 'Jack'
 
function Person1() {
  this.name = 'Jack'
  return {
    age : 18
  }
}
const p1 = new Person1()
console.log(p1.name); // undefined
console.log(p1.age); // 18

const p2 = Person()
console.log(p2); // undefined

上述代码 new 关键词实际上进了四个步骤:

  1. 创建了一个新的对象
  2. 将构造函数的作用域赋給这个新对象(使this指向这个新对象)
  3. 执行构造函数中的代码(为这个新对象添加属性)
  4. 返回新对象

new 关键词执行之后总是会返回一个对象,要么是实例对象 要么是return语句指定的对象

apply & call & bind 原理介绍

==call== 、==apply== 和 ==bind== 是挂在Function 对象上的三个方法

调用这三个方法必须是一个函数

func.call(thisArg, p1, p2, ...)
func.aplly(thisArg, [p1, p2, ...])
func.bind(thisArg,p1,p2,...)

==call== 、==apply== 和 ==bind== 都可以改变函数内的this指向,但是用法有所不同,apply的第二个形参是数组的形式,call、bind调用后是立刻执行,bind是返回一个新的函数并不会立刻执行

const a = {
  name: 'jack',
  age: 18,
  getName: function(msg) {
    return msg + this.name
  }
}
const b = {
  name: 'lili',
}
console.log(a.getName('hi~ '));// hi~ jack
console.log(a.getName.call(b, 'hi~~'));// hi~~lili
console.log(a.getName.apply(b, ['hi~~~!']));// hi~~~!lili
const newfunc = a.getName.bind(b, 'hello ')
console.log(newfunc()); // hello lili

应用场景

  • ==判断数据类型 Object.prototype.toString 几乎可以判断所有类型的数据==
Object.prototype.toString.call('123')
  • ==类数组不是真正的数组,无法使用一些数组类型自带的方法,就得使用一些方法去借用数组的方法==

  • ==获取数组的最值==

    const arr = [1,2,41,2,1,-1,0,8,-99,76]
    const max = Math.max.apply(Math,arr)
    const min = Math.min.apply(Math, arr)
    console.log(max);
    console.log(min);
    
  • ==继承==

new的实现

==new被调用后大致做了哪几件事情==

  1. 让实例可以访问私有属性
  2. 让实例可以访问构造函数的原型所在原型链上的属性
  3. 构造函数返回的最后结果是引用数据类型
function _new(ctor, ...args) {
  if (typeof ctor !== 'function') {
    throw 'ctor must be a function'
  }

  const obj = new Object()
  obj.__proto__ = Object.create(ctor.prototype)
  const res = ctor.apply(obj, ...args)
  const isObj = typeof res === 'object' && res !== 'null'
  const isFunc = typeof of === 'function'
  return isObj || isFunc ? res : obj
}

call、apply的实现

Function.prototype.call = function(context,...args) {
  const context = context || window
  context.fn = this
  const res = eval('context.fn(...args)')
  delete context.fn
  return res
}

Function.prototype.apply = function(context,...args) {
  const context = context || window
  context.fn = this
  const res = eval('context.fn(...args)')
  delete context.fn
  return res
}

bind的实现

Function.prototype.bind = function(context, ...args) {
  if (typeof this !== 'function') {
    throw 'this must be a function'
  }
  const self = this
  const found = function() {
    self.apply(this instanceof self ? this : context,
    args.concat(Array.prototype.slice.call(arguments))
    )
  }
  if (this.prototype) {
    found.prototype = Object.create(this.prototype)
  }
  return found
}

总结

10.png