1. Function.prototype.myCall = function (context, ...args) {
    2. if (!context || context === null) {
    3. context = window;
    4. }
    5. // 创造唯一的key值 作为我们构造的context内部方法名
    6. let fn = Symbol();
    7. context[fn] = this; //this指向调用call的函数
    8. // 执行函数并返回结果 相当于把自身作为传入的context的方法进行调用了
    9. return context[fn](...args);
    10. };
    11. // apply原理一致 只是第二个参数是传入的数组
    12. Function.prototype.myApply = function (context, args) {
    13. if (!context || context === null) {
    14. context = window;
    15. }
    16. // 创造唯一的key值 作为我们构造的context内部方法名
    17. let fn = Symbol();
    18. context[fn] = this;
    19. // 执行函数并返回结果
    20. return context[fn](...args);
    21. };
    22. //bind实现要复杂一点 因为他考虑的情况比较多 还要涉及到参数合并(类似函数柯里化)
    23. Function.prototype.myBind = function (context, ...args) {
    24. if (!context || context === null) {
    25. context = window;
    26. }
    27. // 创造唯一的key值 作为我们构造的context内部方法名
    28. let fn = Symbol();
    29. context[fn] = this;
    30. let _this = this;
    31. // bind情况要复杂一点
    32. const result = function (...innerArgs) {
    33. // 第一种情况 :若是将 bind 绑定之后的函数当作构造函数,通过 new 操作符使用,则不绑定传入的 this,而是将 this 指向实例化出来的对象
    34. // 此时由于new操作符作用 this指向result实例对象 而result又继承自传入的_this 根据原型链知识可得出以下结论
    35. // this.__proto__ === result.prototype //this instanceof result =>true
    36. // this.__proto__.__proto__ === result.prototype.__proto__ === _this.prototype; //this instanceof _this =>true
    37. if (this instanceof _this === true) {
    38. // 此时this指向指向result的实例 这时候不需要改变this指向
    39. this[fn] = _this;
    40. this[fn](...[...args, ...innerArgs]); //这里使用es6的方法让bind支持参数合并
    41. } else {
    42. // 如果只是作为普通函数调用 那就很简单了 直接改变this指向为传入的context
    43. context[fn](...[...args, ...innerArgs]);
    44. }
    45. };
    46. // 如果绑定的是构造函数 那么需要继承构造函数原型属性和方法
    47. // 实现继承的方式: 使用Object.create
    48. result.prototype = Object.create(this.prototype);
    49. return result;
    50. };
    51. //用法如下
    52. // function Person(name, age) {
    53. // console.log(name); //'我是参数传进来的name'
    54. // console.log(age); //'我是参数传进来的age'
    55. // console.log(this); //构造函数this指向实例对象
    56. // }
    57. // // 构造函数原型的方法
    58. // Person.prototype.say = function() {
    59. // console.log(123);
    60. // }
    61. // let obj = {
    62. // objName: '我是obj传进来的name',
    63. // objAge: '我是obj传进来的age'
    64. // }
    65. // // 普通函数
    66. // function normalFun(name, age) {
    67. // console.log(name); //'我是参数传进来的name'
    68. // console.log(age); //'我是参数传进来的age'
    69. // console.log(this); //普通函数this指向绑定bind的第一个参数 也就是例子中的obj
    70. // console.log(this.objName); //'我是obj传进来的name'
    71. // console.log(this.objAge); //'我是obj传进来的age'
    72. // }
    73. // 先测试作为构造函数调用
    74. // let bindFun = Person.myBind(obj, '我是参数传进来的name')
    75. // let a = new bindFun('我是参数传进来的age')
    76. // a.say() //123
    77. // 再测试作为普通函数调用
    78. // let bindFun = normalFun.myBind(obj, '我是参数传进来的name')
    79. // bindFun('我是参数传进来的age')