资讯专栏INFORMATION COLUMN

js中call、apply、bind那些事

shiyang6017 / 669人阅读

摘要:应用场景求数组中的最大值和最小值并不是最佳选择是中的静态方法,因此必然是没有使用上下文的必要的。因此绑定只需要用或者占位就可以了。

前言

面试,几乎每次都会问到一个js中关于call、apply、bind的问题,比如…

怎么利用call、apply来求一个数组中最大或者最小值

如何利用call、apply来做继承

apply、call、bind的区别和主要应用场景

作用

首先问个问题,这三个函数的存在意义是什么?答案是改变函数执行时的上下文,再具体一点就是改变函数运行时的this指向。

举个栗子
function Person(name) {
    this.name = name
}

Person.prototype = {
    constructor: Person,
    showName: function() {
        console.log(this.name)
    }
}

var person = new Person("shifeng")
person.showName() // 输入"shifeng"
接下来
var animal = {
    name: "cat
}

上面代码中有一个对象字面量,他没有所谓的showName方法,但是我还是想用?怎么办?(坑爹了,这好像在让巧媳妇去做无米之炊),不过没关系,call、apply、bind可以帮我们干这件事。

// 以下三种都会输出"cat"
// 1. call
person.showName.call(animal)
// 2. apply
person.showName.apply(animal)
// 3. bind
person.showName.bind(animal)

我们拿别人的showName方法,并动态改变其上下文帮自己输出了信息,说到底就是实现了复用

区别

上面看起来三个函数的作用差不多,干的事几乎是一样的,那为什么要存在3个家伙呢,留一个不就可以。所以其实他们干的事从本质上讲都是一样的动态的改变this上下文,但是多少还是有一些差别的...

call, apply与bind的差别

call和apply改变了函数的this上下文后便执行该函数, 而bind则是返回改变了上下文的一个函数

call和apply的区别

他们俩之间的差别在于参数的区别,call和aplly的第一个参数都是要改变上下文的对象,而call从第二个参数开始以参数列表的形式展现,apply则是把除了改变上下文对象的参数放在一个数组里面作为它的第二个参数。

fn.call(contextObj, arg1, arg2, arg3...)
fn.apply(contextObj, [arg1, arg2, aeg3...])
应用场景

求数组中的最大值和最小值(并不是最佳选择)

var arr = [34,5,3,6,54,6,-67,5,7,6,-8,687]

// max、min 是 Math 中的静态方法,因此必然是没有使用上下文的必要的。
// 因此 call、apply 绑定只需要用 null 或者 undefined 占位就可以了。
Math.max.call(null, 34,5,3,6,54,6,-67,5,7,6,-8,687) // 同Math.max(34,5,3,6,54,6,-67,5,7,6,-8,687)
Math.max.apply(null, arr)

Math.min.call(undefined, 34,5,3,6,54,6,-67,5,7,6,-8,687)
Math.min.apply(undefined, arr)

// 最佳方法, ES6数组解构
Math.max(...arr)
Math.min(...arr)

将伪数组转化为数组

js中的伪数组(例如通过document.getElementsByTagName或者document.querySelectorAll获取的元素)具有length属性,并且可以通过0、1、2…下标来访问其中的元素,但是没有Array中的push、pop等方法。我们可以利用call、apply来将其转化为真正的数组这样便可以方便地使用数组方法了。

var arrayLike = {
    0: "shifeng",
    1: "xingyun",
    2: "ruxue",
    length: 3
}

上面就是一个普通的对象字面量,怎么把它变成一个数组呢?最简单的方法就是

var arr = Array.prototype.slice.call(arrayLike)

上面arr便是一个包含arrayLike元素的真正的数组啦(注意数据结构必须是以数字为下标而且一定要有length属性)

数组追加

在js中要往数组中添加元素, 可以直接用push方法

var arr1 = [1,2,3]
var arr2 = [4,5,6]

// Array.prototype.push.apply(arr1, arr2)
[].push.apply(arr1, arr2)
// 使用一个辅助的空数组(为了访问非静态方法),就是把arr2利用apply的数组参数特性push到arr1中.
// 这样通过解构可以写成 arr1.push(...arr2), 如果需要返回一个全新的对象,还可以使用 [...arr1, ...arr2]。
// 还可以写成var newArr =  arr1.concat(arr2)

// arr1 [1, 2, 3, 4, 5, 6]
// arr2 [4,5,6]

判断变量类型

对于对象型的数据类型, 我们可以借助call来得知他的具体类型, 例如数组

function isArray(obj){
  return Object.prototype.toString.call(obj) == "[object Array]";
}
isArray([]) // true
isArray("qianlong") // false

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/88011.html

相关文章

  • javascript 总结(那些剪不断理还乱的关系)

    摘要:前言整理中一些相似的关键字方法概念。于是我们修改上面的函数来验证它们的区别小明撸代码撸代码小红小黑小刚小红小黑撸代码小李小谢小刚小李小谢撸代码那么与有什么区别呢与和不同的是,绑定后不会立即执行。通常用来处理一些并发的异步操作。 前言 整理 javascript 中一些相似的关键字、方法、概念。 1. var、function、let、const 命令的区别 使用var声明的变量,其作...

    hlcfan 评论0 收藏0
  • 如何写一个实用的bind

    摘要:方法创建一个新的函数当被调用时,它的关键字被设置为提供的值。语法简单地看一下这些参数的含义当绑定函数被调用时,该参数会作为原函数运行时的指向当使用操作符调用绑定函数时,该参数无效。结尾文章很简短,知道怎么实现一个原生的就行。 前言 这是underscore.js源码分析的第五篇,如果你对这个系列感兴趣,欢迎点击 underscore-analysis/ watch一下,随时可以看到动态...

    zhaofeihao 评论0 收藏0
  • 如何写一个实用的bind

    摘要:方法创建一个新的函数当被调用时,它的关键字被设置为提供的值。语法简单地看一下这些参数的含义当绑定函数被调用时,该参数会作为原函数运行时的指向当使用操作符调用绑定函数时,该参数无效。结尾文章很简短,知道怎么实现一个原生的就行。 前言 这是underscore.js源码分析的第五篇,如果你对这个系列感兴趣,欢迎点击 underscore-analysis/ watch一下,随时可以看到动态...

    Prasanta 评论0 收藏0
  • this - 想说爱你不容易

    摘要:构造函数也是函数,所以当你用普通调用方式调用时这个时候相当于给对象添加了和两个属性。为构造函数指定这里报错了,原因是我们去了函数,这里的函数不是一个构造函数当然解决方式也是有的。 前言 javascript中的this是啥东西?为啥我们经常被他搞得晕头转向不知所以?他是恶魔?是天使 ?是怪胎?让我们一起来揭开它那神秘的面纱。 showImg(https://segmentfault.c...

    zhaot 评论0 收藏0
  • JS程序

    摘要:设计模式是以面向对象编程为基础的,的面向对象编程和传统的的面向对象编程有些差别,这让我一开始接触的时候感到十分痛苦,但是这只能靠自己慢慢积累慢慢思考。想继续了解设计模式必须要先搞懂面向对象编程,否则只会让你自己更痛苦。 JavaScript 中的构造函数 学习总结。知识只有分享才有存在的意义。 是时候替换你的 for 循环大法了~ 《小分享》JavaScript中数组的那些迭代方法~ ...

    melody_lql 评论0 收藏0

发表评论

0条评论

shiyang6017

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<