bind ๏ผ๐Ÿš”๐Ÿš๐Ÿš“๐Ÿš’

227 ้˜…่ฏป2ๅˆ†้’Ÿ

1. Polyfill ๐Ÿ‘๐Ÿ‘๐Ÿ‘๐Ÿ‘๐Ÿ‘๐Ÿ‘

// Does not work with `new funcA.bind(thisArg, args)`
if (!Function.prototype.bind) (function(){
  var slice = Array.prototype.slice;
  Function.prototype.bind = function() {
    var thatFunc = this, thatArg = arguments[0];
    var args = slice.call(arguments, 1);
    if (typeof thatFunc !== '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');
    }
    return function(){
      var funcArgs = args.concat(slice.call(arguments))
      return thatFunc.apply(thatArg, funcArgs);
    };
  };
})();

2. ๅ‘็”Ÿไบ†ไป€ไนˆ๏ผŸ๐Ÿ˜ฑ๐Ÿ˜ฑ๐Ÿ˜ฑ๐Ÿ˜ฑ๐Ÿ˜ฑ๐Ÿ˜ฑ

Does not work with new funcA.bind(thisArg, args)

3. ๅฐ้ฉฌ่ฟ‡ๆฒณ๏ผ๐Ÿ˜ณ๐Ÿ˜ณ๐Ÿ˜ณ๐Ÿ˜ณ๐Ÿ˜ณ๐Ÿ˜ณ

function Cat() {
  console.log('this in cat is ',this)
  Cat.prototype.greeting = function() {
    const str = 'Hello, my name is ' + this.name
    console.log(str)
  }
}

const anotherCat = { name:'Jerry'}
const NewCat = Cat.bind(anotherCat)
const newCat = new NewCat()
console.log(newCat)
console.log(newCat.greeting)

่ฟ่กŒไปฃ็ ๏ผŒ่พ“ๅ‡บ็ป“ๆžœๅฆ‚ไธ‹๏ผš

this in cat is  { name: 'Jerry' }
{}
undefined ? what

4. ้ƒฝๆ˜ฏ new ็š„้”…ใ€‚๐ŸŒš๐ŸŒš๐ŸŒš๐ŸŒš๐ŸŒš๐ŸŒš

  • ๆ˜Ž็™ฝไบ† new ๅ…ณ้”ฎๅญ—็š„ๆœบๅˆถๅŽ๏ผŒๆˆ‘ไปฌๅฐฑๅฏไปฅๅˆ†ๆžๅ‰้ข้€š่ฟ‡ new ๅ…ณ้”ฎๅญ—ๅฎžไพ‹ๅŒ– NewCat ็ฑป๏ผŒๅพ—ๅˆฐ็š„่ฟ”ๅ›žๅ€ผๆ˜ฏ็ฉบๅฏน่ฑก็š„ๅŽŸๅ› ไบ†ใ€‚
  • ่ฟ™ๆ˜ฏๅ› ไธบ๏ผŒNewCat ็›ธๅฏนไบŽๅŽŸๅง‹็š„ Cat ๆ˜ฏไธ€ไธชๅ…จๆ–ฐ็š„ๅ‡ฝๆ•ฐ๏ผˆ่ฐƒ็”จ bind ๆ–นๆณ•ๆ–นๆณ•่ฟ”ๅ›ž๏ผ‰๏ผŒๆˆ‘ไปฌๅœจไฝฟ็”จ new ๅ…ณ้”ฎๅญ—่ฐƒ็”จ NewCat ๆ—ถ๏ผŒ่ฐƒ็”จ็š„ๅ…ถๅฎžๆ˜ฏ่ฟ™ไธชๆ–ฐ็š„ๅ‡ฝๆ•ฐ๏ผŒๅœจๆ–ฐๅ‡ฝๆ•ฐไธญๅ†้€š่ฟ‡ call ๆ–นๆณ•่ฐƒ็”จ Cat ๅ‡ฝๆ•ฐ๏ผŒๅนถๆฒกๆœ‰็›ดๆŽฅๅฏน Cat ่ฟ›่กŒๅฎžไพ‹ๅŒ–ใ€‚
  • ๅœจ่ฐƒ็”จๆ–ฐๅ‡ฝๆ•ฐ็š„ๆ—ถๅ€™๏ผŒ้ฆ–ๅ…ˆไผš็”Ÿๆˆไธ€ไธช็ฉบๅฏน่ฑกใ€‚ๆญคๅค–๏ผŒๆ–ฐๅ‡ฝๆ•ฐ่ฟ˜ๆœ‰ไธ€ไธช่ฟ”ๅ›žๅ€ผ๏ผŒ่ฟ”ๅ›ž็š„ๆ˜ฏ Cat ๅ‡ฝๆ•ฐ่ฐƒ็”จ็š„็ป“ๆžœใ€‚ๅฝ“ Cat ไฝœไธบๅ‡ฝๆ•ฐ่€Œ้ž็ฑป่ฐƒ็”จๆ—ถ๏ผŒๅ…ถ่ฟ”ๅ›žๅ€ผๆ˜ฏ undefinedใ€‚ๅ› ่€Œๅฎžไพ‹ๅŒ–่ฟ™ไธชๆ–ฐๅ‡ฝๆ•ฐ็š„ๆœ€็ปˆ็ป“ๆžœ๏ผŒๅฐฑๆ˜ฏ่ฟ”ๅ›žๅœจไฝฟ็”จ new ๅฎžไพ‹ๅŒ–ๅฎƒ่‡ช่บซๆ—ถๆ‰€ๅˆ›ๅปบ็š„้‚ฃไธช็ฉบๅฏน่ฑกใ€‚

