this、apply、call、bind

this的指向

在绝大多数情况下,函数的调用方式决定了this的值(运行时绑定),this永远指向最后调用它的那个对象。

  1. 全局的this非严格模式指向window对象,严格模式指向undefined
  2. 对象的属性方法中的this指向对象本身
  3. apply、call、bind可以变更this指向为第一个传参
  4. 箭头函数中的this指向它的父级作用域,它本身不存在this

改变this的指向

  • 使用ES6的箭头函数
  • 在函数内部使用_this=this
  • 使用applycallbind
  • new实例化一个对象

箭头函数

箭头函数的this始终指向函数定义时的this,而非执行时。
箭头函数中没有this绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数包含,则this绑定的最近一层非箭头函数的this,否则,this为undefined。

var name = "windowsName";
var a = {
    name: "gary",
    func1: function () {
        console.log(this.name)
    },
    func2: function () {
        setTimeout(() => {
            this.func1()
        }, 100);
    }
};
a.func2() // gary

在函数内部使用_this=this

如果不使用ES6,这种方式应该是最简单的不会出错的方式了,我们是先将调用这个函数的对象保存在变量_this中,然后在函数中都使用这个_this,这样_this就不会改变了。

var name = "windowsName";
var a = {
    name: "gary",
    func1: function () {
        console.log(this.name)
    },
    func2: function () {
        var _this = this;
        setTimeout(function () {
            _this.func1()
        }, 100);
    }
};
a.func2() // gary

在这个例子中,在func2中,首先设置var _this=this,这里的this是调用func2的对象
a,为了防止在func2中的setTimeout被window调用而导致的在setTimeout中的this为window。我们将this(指向变量a)赋值给一个变量_this,这样,在func2中我们使用_this就是指向对象a了。

使用apply、call、bind

使用apply

var name = "windowsName";
var a = {
    name: "gary1",
    func1: function () {
        console.log(this.name)
    },
    func2: function () {
        setTimeout(function () {
            this.func1()
        }.apply(a), 100);
    }
};
a.func2() // gary1

使用call

var name = "windowsName";
var a = {
    name: "gary2",
    func1: function () {
        console.log(this.name)
    },
    func2: function () {
        setTimeout(function () {
            this.func1()
        }.call(a), 100);
    }
};
a.func2() // gary2

使用bind

var name = "windowsName";
var a = {
    name: "gary3",
    func1: function () {
        console.log(this.name)
    },
    func2: function () {
        setTimeout(function () {
            this.func1()
        }.bind(a)(), 100);
    }
};
a.func2() // gary3

apply、call、bind区别

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

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

apply和call的区别

apply和call基本类似,区别只是传入的参数不同。
call的词法为:

fun.call(thisArg[, arg1[, arg2[, ...]]])

apply和call的区别是apply接收的是一个包含多个参数的数组,而call方法接受的是若干个参数列表。
apply:

var a = {
     name: "gary",
     fn: function (a, b) {
         console.log(a + b)
     }
 }
 var b = a.fn
 b.apply(a, [1, 2]) // 3

call:

 var a = {
     name: 'gary',
     fn: function (a, b) {
         console.log(a + b)
     }
 }
 var b = a.fn
 b.call(a, 1, 2) // 3

bind和apply、call区别

先用刚才的例子使用bind试一下:

 var a = {
     name: 'gary',
     fn: function (a, b) {
         console.log(a + b)
     }
 }
 var b = a.fn
 b.bind(a, 1, 2) // 3

我们发现并没有输出,这是为什么呢,我们来看一下MDN上的文档说明:

bind()方法创建一个新的函数,当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。

所以我们可以看出,bind是创建一个新的函数,我们必须要手动调用:

 var a = {
     name: 'gary',
     fn: function (a, b) {
         console.log(a + b)
     }
 }
 var b = a.fn
 b.bind(a, 1, 2)() // 3

JS中的函数调用

例6:

var name = "windowsName";

function fn() {
    var name = 'gray';
    innerFunction();
    function innerFunction() {
        console.log(this.name);      // windowsName
    }
}

fn()

例7:

var name = "windowsName";
var a = {
    name : "gray",
    func1: function () {
        console.log(this.name)     
    },
    func2: function () {
        setTimeout(  function () {
            this.func1()
        },100);
    }
};
a.func2()     // this.func1 is not a function

函数调用的方法一共有4种:

  1. 作为一个函数调用
  2. 函数作为方法调用
  3. 使用构造函数调用函数
  4. 作为函数方法调用函数(call、apply)

作为一个函数调用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值