Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polyfill #29

Open
kangkai124 opened this issue Jul 1, 2019 · 2 comments
Open

Polyfill #29

kangkai124 opened this issue Jul 1, 2019 · 2 comments
Labels

Comments

@kangkai124
Copy link
Owner

kangkai124 commented Jul 1, 2019

实现bind要做什么

  1. 返回一个函数,绑定this,传递预置参数
  2. bind返回的函数可以作为构造函数使用。故作为构造函数时应使得this失效,但是传入的参数依然有效
if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
      // closest thing possible to the ECMAScript 5 internal IsCallable function
      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var aArgs = Array.prototype.slice.call(arguments, 1),
      fToBind = this,
      fNOP = function () { },
      fBound = function () {
        // this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用
        return fToBind.apply(this instanceof fBound
          ? this
          : oThis || window,
          aArgs.concat(Array.prototype.slice.call(arguments)));
      };

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();

    return fBound;

  };

}

第一个是参数,agruments的使用

 var aArgs = Array.prototype.slice.call(arguments, 1)

这里是将bind函数的参数数组取出来,第一个参数不要(就是不要oThis)也就是要被绑定方法的那个对象,第二个是

aArgs.concat(Array.prototype.slice.call(arguments)))

这里是用了数组的方法,把参数插在参数数组后面,要注意,这个函数是要被return 出去然后执行的,他的参数数组是return出去的那个fBound函数的参数数组,所以上下两个参数数组是不一样的,有点像柯里化。

第二个是上下文,在其中上下文的变化比较难理解,bind函数主要就是为了绑定上下文来使用的

fToBind = this

这里是保存了对象的上下文,紧接着下面的apply方法让要被绑定的那个对象可以使用该上下文

fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();

这里是以fNOP为中介把this.prototype这个原对象的属性给fBound,确保fBound是在定义的时候的那个上下文里面执行。本来

bound.prototype = self.prototype

就可以将原属性集成过来了,但是这样两个对象属性都指向同一个地方,修改 bound.prototype 将会造成self.prototype 也发生改变,这样并不是我们的本意。所以通过一个空函数 nop 做中转,能有效的防止这种情况的发生。

@kangkai124 kangkai124 changed the title bind polyfill olyfill Jul 5, 2019
@kangkai124 kangkai124 changed the title olyfill Polyfill Jul 5, 2019
@kangkai124
Copy link
Owner Author

call

Function.prototype.$call = function () {
      let [thisArg, ...args] = [...arguments]
      if (!thisArg) {
        thisArg = typeof window === 'undefined' ? global : window
      }
      thisArg.func = this
      let result = thisArg.func(...args)
      Reflect.deleteProperty(thisArg, 'func')
      return result
    }

    function func1 () {
      return this.value
    }

    let obj = {
      value: 2
    }

    let res = func1.$call(obj)
    console.log(res); // 2

image

@kangkai124 kangkai124 added the JS label Jul 17, 2019
@kangkai124
Copy link
Owner Author

对于bind返回的函数做构造函数使用时:

Function.prototype.$bind = function (oThis) {
  var aArgs = Array.prototype.slice.call(arguments, 1),
    fToBind = this,
    fNOP = function () { },
    fBound = function () {
      console.log(this instanceof fBound);  // true
      return fToBind.apply(this instanceof fBound
        ? this
        : oThis,
        aArgs.concat(Array.prototype.slice.call(arguments)))
    }


  fNOP.prototype = this.prototype
  fBound.prototype = new fNOP()

  return fBound
}


function func1(a, b) {
  this.aaa = a
  this.say = function () {
    console.log('say ===> ', a);
  }
}

let obj = {
  value: 2
}

let func2 = func1.$bind(obj, 'aaa', 'bbb')
let res = new func2()
res.say()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant