神秘的this

神秘的this

this在 JavaScript 中是一个非常重要的关键字,它的指向在不同的情况下会有所不同。可以把this想象成一个"指针",它总是指向当前正在执行的代码所在的对象。

足够先进的技术都和魔法无异 --- Arthur C.Clarke

this又存在于哪里?

1.全局
2.函数体内

this的绑定规则

kotlin 复制代码
1.默认绑定:当一个函数默认调用时,不带任何修饰符的调用,该函数的this指向window
2.隐式绑定:当一个函数被某个对象所拥有,或者函数被某个上下文对象调用时,该函数中的this指向该上下文对象
3.隐式丢失:当一个函数被多个对象链式调用时,this指向最近的那个对象
4.显式绑定:通过call,apply,bind,将函数的this掰弯一个对象中
5.new绑定:this指向实例对象

没看懂对不对?单看文字没有例子,看不太懂

1.默认绑定:

javascript 复制代码
当一个函数默认调用时,不带任何修饰符的调用,该函数的this指向window,即指向全局对象

案例一

ini 复制代码
var a =1 
console.log(a);

function foo(){
    var b = 1;
    console.log(b);
}
foo();//这就是不带任何修饰符的调用

深度解析

scss 复制代码
//this指代,函数生效的词法作用对象
function foo(){
    var a = 1 
    function bar(){
        console.log(this.a); //
    }
    bar(); 
    //bar在foo的作用域里面生效
    //foo的词法作用域是全局
    //this指代全局对象即window
}
foo();

升级一下

scss 复制代码
var a = 1
function foo(){
    var a = 2
    function bar(){
        var a = 3
        function baz(){ 
            console.log(this.a);// 打印undefined
        }
        baz();
        //baz在bar的作用域里面生效
        //bar的词法作用域是foo
        //foo的词法作用域又是全局,所以this指向去全局对象
    }
   bar();
}
foo();

再升级一下

javascript 复制代码
var a = 1
function foo(){
    var a = 2
    function bar(){
        var a = 3
        function baz(){ 
            console.log(this.a);// 打印undefined
        }
        return baz;
    }
    var d = bar();
    d() //d即baz在foo中生效,foo的词法作用域是全局。this指代全局对象

}
foo();

奇怪为什么打印的还是undefined吗?this指向的是全局对象。this.a表示对象的属性,而全局这个对象中并没有a这个属性。var a = 1;a只是一个变量。

小结:默认绑定的就是全局对象

2.隐式绑定:

当一个函数被某个对象所拥有,或者函数被某个上下文对象调用时,该函数中的this指向该上下文对象

javascript 复制代码
var obj = {
    a :1,
    foo: foo
}

function foo(){
    console.log(this.a);
}
obj.foo()//当一个函数被某个对象所拥有

温馨提示:obj.foo和obj.foo()的区别

obj.foo 得到的是函数 foo 本身,即得到返回值

obj.foo() 则是对这个函数进行调用执行,会执行函数内部的代码,在这个例子中就是输出 this.a 的值。

升级一下

yaml 复制代码
var obj1 = {
    name: 'obj1',
    method1: function() {
      console.log('obj1 method1 this:', this);
    }
  };

  var obj2 = {
    name: 'obj2',
    method2: obj1.method1
  };

  obj1.method1();
  // obj1 method1 this: { name: 'obj1', method1: [Function: method1]}

  obj2.method2();
  //obj1 method1 this: { name: 'obj2', method2: [Function: method1]}
  
  
 

当执行 obj1.method1() 时,此时 this 指向 obj1 对象,所以会打印出 obj1 对象本身。

当执行 obj2.method2() 时,这是因为 obj2.method2 是对 obj1.method1 函数的引用,当调用 obj2.method2() 时,实际上是在调用 obj1.method1 函数,并且 this 的值被绑定到了 obj2 对象上。

3.隐式丢失:

当一个函数被多个对象链式调用时,this指向最近的那个对象

javascript 复制代码
var obj1 = {
    name: 'obj1',
    method1: function() {
      console.log('obj1 method1 this:', this);
    }
  };

  var obj2 = {
    name: 'obj2',
    method2: obj1
  };

  obj2.method2.method1()//相当于obj2.obj1.method();被对象链式调用选最近的
  //打印obj1 method1 this: { name: 'obj1', method1: [Function: method1] }
  
  

