JavaScript之this解析

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: this的关键字是JavaScript中最复杂的机制之一,它是一个很特别的关键字,被自动定义在所有函数作用域中。但是即使是非常有经验的JavaScript开发者也很难说清它到底指向的是什么。 ——来源《你不知道的JavaScript上卷》

要说 JavaScript 这门语言最容易让人困惑的知识点,this 关键词肯定算一个。学习 this 会拓展你的知识,加深对代码的理解。即使你并不打算在你的代码库中使用它,了解清楚 this 的指向也能让你在接手别人代码、理解代码逻辑的时候事半功倍。

一、在普通函数中的指向

(1)如果一个函数中有this,但是它没有被上一级对象所调用,那么this指向就是window(非严格模式下)/ undefined(严格模式下)。

function a(){     
  var user = "李明"     
  console.log(this); // 非严格模式为window,严格模式为undefined         
  console.log(this.user); //非严格模式为undefined,严格模式报错 
} 
a(); 

(2)如果一个函数中有this,这个函数有被上一级调用,那么this指向的就是上一级的对象。

var o = {     
  user:"李明",     
  fn:function(){         
    console.log(this.user);  //李明     
  } 
};
o.fn(); 

(3)如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它的上一级的对象。

var o = {     
  a:10,     
  b:{         
    a:12,         
    fn:function(){             
      console.log(this.a); // 12         
    }     
  } 
}; 
o.b.fn(); 

总结:this永远指向最后调用它的对象,也就是看他执行时是谁调用的。
注意:将含this的的函数,赋值给变量后,再单独执行该对象,那么this指向就是window(非严格模式下)/ undefined(严格模式下)。

var o = {     
  a:10,     
  b:{         
    a:12,         
    fn:function(){             
      console.log(this); // 非严格模式为window,严格模式为undefined                
      console.log(this.a); //非严格模式为undefined,严格模式报错         
    }     
  } 
}; 
var j = o.b.fn; //将fn赋值给变量j,并没有执行 
j();  //执行,但它没有被上一级调用

二、在构造函数中的指向

(1)构造函数中无return
this指向函数的实例。
因为:new关键字会创建一个空对象,然后会自动调用apply(),将this指向这个空对象。创建实例相当于复制了一份构造函数到实例对象里。

function Fn(){     
  this.user = "李明"; 
}; 
var a = new Fn();  // Fn {user: "李明"} 
console.log(a.user); // 李明 

(2)构造函数中有return
如果返回的是一个引用类型的值,那么使用new创建实例后,this指向的是那个返回的值; 如果返回值不是一个引用类型的值,那么this还是指向函数的实例。

/* * 示例1 */ 
function Fn(){       
  this.user = '李明';       
  return [1,2];  // 或者{},或者function(){} 
}; 
var a = new Fn;   
console.log(a);  // [1,2] 
console.log(a.user); // undefined 
/* * 示例2 */ 
function Fn()   {       
  this.user = '李明';       
  return {user:"lily"};   
}; 
var a = new Fn;  
console.log(a); // {user: "lily"} 
console.log(a.user); //lily 
/* * 示例3 */ 
function Fn()   {       
  this.user = '李明';       
  return 1; // 或者String,或者Boolean,或者Symbol,或者undefined,或者null 
};
var a = new Fn;   
console.log(a); // fn {user: "李明"} 
console.log(a.user); // 李明 

扩展:当使用new运算符时,如果没有参数要传,括号是可以省略来简化写法的。但有一些工具可能会认为这是不规范的写法,进而报警告。
但要注意:new运算符与属性调用一起使用时,有无括号是有区别的。(因为.的优先级高于new)

function Fn()   {       
  this.user = '李明';   
}; 
var a = new Fn.user;   // Fn.user is not a constructor 
var b = new Fn().user;  // '李明' 

三、在事件函数中的指向

this指向触发这个事件的标签。

<button class="btn1">button1</button>

<body>
    <button class="btn1">button1</button>
    <button class="btn2">button2</button>
    <button class="btn3">button3</button>
    <script type="text/javascript">
            
            
        for(var i = 1; i < 4; i++) {
            var btn = document.getElementsByClassName('btn'+i)[0];
            btn.onclick = function () {
                    console.log(this); //分别是btn1、btn2和btn3对应的标签
            }
        } 
    </script>
</body>

注意:

 <button onclick="handleClick()"></button>
 <script>
    function handleClick(){
        console.log(this);  //Window
    };
</script>

四、在定时器中的指向

this指向window。

setInterval( function () {
    console.log(this);  //window
},1000);

setTimeout(function() {
    console.log(this);  //window
}, 1000)


var a = 23;
function Demo() {
      this.a = 12;
      var self = this;
      setInterval(this.show, 1000);
}
Demo.prototype.show = function() {
    alert(this.a);
};
var demo = new Demo();
demo.show();
// 12
// 23.........23

五、在箭头函数中的指向

箭头函数不绑定this,它的this来自于作用域链的上一层。

