谈谈对this的理解和绑定原理

this的理解

要想了解this,必须在脑子里想:this是什么?为什么要有this?this是干什么的?

  • this是一个关键字,它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。
  1. 作为纯粹的函数调用 this指向全局对象, fn() -->window。
  2. 作为对象的方法调用 this指向调用对象, obj.fn() -->obj
  3. 作为构造函数被调用 this指向新的对象,var obj = new person() -->obj(new会改变this指向)
  4. apply调用 this指向apply方法的第一个参数,fn.apply() -->apply(第一个实参)
  5. 箭头函数中的this永远指向 该函数定义的位置所在作用域的this。

this绑定原理

01–this指向–>调用位置–默认规则

调用位置–>函数调用生效的位置

  1. 看 --> 带()的
  2. 打断点 --> debugger(打断点) --> 在控制台callstack的第二行标识该代码的调用位置(调用的栈)

明确了函数的调用位置->在该位置时的this指向

  var obj = {
        value: 1
      }

      function fn() {
        // 'use strict'
        console.log(this) // 2 || undefind
      }
      var value = 2
      console.log(this)

      fn()

结论:

1, 独立函数的调用 --> 默认绑定
1.1 非严格模式: this --> window
1.2 严格模式: this --> undefined

02-this指向–>隐式绑定–绑定丢失
// 如果方法调用时包含在对象的里面, 此时this->该对象
      // 2.1 基本形式
       function fn() {
        console.log(this.value)
       }
       var obj = {
         value: 1,
         fn: fn
       }
       var value = 2

       obj.fn()

      // 2.2-> 距离fn最近的对象才是this指向
       function fn() {
         console.log(this.value)
       }
       var obj1 = {
        value: 1,
        fn: fn
       }
       var obj2 = {
         value: 2,
         obj1: obj1
       }
       var value = 3

       obj2.obj1.fn()
      // 2.3 -> 隐式丢失->window
       function fn1() {
         console.log(this.a)
       }
       var obj = {
         a: 1,
         fn1: fn1
       }
       var a = 2
       // fn2和obj.fn1指向同一空间
       var fn2 = obj.fn1
       console.log(this)
       fn2() // 2
      // 2.4 隐式丢失->window

       function fn1() {
         console.log(this.a)
       }
       var obj = {
         a: 1,
         fn1: fn1
       }
       var a = 2
       function fn2(fn) {
         fn()
       }
       fn2(obj.fn1) // this->window

      // 2.5 隐式丢失 -> this->window
       function fn1() {
         console.log(this.a)
       }
       var obj = {
         a: 1,
         fn1: fn1
       }
       var a = 2
      setTimeout(obj.fn1, 1000)

结论:

obj.fn() --> this --> obj

03-this指向–>显示绑定
// 3. 显示绑定: fn.call/apply() fn.bind()() -> fn的this指向的是bind/call/apply(第一个实参)
// call/bind/apply(null||undefined) 会让显示绑定规则失效->应用默认规则->this->window

        var a = 10

        function fn() {
            console.log(this.a); // ?

        }
        var obj = {
                a: 20
            }
            // fn.call(obj)
        fn.call(undefined)

结论;

fn.call(obj) -->fn里的this --> this
fn.call(undefined || null) --> 此时应用默认帮定规则 -->window

04-this指向–new绑定
// 补充
        // 1. 构造函数和普通函数没啥区别
        // 2. 如果函数调用使用了new关键字,此时函数为构造函数
        // 3. new的作用
        // 3.1 开辟空间,创造对象
        // 3.2 调用方法 new person
        // 3.3 new返回了创造的对象      
function person(name) {
        this.name = name
      }
      var name = 2
      var obj = new person(1) // person函数中的this->obj
      console.log(obj.name)

结论:

new关键字的作用:把函数中的this --> obj

05-this指向-小结-优先级
  1. 默认绑定 --> 独立调用函数 --> fn() --> window || undefined
  2. 隐式绑定 --> obj.fn() --> this–>obj
    a. 回调函数 --> 容易丢失
    b. var fn2 = obj.fn1 fn2()
  3. 显示绑定 call apply bind
    a. fn.call(obj) --> fn的this --> obj
    b. fn.call(null || undefined) -->应用默认绑定规则
  4. new绑定 --> Person方法中的this --> 实例化对象

小结:

  1. 非箭头函数:this指向方法调用位置所在上下文(作用域)的this指向
  2. 箭头函数:this指向的是该函数定义(声明)的位置所在的作用域的this
// 箭头函数的使用场景?
// 1. 构造函数不能用()=>{}
// 2. 匿名函数通常是cb->cb会出现隐式丢失->this有问题->改为箭头函数
  1. 同时出现多种绑定情况:4种绑定方式的优先级:new --> 显 --> 隐 --> 默认!!!
1. 默认规则 --> 独立调用
2. 最开始执行的函数
最后练习一下吧,检验学习成果
//第一题
var num = 1;
var myObject = {
    num: 2,
    add: function() {
        this.num = 3;
        (function() {
            console.log(this.num);
            this.num = 4;
        })();
        console.log(this.num);
    },
    sub: function() {
        console.log(this.num)
    }
}
myObject.add();
console.log(myObject.num);
console.log(num);
var sub = myObject.sub;
sub();
//分析答案
var num = 1;
var myObject = {
    num: 2,
    add: function() {
        this.num = 3; // 隐式绑定 修改 myObject.num = 3
        (function() {
            console.log(this.num); // 默认绑定 输出 1
            this.num = 4; // 默认绑定 修改 window.num = 4
        })();
        console.log(this.num); // 隐式绑定 输出 3
    },
    sub: function() {
        console.log(this.num) // 因为丢失了隐式绑定的myObject,所以使用默认绑定 输出 4
    }
}
myObject.add(); // 1 3
console.log(myObject.num); // 3
console.log(num); // 4
var sub = myObject.sub;//  丢失了隐式绑定的myObject
sub(); // 4

//1、3、3、4、4
//第二题
var obj = {
            say: function() {
                function _say() {
                    console.log(this);
                }
                console.log(obj);
                return _say.bind(obj);
            }()
        }
        obj.say()
 // 1、赋值语句是右执行的,此时会先执行右侧的对象
        var obj = {
            // 2、say 是立即执行函数
            say: function() {
                function _say() {
                    // 5、输出 window
                    console.log(this);
                }
                // 3、编译阶段 obj 赋值为 undefined
                console.log(obj);
                // 4、obj是 undefined,bind 本身是 call实现,
                return _say.bind(obj);
            }(),
        };
        obj.say();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Friday--星期五

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值