前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >call、apply、bind

call、apply、bind

作者头像
wade
发布2020-04-23 16:23:38
9410
发布2020-04-23 16:23:38
举报
文章被收录于专栏:coding个人笔记coding个人笔记

刚开始写技术笔记的时候,很浅显的写了一篇this的指向问题,现在看起来不能说错误百出,但也确实是没什么技术水平。今天分享自己对于call、apply、bind新的认识,并手写一个自己的call、apply、bind。

三个方法的语法大体一样:

代码语言:javascript
复制
fnction fn() {}
fn.call(thisArg, arg1, arg2, ...)
fn.apply(thisArg, [arg1,arg2,...])
fn.bind(thisArg, arg1, arg2, ...)

call和bind的参数一样,apply的参数是一个数组(a开头,Array),call和apply返回的是fn执行的结果,bind返回的是fn的拷贝并指定this值和参数(bind不执行,需要调用)。

thisArg是可选的,fn的this指向是thisArg对象。

非严格模式thisArg指定为null、undefined,fn的this指向就是window:

代码语言:javascript
复制
function fn() {
  console.log(this);//window
}
fn.call()
严格模式fn的this指向是undefined:
"use strict"
function fn() {
  console.log(this);//undefined
}
fn.call()

如果thisArg是数字、字符串、布尔值,this指向原始值的对象:

代码语言:javascript
复制
function fn() {
  console.log(this);//String||Number||Boolean
}
fn.call('' || 5 || true)

call、apply和bind是挂在Function对象上的方法,只有函数才能调用。

说真的,这三个方法开发业务的时候并不常用,有用也是用来装一装,面面试。三个方法最主要的就是借助别人的方法,减少重复代码,节省内存。比如fn1方法和fn2方法,fn2需要用到fn1的方法,这时候直接用fn1的方法而不是自己声明一个方法。bind方法比较不一样,bind返回的是一个函数,所以还可以用来做闭包等。

比如求一个数组的最大最小值:

代码语言:javascript
复制
var arr = [5, 6, 2, 8, 1];
console.log(Math.max.apply(Math, arr));//8
console.log(Math.min.apply(Math, arr));//1

实现一个call::

代码语言:javascript
复制
Function.prototype.myCall = function (context) {
  if(context === undefined || context === null){
    context = window;
  }else{
    context = Object(context);
  };
  context.fn = this;
  let result = context.fn([...arguments].slice(1));
  delete context.fn;
  return result;
};

这边需要注意的一个就是context,不能context = context || window;因为这样会把原始数值都绑定到window,但是上面也说了,String是绑定String的。还有就是直接context.fn也是不够严谨,可以使用symbol就绝对不会冲突,只能说fn这个需要用特殊的不会命名冲突的去实现,考虑兼容的话symbol好像也不是非常合适。

实现一个apply:

代码语言:javascript
复制
Function.prototype.myApply = function (context) {
  if(context === undefined || context === null){
    context = window;
  }else{
    context = Object(context);
  };
  context.fn = this;
  let result;
  if(arguments[1] instanceof Array){
    result = context.fn(...arguments[1]);
  }else{
    result = context.fn();
  };
  delete context.fn;
  return result;
};

跟call差不多,就是一个参数的判断不一样,其他的跟call的注意点一样。

实现一个bind:

代码语言:javascript
复制
Function.prototype.mybind = function (context) {
  let that = this;
  if(context === undefined || context === null){
    context = window;
  }else{
    context = Object(context);
  };
  let args = [...arguments].slice(1);
  return function Fn() {
    if(this instanceof Fn){
      return new that(...args, ...arguments)
    }else{
      return that.apply(context, args.concat(...arguments));
    }
  }
}

因为bind返回的是一个函数,所以思路是一样的,不同的是需要判断,bind之后是否是直接new这个函数,如果是new,那么this就是这个构造函数。

代码语言:javascript
复制
function Fn() {
  console.log(this);//Fn
}
new Fn();

(完)

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-08-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 coding个人笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档