欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

js 关于apply和call的理解使用

程序员文章站 2022-05-18 20:57:04
关于call和apply,以前也思考良久,很多时候都以为记住了,但是,我太难了。今天我特地写下笔记,希望可以完全掌握这个东西,也希望可以帮助到任何想对学习这个东西的同学。 一.apply函数定义与理解,先从apply函数出发 在MDN上,apply的定义是: “apply()方法调用一个具有给定th ......

  关于call和apply,以前也思考良久,很多时候都以为记住了,但是,我太难了。今天我特地写下笔记,希望可以完全掌握这个东西,也希望可以帮助到任何想对学习这个东西的同学。

一.apply函数定义与理解,先从apply函数出发

  在mdn上,apply的定义是:

    “apply()方法调用一个具有给定this值的函,以及作为一个数组(或类似数组对象)提供的参数。”

  我的理解是:apply的前面有个含有this的对象,设为a,apply()的参数里,也含有一个含有this的对象设为b。则a.apply(b),表示a代码执行调用了b,b代码照常执行,执行后的结果作为apply的参数,然后apply把这个结果所指代表示的this替换掉a本身的this,接着执行a代码。

  比如:

 1     var aa = {
 2         _name:111,
 3         _age:222,
 4         _f:function(){
 5             console.log(this)
 6             console.log(this._name)
 7         }
 8     }
 9     var cc = {
10         _name:0,
11         _age:0,
12         _f:function(){
13             console.log(this)
14             console.log(this._name)
15         }
16     }
17     cc._f.apply(aa)//此时aa表示的this就是aa本身
18     cc._f.apply(aa._f)//此时aa._f表示的this就是aa._f本身
19     
20     /**
21      * 此时aa._f()表示的this,就是执行后的结果本身。aa._f()执行后,没有返回值,所以应该是undefined,而undefined作为call和apply的参数时,call和apply前面的方法 cc._f 的this会替换成全局对象window。
22      * 参考mdn:https://developer.mozilla.org/zh-cn/docs/web/javascript/reference/global_objects/function/apply 的参数说明
23      */
24     cc._f.apply(aa._f())

执行结果:

  1.参数为aa

  js 关于apply和call的理解使用

  这两行的打印的都是来自 cc._f 方法内的那两句console 。aa的时候算是初始化,里面的 aa._f 方法没有执行。

  2.参数为aa.f

  js 关于apply和call的理解使用

  这两行的打印的都是来自 cc._f 方法内的那两句console 。aa.f 的时候应该也算是初始化,或者是整个函数当参数传但是不执行这个参数,即 aa._f 方法没有执行。

  3.参数为aa.f()

   js 关于apply和call的理解使用

  这四行的打印,前面两行来自 aa._f() 方法执行打印的;后面两行是来自cc._f()方法打印的。

  后两行解析:aa._f()执行后,没有返回值,所以是undefined,在apply执行解析后,cc._f()的this变成的window,所以打印了window。window里面没有_name这个属性,所以undefined。

 二.apply与call的区分

  1.apply()

    a.apply(b, [1,2,3]) 后面的参数是arguments对象或类似数组的对象,它会被自动解析为a的参数;

    对于a.apply(b) / a.call(b) , 简单讲,b先执行,执行后根据结果去执行a。这个时候,用a去执行b的内容代码,然后再执行自己的代码。

  比如:

    var f1 = function(a,b){
        console.log(a+b)
    }
    var f2 = function(a,b,c){
        console.log(a,b,c)
    }
    f2.apply(f1,[1,2])//1 2 undefined

   先执行f1,f1执行后(f1是f1,不是f1()执行方法,所以console.log(a+b)这行代码并没有执行,相当于,初始化了代码f1),由于没有返回值,所以结果是undefined,f2执行的时候this指向window;参数中的 ” [1,2] “,解析后变成 f2 的参数 “ 1,2,undefined ”,执行f2方法后,打印出1,2,undefined三个值

  2.call()

    a.call(b, 1,2,3) 后面的参数都是独立的参数对象,它们会被自动解析为a的参数;

  比如: 

    var f1 = function(a,b){
        console.log(a+b)
    }
    var f2 = function(a,b,c){
        console.log(a,b,c)
    }
    f2.call(f1,[1,2])//[1,2] undefined undefined
    f2.call(f1,1,2)//1 2 undefined

   参数中的 ” [1,2] “,因为传入了一个数组,相当于只传入了第一个参数,b和c参数没有传。解析后变成 f2 的参数 “ [1,2],undefined ,undefined ”,执行f2方法后,打印出 [1,2],undefined ,undefined 三个值。

三.apply与call带来的便利

  1. push();

  push参数是类似(a,b,c,d,e)如此传输的,如果在一个数组的基础上进行传输另一个数组的内容,可以如下:

    //apply用法
    var arr = new array(1,2,3)
    var arr1 = new array(11,21,31)
    array.prototype.push.apply(arr,arr1)
    console.log(arr)//[1, 2, 3, 11, 21, 31]
    
    //call用法
    var arr = new array(1,2,3)
    var arr1 = new array(11,21,31)
    array.prototype.push.call(arr,arr1[0],arr1[1],arr1[2])
    console.log(arr)//[1, 2, 3, 11, 21, 31]

   2. 数组利用math求最大和最小值

  apply和call的第一个参数,如果是null或者undefined,则apply或call前面的函数会把this指向window

    //apply的用法
    var _maxnum = math.max.apply(null,[1,3,2,4,5])
    console.log(_maxnum)//5
    var _minnum = math.min.apply(null,[1,3,2,4,5])
    console.log(_minnum)//1
    
    //call的用法
    var _maxnum = math.max.call(null,1,3,2,4,5)
    console.log(_maxnum)//5
    var _minnum = math.min.call(null,1,3,2,4,5)
    console.log(_minnum)//1

 四.总结

  简而言之,apply和call函数的第一个参数都是用来替换this指向的对象;apply的第二个参数使用arguments或者类似数组的参数进行传参,call的第二个或以上的参数,使用独立单位,一个一个进行传参;执行顺序是apply或call的第一个参数先执行得到结果,然后执行apply或call前面的函数,执行的时候用已经执行的结果所指代的this去执行。apply和call的使用除了参数上的使用方式不同外,功能是一模一样的。

  以上内容纯属个人理解,有误勿喷请指出!谢谢!