专栏首页carvenjs原生函数之call和apply,bind

js原生函数之call和apply,bind

call 和 apply

callapplybind 都是为了改变某个函数运行时的 context 即上下文而存在的,换句话说,就是为了改变函数体内部 this 的指向。

js原生函数中的call和apply都不陌生,这两个方法的作用相似,接受两类参数。

第一类是context(上下文),传入的参数作为执行函数的上下文,也是要传入的第一个参数。 第二类的argument(参数),传入的参数作为函数执行的参数,call是逐个参数传入,apply是将参数以数组方式传入。

应用如下

var callObj = {c:1};
var applyObj = {c:2};
function fun(a,b){
    return a+b+this.c;
}

fun(2,3);//NaN
fun.call(callObj,2,3);//6;
fun.apply(applyObj,[2,3]);//7

应用

日常的应用这里不提了,收集了一些我平时看到的,比较意想不到的应用。

将NodeList转数组

document.querySelectorAll()是大家常用的DOM元素选择器,他会返回查询到的DOM元素的数组,也就是NodeList; 我曾经试过使用forEach去循环监听里面的各个dom,结果失败了,因为NodeList并不具有数组的函数功能。 如果我们要对每个Node遍历处理,就不能用数组的方式去处理了,当然,通过for循环还是可以的。 另一方面,出于其他理由,我们要将NodeList转成数组呢。 于是可以用到call

var pList = document.querySelectorAll('p');//NodeList
var pArray = [].slice.call(pList);//Array

顺便一提,ES6标准中有一个Array.from() 方法可以将一个类数组对象或可迭代对象转换成真正的数组。

var pList = document.querySelectorAll('p');//NodeList
var pArray = Array.from(pList);//Array

Currying(柯里化)

Currying(柯里化)(部分函数应用)是应用 call 和 apply 的一个函数式编程。Currying 允许我们创建返回已知条件的函数

function curry(fun){
    if(arguments.length < 1){
        return this;
    }
    //获取后面的参数
    var args = Array.prototype.slice.call(arguments, 1);
    console.log(args);
    //将后面的参数作为fun的参数
    return function () {
        //这里的arguments和上面的arguments不是同一个变量,这是传入本function的参数
        return fun.apply(this, args.concat(Array.prototype.slice.call(arguments,0)));
    }
}

//定义一个函数是 1 + a + b
function addOneToNumber(a , b) {
    return 1 + a + b;
}

// 将addOneToNumber柯里化
var addOneCurried = curry(addOneToNumber, 10);// 柯里化同时传进一个参数,将a常数化/已知化
console.log(addOneCurried(10, 2)); // 1 + 10 + 10 = 21;

其实也是通过Array.prototype.slice将类数组转换成数组的一个应用,只是赋予了更加复杂的应用逻辑; 这里同时也是闭包的一个应用过程;

bind

说了call和apply,也是要介绍一下bind的。 bind方法用于明确指定调用 this 方法。在作用域方面,类似于 call 和 apply 。当你将一个对象绑定到一个函数的 this对象时,你就会用到 bind。

var tom = {
    hobby: 'reading',
    advantage: 'programming'
};

function getHobby(){
    return this.hobby;
}

console.log(getHobby());//undefined
console.log(getHobby.bind(tom)());//reading

bind 和 call的使用方式很类似,同样接受两部分参数,上下文this和作用函数的后续参数,下面是我猜想的bind的模拟实现方法。

Function.prototype.bind = function(scope) {
    var _that = this;
    var args = Array.prototype.slice.call(arguments,1);
    return function() {
        return _that.apply(scope, args.concat(Array.prototype.slice.call(arguments)));
    }
};

bind和call的主要区别在于,bind返回的是一个新函数,而call这是直接执行了该函数。

总结

本来想写一篇call/apply整理一次自己的思路的,原本以为可以写很多,最后发现实在想不起什么了,自己果然还是学得太少。 后来想到了bind,作为和call的对比也就加了进来,之前没想到bind除了thisArg外还可以继续接受其他参数,因为之前看别人写的bind方法模拟不是这样的, 原来我看到的别人写的bind实现原理代码是这样的:

Function.prototype.bind = function(scope) {
  var _that = this;

  return function() {
    return _that.apply(scope, arguments);
  }
}

后来自己实验了一遍,发现不对,才自己做了修改

Function.prototype.bind = function(scope) {
    var _that = this;
    var args = Array.prototype.slice.call(arguments,1);
    return function() {
        return _that.apply(scope, args.concat(Array.prototype.slice.call(arguments)));
    }
};

虽然不一定是正确的,但至少是我的理解范围内的原理解释。 想不到最终收获的是bind

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 前端模块化开发

    其实对前端模块化开发的接触时间并不多,很多见解都是别人的,或者是偏的, 还是乐意记录下来,谁让我一天一个念头 说到前端模块化开发,其实是说 javascript...

    用户1394570
  • 浅谈闭包

    闭包 – closure, 应该可以说是javascript的一个难点吧, 其实说难也不难, 只是因为没有真正一个权威的人/书去给他一个真正的定义。 不过,学编...

    用户1394570
  • 实习笔记1--20160120

    今天主要做的是这种账号的注册和软件的安装。 实习了才知道,一个团队的任务管理居然要依赖与那么多的工具,尽管团队不大,但是任务分工看起来很严格呢。 软件也安装了很...

    用户1394570
  • Js中的call vs apply vs bind及记忆方式

    js中的call(), apply()和bind()是Function.prototype下的方法,都是用于改变函数运行时上下文,最终的返回值是你调用的方法的返...

    javascript.shop
  • 用故事讲技术:关于js apply、call、bind的区别,我们可以将call忘掉,只使用apply就足够了

    简单说,apply 是给框架设计者用的,而 call 是给开发者用的。两者都能扩充函数作用域。而 bind,主要是绑定作用域,并不是函数执行。

    李艺
  • JavaScript中apply、call、bind的区别与用法

    apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数。 语法: func.apply(thisArg,...

    前端达人
  • js中call、apply、bind那些事

    前言 回想起之前的一些面试,几乎每次都会问到一个js中关于call、apply、bind的问题,比如… 怎么利用call、apply来求一个数组中最大或者最小值...

    用户1667431
  • maven安装

    下载地址 https://archive.apache.org/dist/maven/maven-3/

    东营浪人
  • 一位资深程序员大牛给予Java初学者的学习路线建议

    Java学习这一部分其实也算是今天的重点,这一部分用来回答很多群里的朋友所问过的问题,那就是你是如何学习Java的,能不能给点建议?今天我是打算来点干货,因此咱...

    用户1063783
  • 一位资深程序员大牛给予Java初学者的学习路线建议

    精讲java

扫码关注云+社区

领取腾讯云代金券