call、apply、bind

本文阅读 5 分钟
首页 前端笔记 正文
  1. 怎么利用 call、apply 来求一个数组中最大或者最小值 ?
  2. 如何利用 call、apply 来做继承 ?
  3. apply、call、bind 的区别和主要应用场景 ?
  • call 跟 apply 的用法几乎一样,唯一的不同就是传递的参数不同,call 只能一个参数一个参数的传入。
  • apply 则只支持传入一个数组,哪怕是一个参数也要是数组形式。最终调用函数时候这个数组会拆成一个个参数分别传入。
  • 至于 bind 方法,他是直接改变这个函数的 this 指向并且返回一个新的函数,之后再次调用这个函数的时候 this 都是指向 bind 绑定的第一个参数。
  • bind 传参方式跟 call 方法一致。
    适用场景:

求一个数组中最大或者最小值

  1. // 如果一个数组我们已知里面全都是数字,想要知道最大的那个数,由于 Array 没有 max 方法,Math 对象上有
  2. // 我们可以根据 apply 传递参数的特性将这个数组当成参数传入
  3. // 最终 Math.max 函数调用的时候会将 apply 的数组里面的参数一个一个传入,恰好符合 Math.max 的参数传递方式
  4. // 这样变相的实现了数组的 max 方法。min 方法也同理
  5. const arr = [1,2,3,4,5,6]
  6. const max = Math.max.apply(null, arr)
  7. console.log(max) // 6

参数都会排在之后

  1. // 如果你想将某个函数绑定新的`this`指向并且固定先传入几个变量可以在绑定的时候就传入,之后调用新函数传入的参数都会排在之后
  2. const obj = {}
  3. function test(...args) { console.log(args) }
  4. const newFn = test.bind(obj, '静态参数1', '静态参数2')
  5. newFn('动态参数3', '动态参数4')

利用 call 和 apply 做继承

  1. function Animal(name){
  2. this.name = name;
  3. this.showName = function(){
  4. console.log(this.name);
  5. }
  6. }
  7. function Cat(name){
  8. Animal.call(this, name);
  9. }
  10. // Animal.call(this) 的意思就是使用 this 对象代替 Animal 对象,那么
  11. // Cat 中不就有 Animal 的所有属性和方法了吗,Cat 对象就能够直接调用 Animal 的方法以及属性了
  12. var cat = new Cat("TONY");
  13. cat.showName(); //TONY

将伪数组转化为数组(含有 length 属性的对象,dom 节点, 函数的参数 arguments)

  1. // case1: dom节点:
  2. <div class="div1">1</div>
  3. <div class="div1">2</div>
  4. <div class="div1">3</div>
  5. let div = document.getElementsByTagName('div');
  6. console.log(div); // HTMLCollection(3) [div.div1, div.div1, div.div1] 里面包含length属性
  7. let arr2 = Array.prototype.slice.call(div);
  8. console.log(arr2); // 数组 [div.div1, div.div1, div.div1]
  9. //case2:fn 内的 arguments
  10. function fn10() {
  11. return Array.prototype.slice.call(arguments);
  12. }
  13. console.log(fn10(1,2,3,4,5)); // [1, 2, 3, 4, 5]
  14. // case3: 含有 length 属性的对象
  15. let obj4 = {
  16. 0: 1,
  17. 1: 'thomas',
  18. 2: 13,
  19. length: 3 // 一定要有length属性
  20. };
  21. console.log(Array.prototype.slice.call(obj4)); // [1, "thomas", 13]

判断变量类型

  1. let arr1 = [1,2,3];
  2. let str1 = 'string';
  3. let obj1 = { name: 'thomas' };
  4. //
  5. function isArray(obj) {
  6. return Object.prototype.toString.call(obj) === '[object Array]';
  7. }
  8. console.log(fn1(arr1)); // true
  9. // 判断类型的方式,这个最常用语判断 array 和 object ,null( 因为 typeof null 等于 object )
  10. console.log(Object.prototype.toString.call(arr1)); // [object Array]
  11. console.log(Object.prototype.toString.call(str1)); // [object String]
  12. console.log(Object.prototype.toString.call(obj1)); // [object Object]
  13. console.log(Object.prototype.toString.call(null)); // [object Null]

总结:

  1. 当我们使用一个函数需要改变 this 指向的时候才会用到 call apply bind
  2. 如果你要传递的参数不多,则可以使用 fn.call(thisObj, arg1, arg2 ...)
  3. 如果你要传递的参数很多,则可以用数组将参数整理好调用 fn.apply(thisObj, [arg1, arg2 ...])
  4. 如果你想生成一个新的函数长期绑定某个函数给某个对象使用,则可以使用 const newFn = fn.bind(thisObj); newFn(arg1, arg2...)

手写 bind

  1. Function.prototype.myBind = function(context, ...args) {
  2. // 设置 fn 为调用 myCall 的方法
  3. const fn = this
  4. args = args ? args : []
  5. // 设置返回的一个新方法
  6. const result = function(...newFnArgs) {
  7. // 如果是通过 new 调用的,绑定 this 为实例对象
  8. if (this instanceof result) {
  9. fn.apply(this, [...args, ...newFnArgs]);
  10. } else { // 否则普通函数形式绑定 context
  11. fn.apply(context, [...args, ...newFnArgs]);
  12. }
  13. }
  14. // 绑定原型链
  15. result.prototype = Object.create(fn.prototype);
  16. // 返回结果
  17. return result;
  18. };
  19. this.a = 1;
  20. const fn = function() {
  21. this.a = 2;
  22. console.log(this.a);
  23. }
  24. fn.myBind(fn);
  25. fn();

实现 apply

  1. Function.prototype.myApply = function (context, args) {
  2. //这里默认不传就是给window,也可以用es6给参数设置默认参数
  3. context = context || window
  4. args = args ? args : []
  5. //给context新增一个独一无二的属性以免覆盖原有属性
  6. const key = Symbol()
  7. context[key] = this
  8. //通过隐式绑定的方式调用函数
  9. const result = context[key](...args)
  10. //删除添加的属性
  11. delete context[key]
  12. //返回函数调用的返回值
  13. return result
  14. }

实现 call

  1. //传递参数从一个数组变成逐个传参了,不用...扩展运算符的也可以用arguments代替
  2. Function.prototype.myCall = function (context, ...args) {
  3. //这里默认不传就是给window,也可以用es6给参数设置默认参数
  4. context = context || window
  5. args = args ? args : []
  6. //给context新增一个独一无二的属性以免覆盖原有属性
  7. const key = Symbol()
  8. context[key] = this
  9. //通过隐式绑定的方式调用函数
  10. const result = context[key](...args)
  11. //删除添加的属性
  12. delete context[key]
  13. //返回函数调用的返回值
  14. return result
  15. }
解压密码: detechn或detechn.com

免责声明

本站所有资源出自互联网收集整理,本站不参与制作,如果侵犯了您的合法权益,请联系本站我们会及时删除。

本站发布资源来源于互联网,可能存在水印或者引流等信息,请用户自行鉴别,做一个有主见和判断力的用户。

本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。

width 和 height 的百分比是相对谁讲的 ?margin 和 padding 呢?
« 上一篇 03-12
函数里的 this 什么含义,什么情况下,怎么用 ?
下一篇 » 03-12

发表评论

惪特博客
  • 文章总数:
    18501 篇
  • 评论总数:
    53387 条
  • 标签总数:
    8881 个
  • 总浏览量:
    23400733 次
  • 最后更新:
    4月27日

最多点赞

随便看看

标签TAG