5. ๆˆ‘่ฏฅๆ€ŽไนˆๅŠžใ€‚๐Ÿ‘จโ€๐Ÿ’ปโ€๐Ÿ‘จโ€๐Ÿ’ปโ€๐Ÿ‘จโ€๐Ÿ’ปโ€๐Ÿ‘จโ€๐Ÿ’ปโ€๐Ÿ‘จโ€๐Ÿ’ปโ€๐Ÿ‘จโ€๐Ÿ’ปโ€

function Cat() {
  console.log('this in cat is ',this)
  this.greeting = function() {
    const str = 'Hello, my name is ' + this.name
    console.log(str)
  }
  // Cat ็š„ this ่ขซ็ป‘ๅฎšไธบ {  name:'Jerry' }๏ผŒ่ฟ™้‡Œๆ‰‹ๅŠจๅฐ†ๅ…ถ่ฟ”ๅ›ž
  return this
}

const anotherCat = { name:'Jerry'}
const NewCat = Cat.bind(anotherCat)
const newCat = new NewCat()
console.log(newCat)

่ฟ่กŒไปฃ็ ๏ผŒ่พ“ๅ‡บ็ป“ๆžœๅฆ‚ไธ‹๏ผš

this in cat is  { name: 'Jerry' }
{ name: 'Jerry', greeting: [Function] }

6. ๅˆซ่ท‘้ข˜ใ€‚๐Ÿ‘๐Ÿ‘๐Ÿ‘๐Ÿ‘๐Ÿ‘๐Ÿ‘

Function.prototype.bind = function(thisObj) {
  // ๅˆคๆ–ญ่ฐƒ็”จ bind ็š„ๆ–นๆณ•ๆ˜ฏไธๆ˜ฏไธ€ไธชๅ‡ฝๆ•ฐ
  if(typeof this !== 'function') {
    throw new TypeError('ๅช่ƒฝๅฏนๅ‡ฝๆ•ฐไฝฟ็”จ bind ๆ–นๆณ•')
  }

  // ไฟๅญ˜ๅฝ“ๅ‰ๅ‡ฝๆ•ฐ็š„ๆŒ‡้’ˆ
  const self = this;
  // ๆ‹ฟๅˆฐ้™ค็ฌฌไธ€ไธชๅ‚ๆ•ฐไปฅๅค–็š„ๅ…ถไป–ๅ‚ๆ•ฐๅˆ—่กจ
  const args = [].slice.call(arguments,1)

  function Bound() {
    // ๅฆ‚ๆžœ this instanceof Bound๏ผŒ่ฏดๆ˜Žๆ˜ฏ้€š่ฟ‡ new ๅ…ณ้”ฎๅญ—่ฐƒ็”จ
    // ่ฟ™ๆ—ถๅฐฑๅฐ† this ็›ดๆŽฅ็ป‘ๅฎšๅˆฐ self๏ผŒ่€Œๅฟฝ็•ฅ thisObj๏ผŒๅœจ self ๅ†…้ƒจไผšๅฏน this ๆทปๅŠ ๅฑžๆ€งๅ’Œๆ–นๆณ•
    return self.apply(this instanceof Bound ? this : thisObj,args.concat([].slice.apply(arguments)))
  }

  // ๅฎž็Žฐ็ปงๆ‰ฟ
  if(this.prototype){
    Bound.prototype = Object.create(this.prototype)
  }

  return Bound
}