JS——call()和apply()的用法

在上一篇文章中我们对js中的this指向问题进行了介绍,其中涉及到call()和apply()方法,在这篇文章中,我们将对call()和apply()进行探讨;

首先我们来说说这两种方法的共同点:

1. 每个函数都包含两个非继承而来的方法:call()方法和apply()方法。

2.这两个方法的作用是一样的。 都是在特定的作用域中调用函数,等于设置函数体内this对象的值,以扩充函数赖以运行的作用域。

在JS中this总是用来指向某个方法的对象,而call()和apply()的作用就是用来改变this的指向

call()和apply()作用完全一样,只是接受参数的方式不一样。

call的用法:

下面的代码演示了this指向问题,call()改变this指向,以及call()实现继承

//下面这段代码主要演示了this指向的问题

    window.color = 'red';
    document.color = 'yellow';
    var s1 = {color: 'blue' };

    changeColor(){
        console.log(this.color);
    }


    changeColor.call();         //red (默认传递参数)
    changeColor.call(window);   //red
    changeColor.call(document); //yellow
    changeColor.call(this);     //red
    changeColor.call(s1);       //blue



//下面我们将看看call是怎样改变this指向的

    var Pet = {
         words : '...',
         speak : function (say) {
              console.log(say + ''+ this.words)
         }
    }

    Pet.speak('Speak'); // 结果为:Speak...

    var Dog = {
         words:'Wang'
    }       //将this的指向改变成了Dog

    Pet.speak.call(Dog, 'Speak'); //结果为: SpeakWang



//下面这段代码我们再看看使用call()实现继承

  function Animal(name){   
        this.name = name;   
        this.showName = function(){   
             console.log(this.name);   
        }   
  }   
 
  function Cat(name){  
         Animal.call(this, name);  
  }   
 
  var cat = new Cat("Black Cat");   
  cat.showName();     //结果为:  Black Cat

apply()与call()用法类似,可参考上面的例子

下面我们看看不同点,即传入参数不同:

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

//调用该函数的两种不同方式
func.call(this, arg1, arg2);
func.apply(this, [arg1, arg2])

其中 this 是你想指定的上下文,他可以是任何一个 JavaScript 对象(JavaScript 中一切皆对象),call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组里。

我们已经看了call()和apply()的基本用法,下面我们用一些实例巩固一下:

1.数组的追加

var array1 = [1,2,3]; 
var array2 = [a,b,c]; 
Array.prototype.push.apply(array1, array2); 
// array1 值为  [1,2,3,a,b,c] 

Array.prototype.push可以实现数组的追加

2.获取数组中的最大最小值

var  numbers = [5, 458 , 120 , -215 ]; 
var maxInNumbers = Math.max.apply(Math, numbers),   //458
    maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

number 本身没有 max 方法,但是 Math 有,我们就可以借助 call 或者 apply 使用其方法。

3.验证是否为数据类型

console.log(Object.prototype.toString.call(123)) //[object Number]
console.log(Object.prototype.toString.call('123')) //[object String]
console.log(Object.prototype.toString.call(undefined)) //[object Undefined]
console.log(Object.prototype.toString.call(true)) //[object Boolean]
console.log(Object.prototype.toString.call({})) //[object Object]
console.log(Object.prototype.toString.call([])) //[object Array]
console.log(Object.prototype.toString.call(function(){})) //[object Function]

4.类数组使用数组方法

首先我们要明白什么是类数组:

1.具有length属性

2.按索引方式存储数据

3.不具有数组的push,pop等方法

常见的类数组有:arguments,NodeList

(function(){
  Array.prototype.push.call(arguments,4);
  console.log(arguments);//[1, 2, 3, 4]
})(1,2,3)


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

Javascript中存在一种名为伪数组的对象结构。比较特别的是 arguments 对象,还有像调用 getElementsByTagName , document.childNodes 之类的,它们返回NodeList对象都属于伪数组。不能应用 Array下的 push , pop 等方法。
但是我们能通过 Array.prototype.slice.call 转换为真正的数组的带有 length 属性的对象,这样 domNodes 就可以应用 Array 下的所有方法了。

下面是一个经典的面试题:

定义一个 log 方法,让它可以代理 console.log 方法,常见的解决方法是:

1:

function log(msg) {
  console.log(msg);
}
log(1);    //1
log(1,2);    //1

2:上面方法可以解决最基本的需求,但是当传入参数的个数是不确定的时候,上面的方法就失效了,这个时候就可以考虑使用 apply 或者 call,注意这里传入多少个参数是不确定的,所以使用apply是最好的,方法如下:

function log(){
  console.log.apply(console, arguments);
};
log(1);    //1
log(1,2);    //1 2

3.接下来的要求是给每一个 log 消息添加一个"(app)"的前辍,比如:

log("hello world"); //(app)hello world

该怎么做比较优雅呢?这个时候需要想到arguments参数是个伪数组,通过 Array.prototype.slice.call 转化为标准数组,再使用数组方法unshift,像这样:

function log(){
  var args = Array.prototype.slice.call(arguments);
  args.unshift('(app)');
 
  console.log.apply(console, args);
};

log('hello world')      //(app)hello world

以上是关于apply()和call()的一些用法,不尽详细,欢迎指正

猜你喜欢

转载自blog.csdn.net/qq_40856225/article/details/82821910