function foo() {
  setTimeout(() => {
    console.log(id); // {id: 42}
    console.log('id:', this.id);  // id: 42
    //setTimeout里的函数使用了箭头函数,所以它会和外层的this保持一致,也就是{ id: 42 }
    //如果setTimeout里的是普通函数,执行时this应该指向全局对象window,这时应该输出21。
  }, 100);
}
var id = 21;
foo.call({ id: 42 });

使用call/apply/bind无法修改箭头函数的this指向,它是固定的。

function foo() {
    //返回箭头函数
    return(a) => {
        //this 继承自foo()
        console.log(this.a);
    };
}
var obj1 = {
    a:2
};
var obj2 ={
    a:3
};
var bar = foo.call(obj1);
bar.call(obj2); //是2, 不是3!!!
//箭头函数this对象的指向是固定的,所以后面的call修改不了绑定。

六、可以使用call/apply/bind可以修改this指向(除箭头函数外)

注意:对箭头函数使用call/apply/bind时,只能传递参数,不能绑定this。(他们的第一个参数会被忽略)

const obj = {
    a: () => {
        console.log(this)
    }
}
obj.a.call('123')  //打出来的结果依然是window对象
//箭头函数本身与a平级以key:value的形式,也就是箭头函数本身所在的对象为obj,而obj的this就是window,因此这里的this实际上是window

七、全局作用域时,严格模式与非严格模式下,this的指向

非严格模式下,默认的this是window;
严格模式("use strict;")下,默认的this是undefined。
例外:
1、定时器的回调函数为普通函数时,无论严格模式还是非严格模式,函数内this都指向window。
2、箭头函数中,箭头函数的作用域的上一层的this,如果是全局作用域,无论严格模式还是非严格模式,函数内this都指向window(因为ES6中,全局作用域下,无论是否为严格模式,this都指向window)

相关文章
|
2月前
|
JavaScript 前端开发 Go
CSS 与 JS 对 DOM 解析和渲染的影响
【10月更文挑战第16天】CSS 和 JS 会在一定程度上影响 DOM 解析和渲染,了解它们之间的相互作用以及采取适当的优化措施是非常重要的。通过合理的布局和加载策略,可以提高网页的性能和用户体验,确保页面能够快速、流畅地呈现给用户。在实际开发中,要根据具体情况进行权衡和调整,以达到最佳的效果。
|
2月前
|
存储 前端开发 JavaScript
JavaScript垃圾回收机制深度解析
【10月更文挑战第21】JavaScript垃圾回收机制深度解析
99 59
|
2月前
|
机器学习/深度学习 自然语言处理 JavaScript
信息论、机器学习的核心概念:熵、KL散度、JS散度和Renyi散度的深度解析及应用
在信息论、机器学习和统计学领域中,KL散度(Kullback-Leibler散度)是量化概率分布差异的关键概念。本文深入探讨了KL散度及其相关概念,包括Jensen-Shannon散度和Renyi散度。KL散度用于衡量两个概率分布之间的差异,而Jensen-Shannon散度则提供了一种对称的度量方式。Renyi散度通过可调参数α,提供了更灵活的散度度量。这些概念不仅在理论研究中至关重要,在实际应用中也广泛用于数据压缩、变分自编码器、强化学习等领域。通过分析电子商务中的数据漂移实例,展示了这些散度指标在捕捉数据分布变化方面的独特优势,为企业提供了数据驱动的决策支持。
82 2
信息论、机器学习的核心概念:熵、KL散度、JS散度和Renyi散度的深度解析及应用
|
2月前
|
JavaScript 前端开发 索引
JavaScript ES6及后续版本:新增的常用特性与亮点解析
JavaScript ES6及后续版本:新增的常用特性与亮点解析
42 4
|
24天前
|
前端开发 JavaScript
JavaScript新纪元:ES6+特性深度解析与实战应用
【10月更文挑战第29天】本文深入解析ES6+的核心特性,包括箭头函数、模板字符串、解构赋值、Promise、模块化和类等,结合实战应用,展示如何利用这些新特性编写更加高效和优雅的代码。
41 0
|
2月前
|
JavaScript 前端开发 开发者
原型链深入解析:JavaScript中的核心机制
【10月更文挑战第13天】原型链深入解析:JavaScript中的核心机制
32 0
|
2月前
|
JavaScript API
深入解析JS中的visibilitychange事件:监听浏览器标签间切换的利器
深入解析JS中的visibilitychange事件:监听浏览器标签间切换的利器
126 0
|
2月前
|
JavaScript
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
深入解析:JS与Vue中事件委托(事件代理)的高效实现方法
45 0
|
2月前
|
存储 JavaScript 前端开发
Vue.js项目中全面解析定义全局变量的常用方法与技巧
Vue.js项目中全面解析定义全局变量的常用方法与技巧
44 0
|
2月前
|
前端开发 JavaScript UED
JavaScript异步编程深入解析
【10月更文挑战第8天】JavaScript异步编程深入解析
17 0

推荐镜像

更多