阅读 226

JS 的 call、apply 函数

两者的基本用法

call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组

call

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

call的语法

fun.call(thisArg, arg1, arg2, ...)
复制代码

参数

  • thisArg

    fun 函数运行时指定的 this 值。if(thisArg == undefined|null) this = window,if(thisArg == number|boolean|string) this == new Number()|new Boolean()| new String()

  • arg1, arg2, ...

    指定的参数列表。

call的应用

使用 call 方法调用父构造函数实现继承

在该例子中,子构造函数Sun()通过调用父构造函数Father()call 方法来实现继承,此时Sun()函数中拥有了Father()函数中的属性。

function Father(name,age){
	this.name = name;
	this.age = age;
	this.book=['数据结构','计算机网络','算法']
	console.log('1.执行到Father---名字:'+this.name+'; 年龄:'+this.age+' 书籍:'+this.book);

}
function Sun(name,age){
	Father.call(this,name,age);
	this.subject = '软件专业';
	console.log('2.执行到Sun---专业:'+this.subject);
}
var sun = new Sun('gxm','20');
	sun.book.push('javaScript');
	console.log('3.改变sun.book:'+sun.book);
	
var sun2 = new Sun('xz','22');
复制代码

运行结果

1.执行到Father---名字:gxm; 年龄:20 书籍:数据结构,计算机网络,算法
2.执行到Sun---专业:软件专业
3.改变sun.book:数据结构,计算机网络,算法,javaScript

1.执行到Father---名字:xz; 年龄:22 书籍:数据结构,计算机网络,算法
2.执行到Sun---专业:软件专业
4.查看sun2.book:数据结构,计算机网络,算法
复制代码

从这个运行结果也可以看出,new出来的实例对其继承而来的属性进行改变,对于原函数来说并没有改变。

使用 call 方法调用函数并且指定上下文的 this

function play() {
  var reply = [this.player, '打', this.playName,'打了',this.playTimes].join(' ');
  console.log(reply);
}

var obj = {
  player: 'gxm',playName: '羽毛球', playTimes: '1小时'
};

play.call(obj); //gxm 打 羽毛球 打了 1小时
复制代码

如果直接运行play()函数,结果就只会是打 打了。但指定了上下文就不一样了,play.call(obj)就是将play()函数的上下文从全局的window指定到obj对象上了。所以运行出来的结果过成为gxm 打 羽毛球 打了 1小时

思考下面的代码之中有几个this:

function foo() {
  return () => {
    return () => {
      return () => {
        console.log('id:', this.id);
      };
    };
  };
}

var f = foo.call({id: 1});

var t1 = f.call({id: 2})()(); // id: 1
var t2 = f().call({id: 3})(); // id: 1
var t3 = f()().call({id: 4}); // id: 1
复制代码

上面代码之中,只有一个this,就是函数foo的this,所以t1、t2、t3都输出同样的结果。因为所有的内层函数都是箭头函数,都没有自己的this,它们的this其实都是最外层foo函数的this。

使用 call 方法调用函数并且不指定第一个参数(argument)节

在下面的例子中,我们调用了 display 方法,但并没有传递它的第一个参数。如果没有传递第一个参数,this 的值将会被绑定为全局对象。

var sData = 'Wisen';

function display() {
  console.log('sData value is %s ', this.sData);
}

display.call();  // sData value is Wisen
复制代码

注意:在严格模式下,this 的值将会是 undefined。见下文。

'use strict';

var sData = 'Wisen';

function display() {
  console.log('sData value is %s ', this.sData);
}

display.call(); // Cannot read the property of 'sData' of undefined
复制代码

apply

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

apply语法

func.apply(thisArg, [argsArray])

参数

  • thisArg

    可选的。在 func 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 nullundefined 时会自动替换为指向全局对象,原始值会被包装。

  • argsArray

    可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 nullundefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。

apply的应用

apply实现继承

function superType() {
    this.color = ['red','blue','yellow']
}
function subType() {
    //---继承了superType---
    superType.applay(this);
    //superType.call(this);
}
var instance1 = new subType();
instance1.color.push('green');
console.log('instance1.color:', instance1.color);
//instance1.color: (4) ["red", "blue", "yellow", "green"]
复制代码

用 apply 将数组添加到另一个数组

我们可以使用push将元素追加到数组中。并且,因为push接受可变数量的参数,我们也可以一次推送多个元素。

但是,如果我们传递一个数组来推送,它实际上会将该数组作为单个元素添加,而不是单独添加元素,因此我们最终得到一个数组内的数组。如果那不是我们想要的怎么办?在这种情况下,concat确实具有我们想要的行为,但它实际上并不附加到现有数组,而是创建并返回一个新数组。

但是我们想要附加到我们现有的阵列......那么现在呢? 写一个循环?当然不是吗?

apply来帮你!

var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]
复制代码

相同点

callapply的作用相同,即指定的 this 值和单独给出的一个或多个参数来调用一个函数。

关注下面的标签,发现更多相似文章
评论