温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

JavaScript this绑定与this指向问题如何解决

发布时间:2023-02-27 14:44:11 来源:亿速云 阅读:71 作者:iii 栏目:开发技术

本篇内容主要讲解“JavaScript this绑定与this指向问题如何解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript this绑定与this指向问题如何解决”吧!

    一、this 绑定

    怎么理解 this?

    其实 this 就是一个指针,它指示的就是当前的一个执行环境,可以用来对当前执行环境进行一些操作。

    MDN 解释:在绝大多数情况下,函数的调用方式决定了 this 的值(运行时绑定)。this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同。ES5 引入了 bind 方法来设置函数的 this 值,而不用考虑函数如何被调用的。ES2015 引入了箭头函数,箭头函数不提供自身的 this 绑定(this 的值将保持为闭合词法上下文的值)。

    this 是如何绑定的?

    每个函数的 this 是在调用时被绑定的,完全取决于函数的调用位置。我们找到函数的调用位置,然后运用以下四种绑定规则来判断函数的 this 指向。

    1、默认绑定

    函数的 this 会默认绑定到全局对象 window 上,如果在严格模式中,this 绑定到 undefined。

    function foo (){
      console.log(this.a)
    }
    let a = 1
    foo() // 1

    2、隐式绑定

    调用位置是否有上下文对象,或者被某个对象拥有或包含。

    function foo(){
      console.log(this.a)
    }
    let obj = {
      a: 2,
      foo:foo
    }
    let a = 1
    obj.foo(); // 2
    
    function foo(){
      console.log(this.a)
    }
    let obj1 = {
      a: 2,
      foo: foo
    }
    let obj2 = {
      a: 3,
      obj1: obj1
    }
    let a = 1
    obj2.obj1.foo(); // 2

    3、显式绑定

    直接改变 this 指向,绑定到另一个执行环境

    function foo(){
      console.log(this.a)
    }
    let obj = {
      a: 1
    }
    foo.call(obj)

    4、new 绑定

    new 出来的函数 this 绑定的是新创建的对象

    function Foo(a){
      this.a = a
    }
    let bar = new Foo(2)
    console.log(bar.a) // 2

    this 绑定优先级

    默认绑定的优先级是最低的

    new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定

    1、显示绑定 VS 隐式绑定

    function foo(){
      console.log(this.a)
    }
    let obj1 = {
      a: 1,
      foo: foo
    }
    let obj2 = {
      a: 2
    }
    console.log(obj1.foo()) // 1
    obj1.foo.call(obj2) // 2

    通过以上代码我们可以看到 显式绑定 的优先级高于 隐式绑定

    2、显示绑定 VS new 绑定

    function foo(a){
      this.a = a
    }
    let obj1 = {
      foo
    }
    let bar = foo.bind(obj1)
    bar(2)
    console.log(obj1.a) // 2
    let bar2 = new bar(3)
    console.log(obj1.a) // 2
    console.log(bar2.a) // 3

    new 修改了显示绑定 调用 bar 中的 this,所以 new 绑定的优先级高于显式绑定

    二、this 指向

    判断准则

    第一准则:this 永远指向函数运行时所在的对象,而不是函数被创建时所在的对象。(不包含箭头函数)

    第二准则:无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象

    判断顺序

    • 函数是否在 new 中调用,如果是的话 this 绑定的是新创建的对象;

    • 函数是否通过 call、apply、bind 的方式调用,如果是的话 this 绑定的是指定的对象;

    • 函数是否在某个上下文中被调用,如果是的话 this 绑定的是函数调用的上下文;

    • 除此之外 this 绑定的就是全局对象 在严格模式下绑定的是 undefined。

    常见的指向问题

    • 箭头函数没有自己的 this 指针(需要从执行上下文来进行判断)

    三、改变 this 指向

    有四种方式

    • 变量保存 this:将 this 临时保存下来

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

    • bind():会有一个返回值,返回值是一个拥有第一个函数作用域的新的函数体

    • apply():调用一个具有给定 this 值的函数,以及以一个数组(或一个类数组对象)的形式提供的参数。

    变量保存 this

    var _this = window;
    var obj = {
        name:"张三",
        show:function(){
            console.log(this) //obj
            console.log(_this) // window
        }
    }
    obj.show()

    call

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

    函数名称.bind(参数1,参数2,a,b,c.....)
        参数1:当前函数的作用域
        参数2:需要传递的参数,参数是一个一个传

    function fn(a,b){
        console.log(this,a,b)
    }
    document.onclick = functioin(){
        fn.call(document,1,2)
    }

    可以使用 call 来实现继承:写一个方法,然后让另外一个新的对象来继承它(而不是在新对象中再写一次这个方法)。

    function Product(name, price) {
      this.name = name;
      this.price = price;
    }
    function Food(name, price) {
      Product.call(this, name, price);
      this.category = 'food';
    }
    function Toy(name, price) {
      Product.call(this, name, price);
      this.category = 'toy';
    }
    var cheese = new Food('feta', 5);
    var fun = new Toy('robot', 40);

    bind

    bind 创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

    特性就是会有一个返回值,返回值是一个拥有第一个函数作用域的新的函数体

    函数名称.bind(参数1,参数2.....)() // 必须调用一下
        参数1:当前函数的作用域
        参数2:需要传递的参数

    var obj = {
        name:"张三",
        show:function(val){
            console.log(this) //obj  没有修改前
            console.log(this,1) // document 1     修改后
        }
    }
    obj.show().bind(document,1)()

    MDN:ECMAScript 5 引入了 Function.prototype.bind()。调用 f.bind(someObject) 会创建一个与 f 具有相同函数体和作用域的函数,但是在这个新函数中,this 将永久地被绑定到了 bind 的第一个参数,无论这个函数是如何被调用的。

    apply

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

    函数名称.bind(参数1,[参数2,a,b,c.....])
        参数1:当前函数的作用域
        参数2:需要传递的参数   数组

    function fn(a,b,c){
        console.log(this,a,b,c)
    }
    document.onclick = functioin(){
        fn.apply(document,[1,2,3])
    }

    call ,apply ,bind 三者的区别

    不同点:

    • bind 会有一个返回值,返回值是函数体,因此需要加上 () 才能调用 

    • call,apply 是没有返回值的,当改变函数 this 指向的时候,函数就会执行,不需要加 () 调用

    • call 传递参数的时候是一个一个传递的

    • apply 是传递一个数组或者类数组对象的参数

    到此,相信大家对“JavaScript this绑定与this指向问题如何解决”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI