手写call、apply、bind函数

栏目: JavaScript · 发布时间: 5年前

  • 特点:
    • 1)可以改变我们当前函数的this指向
    • 2)还会让当前函数执行
Function.prototype.call = function (context) {
 if (typeof this !== 'function') {
    throw new TypeError(`${this} is not a function`)
  }
  context = Object(context) || window;
  context.fn = this;
  let args = [];
  for (let i = 1; i < arguments.length; i++) {
    args.push('arguments['+i+']'); 
  }
  let r = eval('context.fn('+args+')');
  delete context.fn;
  return r;
}
复制代码

题目自测

function fn1() {
  console.log(this,arguments);
  console.log(1);
  
}
function fn2() {
  console.log(this,arguments);
  console.log(2);
}
fn1.call(fn2,1,2); // fn2 [1,2] 1
fn1.call.call.call.call.call(fn2,1,2); // {number:1} [2] 2
复制代码
  • 思路解析
    • fn1.call(fn2,1,2)
      • 1) call 执行传入 fn2 , 1 , 2 三个参数
      • 2) call 函数内部 context = Object(fn2) = fn2
      • 3) fn2.fn = fn1
      • 4) args=['arguments[1]','arguments[2]']=[1,2]
      • 5) eval('context.fn('+args+')') = fn2.fn(1,2) = fn2.fn1(1,2)
    • fn1.call.call.call.call.call(fn2,1,2)
      • 1) call 执行传入 fn2 , 1 , 2 三个参数
      • 2) call 函数内部 context = Object(fn2) = fn2
      • 3) fn2.fn = call
      • 4) args=['arguments[1]',arguments[2]]=[1,2]
      • 5) eval('context.fn('+args+')') = fn2.fn(1,2) = fn2.call(1,2)
      • 6) call 执行传入 1 , 2 两个参数
      • 7) call 函数内部 context = Object(1) = Number{1}
      • 8) Number{1}.fn = fn2
      • 9) args=['arguments[1]']=[1]
      • 10) eval('context.fn('+args+')') = Number{1}.fn(2) = Number{1}.fn2(2)
      • 注:多次调用 call 的时候其实是 call 执行的时候内部又调用了一次 call ,总共调用两次

apply 函数

  • 特点:
    • 1)可以改变我们当前函数的this指向
    • 2)还会让当前函数执行
Function.prototype.apply = function (context,args) {
  if (typeof this !== 'function') {
     throw new TypeError(`${this} is not a function`)
   }
   context = Object(context) || window;
   context.fn = this;
   if(!args){
    return context.fn();
   }
   let r = eval('context.fn('+args+')');
   delete context.fn;
   return r;
 }
复制代码

new 操作符

  • 特点
    this
    
/*
 *基本使用 
 */
function Animal(type) {
  this.type = type ; 
}
Animal.prototype.say = function () {
  console.log('say');
}
let tiger = new Animal('tiger');
console.log(tiger);
--------------------------------------------------------
/*
 *方法实现
 */
function mockNew(){
    let Constructor = [].shift.call(arguments);
    let obj = {}; // 新生成了对象
    obj.__proto__ = Constructor.prototype; // 链接到原型
    let r = Constructor.apply(obj,arguments) // 绑定`this`
    return r instance Object ? r : obj; //返回一个对象
}
let tiger = mockNew(Animal,'tiger');
console.log(tiger);
复制代码

bind 函数

  • 特点
    • 绑定 this 指向
    • 返回一个绑定后的函数(高阶函数原理)
    • 如果绑定的函数被 new 执行 ,当前函数的 this 就是当前的实例
    • new 出来的结果可以找到原有类的原型
Function.prototype.bind = function (context) {
  if (typeof this !== 'function') {
    throw new TypeError(`${this} is not a function`)
  }
  let that = this;
  let bindArgs = Array.prototype.slice.call(arguments, 1);
  function Fn() { };
  function bindFn() {
    let args = Array.prototype.slice.call(arguments);
    /*
     * 绑定`this`指向
     * 如果绑定的函数被`new`执行 ,当前函数的`this`就是当前的实例
     */
    that.apply(this instanceof bindFn ? this : context, bindArgs.concat(args)); 
  }
  /*`new`出来的结果可以找到原有类的原型*/
  Fn.prototype = that.prototype; 
  bindFn.prototype = new Fn();
  /*返回一个绑定后的函数*/
  return bindFn; 
}
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Modern PHP(中文版)

Modern PHP(中文版)

Josh Lockhart / 安道 / 中国电力出版社 / 2015-9 / 39

PHP正在重生,不过所有PHP在线教程都过时了,很难体现这一点。通过这本实用的指南,你会发现,借助面向对象、命名空间和不断增多的可重用的组件库,PHP已经成为一门功能完善的成熟语言。 本书作者Josh Lockhart是“PHP之道”的发起人,这是个受欢迎的新方案,鼓励开发者使用PHP最佳实践。Josh通过实践揭示了PHP语言的这些新特性。你会学到关于应用架构、规划、数据库、安全、测试、调试......一起来看看 《Modern PHP(中文版)》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具