每一个函数(普通函数/构造函数/内置类)都是Function这个内置类的实例
所以函数. _proto === Function.prototype.函数可以直接调取 Functio 的方法_

  1. //Function.prototype ==> function anonymous(){}
  2. /*
  3. call/ apply/ bind
  4. 原型上提供的三个属性和方法
  5. 每一个函数都可以调用这个方法执行
  6. 这些方法都可以改变函数的this指向
  7. */
  8. function fn(){}
  9. fn.call(); // fn函数基于原型链查找到Function.prototype上的call方法,并且执行(执行的是call方法:方法中的this是fn)
  10. fn.call.call(); //fn.call本身就是Funcion.prototype上的call方法,也是一个函数,只要是函数就能用原型上的方法,所以可以继续调用call来执行
  11. Function.prototype.call = function $1(){
  12. //...
  13. }
  14. fn.call =>$1;
  15. fn.call() =>$1() this:fn;
  16. //实例.方法()都是找到原型上的内置方法,让内置方法执行(只不过执行的时候做了一些事情,就会对实例产生改变,而这也这些内置方法的作用)内置方法的this一般都是当前操作的实例

call方法

语法:函数.call([context],[params],….)
函数基于原型链找到Function.prototype.call方法,并且把它执行,在call方法执行的时候完成了一些功能

  • 让当前函数执行
  • 把函数中的this指向改为第一个传递给call的实参
  • 把传递给call其余的实参当做参数传递给当前函数

如果执行call一个实参都没有传递,非严格模式下是让函数中的this执行window,严格模式下指向undefined

  window.name = 'WINDOW';
    let obj = { name: 'obj' }
    let fn = function (n,m) {
      console.log(this.name); //WINDOW
    }
    // console.log(obj.fn()); // obj中并没有fn这个属性
    // 需要:想让fn执行的时候,方法fn中的this指向obj ,可此时obj并没有属性,
    // obj.fn = fn; 我们可以手动添加
    // delete obj.fn 执行完后还需要删除这个属性,非常麻烦
    fn.call(obj); //fnthis指向obj,如果不传参默认执行window 严格模式为undefined
    fn.call(obj,10,20) // this: obj ,n =10, m=20
    fn.call(10,20);    // this:10    n = 20,  m undefined
    fn.call(null);// this: window,严格模式下null(第一个参数传递,是null/undefined/不传。非严格模式下传递的是谁,this执行谁,不穿this就是undefined_

用原生JavaScript实现函数内置call方法

 ~function () {
      /*
      call:改变函数中的this指向
      */
      function call(context) {
        contest = context||window;
        // this:sum,也就是当前操作的这个函数的实例
        let args = [],
          result;
        for (let i = 1; i < arguments.length; i++) { //除第一个参数外剩余传递的信息值
          args.push(arguments[i]);
        }
        context.$fn = this; //我们给context对象设置一个fn的方法,将sum方法= fn方法,就达到了sum的this指向了context的效果
        // 用result接收函数的结果
        result = context.$fn(...args); // 展开运算符es6语法,把数组每一项传递给函数
        delete context.$fn;
        return result


      }
      //  扩展到内置类的原型上
      Function.prototype.call = call;  //把内置的call也给干没了;正常来写我们定义的call需要加前缀 mycall
    }()

    let obj = {
      name: 'obj'
    }
    function sum(n, m) {
      console.log(this);
      return n + m;
    }
    let total = sum.call(obj, 1, 2);
    console.log(total);