神秘的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 对象。后面的 1 和 2 则是传递给函数的参数。所以在函数内部,this.name 会是 obj1 的 name 值 'obj1',a 为 1,b 为 2。

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

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

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,参数为 5 和 6。同样地,this.name 为 obj3 的 name 'obj3'。

5.new绑定:

this指向实例对象

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

var bar  = new foo(2)
//this指向实例对象
console.log(bar.a);//2
相关推荐
橙光成长2 小时前
PDF离线工具箱深度解析:4MB纯前端单文件,40+功能全本地运行,文件绝不上传
前端·pdf·1024程序员节
小poop8 小时前
CSS 基础与实战:从入门到精通网页美化
前端
Csvn9 小时前
运行时性能
前端
Never_every9910 小时前
位图转矢量工具哪个好?实测抠抠图AI位图转矢量工具
大数据·前端
paopaokaka_luck11 小时前
宠物门店经营管理系统(销售与库存联动、进货自动记账、 退换与退款关联、员工个人业绩、ECharts 经营分析、滞销识别与客户分层、宠物档案年龄计算)
前端·javascript·spring boot·mysql·echarts·mybatis·1024程序员节
空中湖11 小时前
用 React 写数据大屏:为什么我不建议用图表库
前端·react.js·前端框架
欣欣之王来了13 小时前
原始HTML插值:v-html指令的使用与安全风险
前端·学习·架构·项目·vue3教程
IT_陈寒13 小时前
Redis的LRU淘汰策略坑了我一整天
前端·人工智能·后端
计算机魔术师13 小时前
砍半价格、参数再涨,国产旗舰追到 Opus 鼻尖了
前端
特立独行的猫A13 小时前
10 MB 的桌面 AI 客户端:用仓颉 + 系统 WebView 替代 Electron
前端·harmonyos