对比

javascript 复制代码
var obj1 = {
name: 'obj1',
method1: function() {
  console.log('obj1 method1 this:', this);
}
  };

  var obj2 = {
    name: 'obj2',
    method2: obj1
  };

  obj2.method2.method1()
  //obj1 method1 this: { name: 'obj1', method1: [Function: method1] }

javascript 复制代码
  var obj1 = {
    name: 'obj1',
    method1: function() {
      console.log('obj1 method1 this:', this);
    }
  };

  var obj2 = {
    name: 'obj2',
    method2: obj1.method1
  };

  obj2.method2()
//obj1 method1 this: { name: 'obj2', method2: [Function: method1]}

第一个就是明显的隐式绑定,对象链式绑定,可以拆分成(obj2.obj1).method()

第二个可以这样拆分,obj2.(obj1.method()),obj2引用了method方法

4.显式绑定:

通过call,apply,bind,将函数的this掰弯一个对象中

javascript 复制代码
function myFunction(a, b) {
  console.log('this.name:', this.name, ', a:', a, ', b:', b);
}

// 使用 call
const obj1 = { name: 'obj1' };
myFunction.call(obj1, 1, 2);//this.name: obj1 , a: 1 , b: 2

这里使用 call 方法来调用 myFunction 函数。call 方法的第一个参数 obj1 就是明确指定的 this 的值,即让 myFunction 函数内部的 this 指向 obj1 对象。后面的 12 则是传递给函数的参数。所以在函数内部,this.name 会是 obj1name'obj1'a1b2

ini 复制代码
// 使用 apply
const obj2 = { name: 'obj2' };
myFunction.apply(obj2, [3, 4]);//this.name: obj2 , a: 3 , b: 4

apply 方法与 call 类似,也是用于指定 this 的指向。不同的是,它的第二个参数是一个数组,数组中的元素就是要传递给函数的参数。所以这里函数内部 this.nameobj2name 'obj2'a3b4

ini 复制代码
// 使用 bind
const obj3 = { name: 'obj3' };
const boundFunction = myFunction.bind(obj3);
boundFunction(5, 6);//this.name: obj3 , a: 5 , b: 6

bind 方法会创建一个新的函数,这个新函数的 this 被永久地绑定为指定的对象(这里是 obj3)。然后调用这个新函数 boundFunction 时,它内部的 this 就会是 obj3,参数为 56。同样地,this.nameobj3name 'obj3'

5.new绑定:

this指向实例对象

javascript 复制代码
function foo(a){
  this.a;
}

var bar  = new foo(2)
//this指向实例对象
console.log(bar.a);//2
相关推荐
开心工作室_kaic13 分钟前
基于微信小程序的校园失物招领系统的设计与实现(论文+源码)_kaic
c语言·javascript·数据库·vue.js·c#·旅游·actionscript
Small-K14 分钟前
前端框架中@路径别名原理和配置
前端·webpack·typescript·前端框架·vite
bin915318 分钟前
【EXCEL数据处理】000009 案列 EXCEL单元格数字格式。文本型数字格式和常规型数字格式的区别
大数据·前端·数据库·信息可视化·数据分析·excel·数据可视化
山语山36 分钟前
C语言——文件读写操作
java·c语言·前端·microsoft·visual studio
太阳火神的美丽人生1 小时前
Vant WeApp 开启 NPM 遇到的问题总结
前端·npm·node.js
lucifer3111 小时前
JavaScript 中的装饰器模式(十一)
javascript·设计模式
哈哈哈哈cwl2 小时前
一篇打通浏览器储存
前端·面试·浏览器
凌云行者2 小时前
使用rust写一个Web服务器——async-std版本
服务器·前端·rust
等什么君!2 小时前
JavaScript数据类型
开发语言·前端·javascript
DK七七3 小时前
【PHP陪玩系统源码】游戏陪玩系统app,陪玩小程序优势
前端·vue.js·游戏·小程序·php·uniapp