new

    面试官问:能否模拟实现JS的bind方法

    作者:若川
    链接:https://juejin.im/post/5bec4183f265da616b1044d7
    来源:掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    1. var obj = {};
    2. console.log(obj);
    3. // bind本身是个方法,返回值也是一个方法
    4. console.log(typeof Function.prototype.bind); // function
    5. console.log(typeof Function.prototype.bind()); // function
    6. // bind方法的name为bind,返回的方法的name为bound
    7. console.log(Function.prototype.bind.name); // bind
    8. console.log(Function.prototype.bind().name); // bound
    1. bind本身是个方法,返回值也是一个方法
    2. bind方法的name为bind,返回的方法的name为bound ```javascript var obj = { name: ‘baby’, }; function original(a, b){ console.log(this.name); console.log([a, b]); return false; } // 在使用bind方法传入的除第一个参数以外的参数 // 和执行bound函数传入的参数会拼接起来 var bound = original.bind(obj, 1); // 在bind时传入了一个参数1,实际bound函数执行传入2 // 拼接出的实参其实是(1,2) var boundResult = bound(2); // ‘baby’, [1, 2] var bound = original.bind(obj); // 这里bound执行时的实参就是(2) var boundResult = bound(2); // ‘baby’, [2, undefined]

    console.log(boundResult); // false console.log(original.bind.name); // ‘bind’ console.log(original.bind.length); // 1 bind的形参个数为1,就是this指向 console.log(original.bind().length); // 2 返回original函数的形参个数 // bind()返回函数的name为bound + 空格 + 调用bind的函数名 console.log(bound.name); // ‘bound original’ console.log((function(){}).bind().name); // ‘bound ‘ console.log((function(){}).bind().length); // 0

    1. 1. 在使用bind方法传入的除第一个参数以外的参数,和执行bound函数传入的参数会拼接起来
    2. 2. bind返回的函数的形参个数和原函数保持一致
    3. ```typescript
    4. Function.prototype.bindFn = function bind(thisArg){
    5. if(typeof this !== 'function'){
    6. throw new TypeError(this + ' must be a function');
    7. }
    8. // 存储调用bind的函数本身
    9. var self = this;
    10. // 去除thisArg的其他参数 转成数组
    11. var args = [].slice.call(arguments, 1);
    12. var bound = function(){
    13. // bind返回的函数 的参数转成数组
    14. var boundArgs = [].slice.call(arguments);
    15. var finalArgs = args.concat(boundArgs);
    16. // 判断bound函数是否进行 new 调用,其实this instanceof bound判断也不是很准确。
    17. // es6 new.target就是解决这一问题的。
    18. if(this instanceof bound){
    19. // 开始模拟new的调用
    20. // 这里是实现上文描述的 new 的第 1, 2, 4 步
    21. // self可能是ES6的箭头函数,没有prototype,所以就没必要再指向做prototype操作。
    22. if(self.prototype){
    23. // ES5 提供的方案 Object.create()
    24. // bound.prototype = Object.create(self.prototype);
    25. // 这是个ployfill
    26. function Empty(){} // 1.创建一个全新的对象
    27. Empty.prototype = self.prototype; // 2.并且执行[[Prototype]]链接
    28. bound.prototype = new Empty(); // 4.通过`new`创建的每个对象将最终被`[[Prototype]]`链接到这个函数的`prototype`对象上。
    29. }
    30. // 3.生成的新对象会绑定到函数调用的`this`。
    31. var result = self.apply(this, finalArgs);
    32. // 这里是实现上文描述的 new 的第 5 步
    33. // 5.如果函数没有返回对象类型`Object`(包含`Functoin`, `Array`, `Date`, `RegExg`, `Error`),
    34. // 那么`new`表达式中的函数调用会自动返回这个新的对象。
    35. var isObject = typeof result === 'object' && result !== null;
    36. var isFunction = typeof result === 'function';
    37. if(isObject || isFunction){
    38. return result;
    39. }
    40. return this;
    41. }
    42. else{
    43. // apply修改this指向,把两个函数的参数合并传给self函数,并执行self函数,返回执行结果
    44. return self.apply(thisArg, finalArgs);
    45. }
    46. };
    47. return bound;
    48. }