zoukankan      html  css  js  c++  java
  • js笔记——理解js中的call及apply

    call及apply在js里经常碰得到,但一直感觉很陌生,不能熟练使用。怎样才能熟练应用呢?

    为什么存在call和apply?

    在javascript OOP中,我们经常会这样定义:

    function cat(){
    
    }
    
    cat.prototype={ 
        food:"fish",
        say: function(){
               alert("I love "+this.food);
         }
    }
    
    var blackCat = new cat;
    blackCat.say();
    

    但是如果我们有一个对象whiteDog = {food:"bone"},我们不想对它重新定义say方法,那么我们可以通过callapplyblackCatsay方法:

    blackCat.say.call(whiteDog);//可以理解为whiteDog"继承"了blackCat的say方法
    

    所以,可以看出call和apply是为了动态改变this而出现的,当一个object没有某个方法,但是其他的有,我们可以借助call或apply用其它对象的方法来操作。

    用的比较多的,通过document.getElementsByTagName选择的dom 节点是一种类似array的array。它不能应用Array下的push,pop等方法。我们可以通过:

    var domNodes =  Array.prototype.slice.call(document.getElementsByTagName("*"));
    

    这样domNodes就可以应用Array下的所有方法了。

    call和apply的区别

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

    因为 JavaScript 的函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。二者的作用完全一样,只是接受参数的方式不太一样。

    例如,有一个函数 func1 定义如下:

    var func1 = function(arg1, arg2) {};
    

    就可以通过 func1.call(this, arg1, arg2); 或者 func1.apply(this, [arg1, arg2]); 来调用。其中 this 是你想指定的上下文,他可以任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。

    JavaScript 中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时,用 call,而不确定的时候,用 apply,然后把参数 push 进数组传递进去。当参数数量不确定时,函数内部也可以通过 arguments 这个数组来便利所有的参数。

    深入探讨

    Function.prototype.call()
    Function.prototype.apply()
    

    方法定义

    **call方法: **
    语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
    定义:调用一个对象的一个方法,以另一个对象替换当前对象。
    说明:
    call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
    如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

    apply方法:
    语法:apply([thisObj[,argArray]])
    定义:应用某一对象的一个方法,用另一个对象替换当前对象。
    说明:
    如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
    如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。

    常用实例

    a、

    function add(a,b)  
    {  
        alert(a+b);  
    }  
    function sub(a,b)  
    {  
        alert(a-b);  
    }  
      
    add.call(sub,3,1);  
    

    这个例子中的意思就是用 add 来替换 sub,add.call(sub,3,1) == add(3,1) ,所以运行结果为:alert(4); // 注意:js 中的函数其实是对象,函数名是对 Function 对象的引用。

    b、

    function Animal(){    
        this.name = "Animal";    
        this.showName = function(){    
            alert(this.name);    
        }    
    }    
      
    function Cat(){    
        this.name = "Cat";    
    }    
       
    var animal = new Animal();    
    var cat = new Cat();    
        
    //通过call或apply方法,将原本属于Animal对象的showName()方法交给对象cat来使用了。    
    //输入结果为"Cat"    
    animal.showName.call(cat,",");    
    //animal.showName.apply(cat,[]);  
    

    call 的意思是把 animal 的方法放到cat上执行,原来cat是没有showName() 方法,现在是把animal 的showName()方法放到 cat上来执行,所以this.name 应该是 Cat

    c、实现继承

    function Animal(name){      
        this.name = name;      
        this.showName = function(){      
            alert(this.name);      
        }      
    }      
        
    function Cat(name){    
        Animal.call(this, name);    
    }      
        
    var cat = new Cat("Black Cat");     
    cat.showName(); 
    

    Animal.call(this) 的意思就是使用 Animal对象代替this对象,那么 Cat中不就有Animal的所有属性和方法了吗,Cat对象就能够直接调用Animal的方法以及属性了.

    d、多重继承

    function Class10()  
    {  
        this.showSub = function(a,b)  
        {  
            alert(a-b);  
        }  
    }  
      
    function Class11()  
    {  
        this.showAdd = function(a,b)  
        {  
            alert(a+b);  
        }  
    }  
      
    function Class2()  
    {  
        Class10.call(this);  
        Class11.call(this);  
    }  
    
    

    很简单,使用两个 call 就实现多重继承了

    推荐阅读

    1、Function.prototype.apply() - JavaScript | MDN
    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

    2、面向对象编程概述 -- JavaScript 标准参考教程(alpha)
    http://javascript.ruanyifeng.com/oop/basic.html#toc10

    3、JS中的call()和apply()方法 - 每天进步一点点! - ITeye技术网站
    http://uule.iteye.com/blog/1158829

    引用:
    1、https://www.zhihu.com/question/20289071/answer/14644278
    2、http://uule.iteye.com/blog/1158829

  • 相关阅读:
    【转】想成为为一名架构师,应该掌握哪些技术呢?
    【转】每个好架构师都是一位出色的程序员
    [LeetCode] 597. Friend Requests I: Overall Acceptance Rate 朋友请求 I: 全部的接受率
    [LeetCode]577. Employee Bonus 员工奖金
    570. Managers with at Least 5 Direct Reports 至少有5个直接汇报员工的经理
    [LeetCode] 529. Minesweeper 扫雷
    Generate Maximum revenue by selling K tickets from N windows
    [LeetCode] 311. Sparse Matrix Multiplication 稀疏矩阵相乘
    [LeetCode] 689. Maximum Sum of 3 Non-Overlapping Subarrays 三个非重叠子数组的最大和
    [LeetCode] 403. Frog Jump 青蛙跳
  • 原文地址:https://www.cnblogs.com/52fhy/p/5118253.html
Copyright © 2011-2022 走看看