关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

javascript 之 apply()、call() 探索

发布时间:2020-08-07 18:41:57

CMAScript 规范给所有函数都定义了apply 和 call 方法,并且是非继承;
用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。
借用别的对象的方法

apply()

apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。
apply的主要用途是改变函数的作用域,在特定的作用域中调用函数,实际上等于设置函数体内的this对象的值。

apply()基本语法:

Function.prototype.apply(thisArg[, argsArray])
参数说明:

参数名参数说明
thisArg在Function 函数运行时指定到this值或者叫对象,需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。
argsArray一个数组或者类数组对象、arguments对象,非必传,其中的数组元素将作为单独的参数传给 Function函数。如果该参数的值为null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。

一句话总结:
apply() 函数用于调用当前函数Function,并且同时使用指定对象 thisArg作为本次函数执行时函数内部this指针的引用
绕口吧,这是我目前认为最精准的定义。
定义复杂切抽象来点实际的:

函数中使用

定义一个函数,两个数字相加:

let {log} = console; //es6 语法 解构function sum(x,y){
    return x+y;}log(sum.apply(null,[1,2])); // 3log(sum.apply(undefined,[3,2])); // 5log(sum.apply(this,[4,2]));  //61234567

依据定义每个函数都有apply方法,我们直接在全局模式下运行,而且是非严格模式 这个时候调用apply方法,this,null,undefined都是指向window对象。因此我们在执行apply方法的时候具体this指向哪里需要看运行时候的对象环境,全局就是widow对象,
上述例子 说明是吧sum方法放到 window对象执行
等同于直接调用sum(1,2)
在函数里面调用另外一个函数的apply方法会发生什么呢?

let {log} = console;function sum(x,y){
    return x+y;}function sum1(x,y){
    return sum.apply(this,[x,y]);}log(sum1(1,2)); // 312345678

这里 在函数 sum1 里面调用sum.apply 方法,这里的this 其实也是指向window,只有在严格模式才会指向sum1函数。这个时候相当于

function sum1(x,y){
    sum(x,y);}123

到这里看到apply到作用并不大,这么难理解作用不大岂不是浪费,来继续,牛逼的用处在下面
来我们写两个常用的字面两对象

在对象中表现

let {log} = console;let muzi ={
    name:"木子聊前端",
    showName: function(){
        console.log(this.name);
    }}let test ={
    name:"测试名字",
    showName: function(){
        console.log(this.name);
    }}// 分别运行muzi.showName(); //木子聊前端test.showName(); //测试名字test.showName.apply(muzi,[]); //木子聊前端,1234567891011121314151617

当我们在运行没有apply当时候,字面量对象都是调用自己也就是this是这样当前对象,当我们调用量apply当时候就开始发生了变化test.showName.apply(muzi,[]) 这个时候,test对象当this就变成了muzi这个对象。指向当对象属性也是muzi这个对象总结一句话
把muzi对象放到test对象showName方法执行
改动一下代码来证明这句话

let {log} = console;let muzi ={
    name:"木子聊前端"}let test ={
    name:"测试名字",
    showName: function(){
        log(this.name);
    }}test.showName.apply(muzi) // 木子聊前端1234567891011

muzi 对象一家没有showName方法了,但是执行了test.showName方法,这个时候this是指向muzi也就是说muzi对象应用到类test.showName方法里面,这个时候showName 方法属于muzi类;

继承

上面的例子基本依据说明了apply在继承中的作用我们在形象一点

let {log} = console;// 定义一个人类有两个属性,姓名和性别function Person(name,sex){
    this.name = name;
    this.sex = sex;}// 定义一个学生类,继承人类的基本属性,同时拥有自己的方法function Student(name,sex,age){
    Person.apply(this,[name,sex])
    this.age = age    this.talk = function(){
        log(`${this.name}的年龄是${this.age}`)
    }}let s = new Student('木子','男','18')s.talk(); //木子的年龄是1812345678910111213141516

说到底就是 Person 的this指向变为类 Student对象,如果蒙了在看看定义,所有底示例都是为了理解定义;

回调函数中运用

在实际开发中apply运用在回调方法中也很多,例如我们需要改变开发中调上下文就会用到:

let {log} = console;function Person(name,sex){
    this.name = name;
    this.sex = sex;
    this.getName =function(callback){
        if(callback){
            // 定义1一个回调函数 
            callback.apply(this,[name,sex])
        }
    }}let p = new Person('张三','18')p.getName(function(){
    log(`${this.name}`); // 张三})12345678910111213141516

如果我们没有使用apply 那么在调用但是this 指向调就是全局

箭头函数中到表现

我们用箭头函数改写一下开通sum 两个数字相加到方法

let {log} = console;// let sum = (x,y) =>{
    return x + y;}function  sum1(x,y){
    sum.apply(this,[x,y]); }log(sum1(1,2)) // undefined123456789

返回无效。是不是要用箭头函数才有用嗯?来改一下

let sum1 =(x,y) =>{
    sum.apply(this,[x,y]); }log(sum1(1,2)) // undefined1234

还是undefined 无效,说明apply方法在箭头函数中无效; 为什么呢? 函数箭头到this是指向定义时候到对象,不能更改,非箭头函数到this是指向运行是的对象;

call 方法

call方法和apply一样的用途唯一的区别就是apply的第二个参数是数组,call则是以枚举的形式传入一个个的参数,其他都一样看一个例子:

let {log} = console;function sum(x,y){
    return x+y;}function sum1(x,y){
    // return sum.apply(this,[x,y]);
    return sum.call(this,x,y);}log(sum1(1,2)); // 3123456789

上面所有的apply方法是示例都可以改为call 只是把数组的入参改变一下即可



/template/Home/Zkeys/PC/Static