关于普通函数,箭头函数里this指向的分析看法

2021年09月15日 阅读数:4
这篇文章主要向大家介绍关于普通函数,箭头函数里this指向的分析看法,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

内容大概

  • 普通函数的this
  • 箭头函数的this

普通函数

1.结论

先说结论,普通函数的this的指向在函数定义的时候是肯定不了的,只有函数执行的时候才能肯定this到底指向谁,实际上this的最终指向的是那个调用它的对象,而且是最近的那个html

2.分析

例子1:segmentfault

function a(){ 
    var user = "函数内部a";
    console.log(this.user); //undefined
    console.log(this); //Window
}
a();

咱们知道像这种调用方式,都是window调用,因此输出如上,验证一下dom

例子2:函数

var user = "window的a";
function a(){ 
    var user = "函数内部a";
    console.log(this.user); //window的a
    console.log(this); //Window
}
a(); 

a()前面没有东西默认window.a(),调用方是window,因此此时输出“window的a”this

例子3:url

var o = {
    user:"追梦子",
    fn:function(){
        console.log(this.user);  //追梦子
 }
}
o.fn();

这里的this指向的是对象o,由于你调用这个fn是经过o.fn()执行的,那天然指向就是对象o,这里再次强调一点,this的指向在函数建立的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,必定要搞清楚这个。.net

例子4:code

var user = "window追梦子"
var o = {
    user:"追梦子",
    fn:function(){
        console.log(this.user);  //追梦子
 }
}
window.o.fn();

这里虽然最外层是window调用,可是输出的this是对象o,这跟我上面说的结论同样,this的最终指向的是那个调用它的对象,而且是最近的那个htm

例子5:对象

var o = {
    user:"追梦子",
    fn:function(){
        console.log(this) // o
        setTimeout(function(){
            console.log(this);  //window
        },1000)
        
 }
}
o.fn();

fn被对象o触发,因此输出o,定时器和延时器塞队列,最后是由window触发的,因此输出window

箭头函数(敲黑板,重点)

1.结论

  • 在定义的时候就确认了this的指向,跟普通函数在使用的时候确认是彻底不一样
  • 做用域老是指向当前做用域的上一个,上一个,上一个(很重要说3遍)!
  • 当前做用域的上一个指向的对象,就是this的指向

PS:JS的做用域通常指的是函数做用域,全局做用域,使用let那种块级做用域不算

2.分析

例子1:

var b=11;
var obj={
 b:22,
 say:()=>{
 console.log(this.b);
}
}
obj.say();//输出的值为11

say是箭头函数,当前做用域的上一个做用域就是全局,而全局指的是window,因此输出11

例子2:

var b=11;
var obj={
 b:22,
 say:function(){
  return () => {
     console.log(this.b);
  }
 }
}
obj.say()();//输出的值为22

say里面return的那个是箭头函数,当前做用域的上一个做用域是say函数,而后say函数做用域指的是obj,因此输出22

例子3:

var str = 'window';  
 
const obj = {
    str:'obj',
    fn: ()=>{
    console.log(this.str);    
    },
    fn2: function(){
    console.log(this.str)
    return {
        str: 'newObj',
        fn: ()=>{
        console.log(this.str);    
        }    
    }
    }
}
 
obj.newFn = ()=>{
    console.log(this.str);    
}
 
obj.fn(); //window
obj.newFn(); //window
obj.fn2().fn(); //输出obj,obj
  1. fn上一级是全局,因此是window
  2. newFn是在外面定义的,不过解析也是跟fn同样
  3. fn2是obj触发,因此输出obj,fn2里面返回了一个对象,对象里面有一个fn箭头函数,这个fn的上一级做用域是fn2(这里注意不要被newObj迷惑)fn2指向的对象是obj,因此输出仍是obj

例子4:

var obj = {
  str:'obj',
  fn: function(){
   return {
    str: 'inlineObj',
    fn1: function(){
     console.log(this.str); 
     return ()=>{
      console.log(this.str); 
     }
    },
    fn2: ()=>{
     console.log(this.str); 
    }
   }
  }
 }
 
 obj.fn().fn1()(); //输出inlineObj,inlineObj
 obj.fn().fn2(); //输出obj

1.obj.fn()这里注意已经返回了一个对象,因此触发fn1的时候,输出inlineObj,fn1里面return一个箭头函数,上一级做用域是fn1,fn1指向return的那个{},因此输出也是inlineObj
2.fn2的上一级做用域是fn,fn指向obj,因此输出obj

更改this的指向

普通函数能够改

var user = "window的a";
function a(){ 
    var user = "函数内部a";
    console.log(this.user);
}
var obj = {
    user:'obj的a'
}
a() //window的a
a.call(obj) //obj的a

箭头函数不能够改

var obj = {
  str:'obj',
  fn: function(){
    console.log(this.str)
   },
  fn2: function(){
    return () => {
        console.log(this.str)
    }
    
  }
}
var obj2 = {
    str:'obj2'
}
obj.fn()  //obj
obj.fn.call(obj2) //obj2
obj.fn2()() //obj
obj.fn2().call(obj2) //obj

能够看到,箭头函数就算用了call换了this指向,输出仍是当初定义的那个范围

一些比较特别

点击事件

<div id="dianji">点击事件</div>

document.getElementById('dianji').addEventListener('click',function(){
    console.log(this); // 输出dom
 })
document.getElementById('dianji').addEventListener('click',() =>{
    console.log(this); // window
 })

.addEventListener前面是dom,因此普通函数触发的时候输出dom,谁调用输出谁,而箭头函数的上一级做用域是全局,因此输出window

当this碰到return

返回空对象{}

function fn()  
{ 
    this.user = '追梦子'; 
    return {};  
}
new fn().user    //undefined

返回函数

function fn()  
{ 
    this.user = '追梦子'; 
    return function aaa(){};
}
new fn().user    //undefined

返回数字

function fn()  
{ 
    this.user = '追梦子'; 
    return 1;
}
new fn().user  //追梦子

返回null

function fn()  
{ 
    this.user = '追梦子'; 
    return null;
}
new fn().user  //追梦子

上面的列子主要说明
若是返回值是一个引用数据类型(函数,对象都属于object),那么this指向的就是那个返回的对象,若是返回值不是一个对象(基础数据类型,数值,字符串,布尔,null,undefined)那么this仍是指向函数的实例。

鸣谢
很是感谢如下几位大佬的文章
完全理解js中this的指向,没必要硬背。
ES6箭头函数的this指向详解
【ES6】两个例子明白箭头函数this指向
ES6中箭头函数中的this指向