思路:

  1. 判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
  2. 保存当前函数(调用对象)的引用,获取其余传入参数值。
  3. 创建一个函数返回
  4. 函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。

代码:

  1. Function.prototype._bind = function (context) {
  2. if (typeof this !== "function") {
  3. throw new TypeError("error")
  4. }
  5. let args = [...arguments].slice(1)
  6. let fn = this
  7. return function Fn() {
  8. // 观察一下bind执行时的环境
  9. console.log("this:", this);
  10. console.log("Fn:", Fn);
  11. console.log("this instanceof Fn ->", this instanceof Fn);
  12. // 如果说bind是作为构造函数执行,那么执行时,this指向构造出来的对象,所以使用instanceof判断
  13. return fn.apply(
  14. this instanceof Fn ? this : context,
  15. args.concat(...arguments)
  16. )
  17. }
  18. }

测试:

test1

  1. // 一般情况调用时
  2. let obj = {
  3. name: "mikasa"
  4. }
  5. let user = {
  6. getName(value) {
  7. console.log(value);
  8. console.log(this.name);
  9. }
  10. }
  11. let userFn = user.getName._bind(obj, 666)
  12. userFn()

image.png

this指向window,因为userFn()是在window中被调用

test2

  1. // 绑定this,并且自带参数
  2. function getList() {
  3. return Array.prototype.slice.call(arguments)
  4. }
  5. let list = getList._bind(null, 37)
  6. // 绑定后带上了37这个参数
  7. console.log(list(1, 2, 3));

image.png

test3

当绑定后作为构造函数使用

  1. var value = 2
  2. var foo = {
  3. value: 1
  4. }
  5. function bar(name, age) {
  6. this.habit = 'shopping'; // 因为此时this指向实例obj
  7. console.log(this.value);
  8. console.log(name);
  9. console.log(age);
  10. }
  11. var bindFoo = bar._bind(foo, 'daisy')
  12. var obj = new bindFoo('18');
  13. console.log(obj.habit);

image.png