Функция ручной привязки JS

JavaScript

1. Тема

  • 1. Известно, что func.bind(context, 1, 2)(3, 4) в ES5 эквивалентен func.call(context, 1, 2, 3, 4) Пожалуйста, реализуйте связывание полифилла с ES3

На фронтенд-интервью часто задают вопрос о разнице между методами call, apply и bind?

  • call: fn.call(context, 1, 2, 3, 4)
  • apply: fn.apply(context, [1, 2, 3, 4])
  • bind: fn.bind(context, 1, 2)(3, 4)

context为this的指向, 以上三种方法执行的结果一致,call、apply两者的区别就是传参方式的不同,而bind方法执行结果返回的是一个未执行的方法,执行时可以继续传入参数,实现了函数的柯里化,提高参数的复用

Во-вторых, процесс реализации

Function.prototype.myBind = function (context = window) { // 原型上添加mybind方法
   // var args = Array.from(arguments) // 类数组转数组(es6) console.log(args instanceof Array)
   var argumentsArr = Array.prototype.slice.call(arguments) // 类数组转数组
   var args = argumentsArr.slice(1) // 后面的参数
   var self = this // 调用的方法本身
   return function () { // 返回一个待执行的方法
       var newArgs = Array.prototype.slice.call(arguments) // 返回函数的arguments,类数组转数组或者使用es6解构赋值
       self.apply(context, args.concat(newArgs)) // 合并两args
   }
}

3. Результаты испытаний

//  测试
var name = 'window name'
var obj = {
    name: 'obj name',
}
var fn = function () {
    console.log(this.name, [...arguments])
}
fn(1, 2, 3, 4) // 直接执行,this指向window
fn.myBind(obj, 1, 2)(3, 4) // mybind改变this指向
fn.bind(obj, 1, 2)(3, 4) // 原生bind

// 以上执行结果如下:
// window name [1, 2, 3, 4]
// obj name [1, 2, 3, 4]
// obj name [1, 2, 3, 4]

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

Function.prototype.MyBind = function(context){
    var self = this
    var args = Array.prototype.slice.call(arguments, 1)
    var temp = function () {}
    var fn = function () {
        var newArgs = Array.prototype.slice.call(arguments)
        // 如果被new调用,this应该是fn的实例
        return self.apply(this instanceof fn ? this : (context || window), args.concat(newArgs) )
    }
    // 维护fn的原型
    temp.prototype = self.prototype
    fn.prototype = new temp()
    return fn
}