前端面试之你必须知道的this指向~

前文

来吧来吧,又要长脑子了,关于this指向那些不得不知的秘密,下面就让我们一一揭晓~

this绑定规则

首先我们要清楚:JS 中的 this 代表的是当前行为执行的主体

下面都是普通函数的this绑定规则,加粗的是重点

  • this指向的是函数运行时所在的对象;
  • 全局环境this相当于window; 若没有调用函数则指向全局
  • 嵌套函数的 this取决于最里一层的调用方式
  • 使用call、apply、bind绑定的,this指向绑定的对象。
  • 方法调用的时候,没有任何前缀,则指向window,例如function fn(){console.log(this)}; fn()
  • new构造函数,指向new出来的对象;
  • 以下情况,this 会 100% 指向 window
    • 立即执行函数(IIFE)
    • setTimeout 中传入的非箭头函数、setInterval 中传入的非箭头函数

箭头函数:

  • 箭头函数指向外层引用的this(这个外层指的是非箭头函数)
  • 箭头函数指向在定义的时候就是固定好的,不可以修改,call、apply也不行
const name = 2; 
const p1 = {
	name:'inner',
    foo:()=>{console.log(this.name)}
  	}
p1.foo()
  • 这里指向的就是外层this,就是p1的this,所以就是p1.foo()的结果是2

具体案例

1、方法调用 & 函数调用

const obj = {
  name: 'Alice',
  greet: function() {
    console.log(this.name);
  }
};

obj.greet(); // 1)输出什么?
const greetFunc = obj.greet;
greetFunc(); // 2)输出什么?

输出结果
1)输出:‘Alice’,方法调用,this 指向调用该方法的对象 obj。
2)输出:undefined,函数调用,this 默认指向全局对象或 undefined。

2、多层嵌套

const obj = {
  name: 'Bob',
  outer: function() {
    function inner() {
      console.log(this.name);
    }
    inner();
  }
};

obj.outer(); // 输出什么?

输出结果: undefined
inner 是普通函数,直接调用时 this 指向全局对象或 undefined,而非 obj。

3、箭头函数的多层嵌套

  • 指向的是最近一层的普通函数的this
const obj = {
  name: 'Charlie',
  outer: function() {
    const inner = () => {
      console.log(this.name);
    };
    inner();
  }
};

obj.outer();

输出结果: ‘Charlie’

  • 箭头函数的 this ,定义时候就决定了,是继承自外层作用域(outer 的 this),而 outer 是方法调用,this 指向 obj。
  • 如果outer也是箭头函数,指向的就是全局啦,结果也就变成undefined了

4、回调函数中的 this

const obj = {
  name: 'David',
  handleClick: function() {
    setTimeout(function() {
      console.log(this.name);
    }, 100);
  }
};

obj.handleClick();

输出结果: undefined
setTimeout 的回调函数是普通函数,this 默认指向全局对象或 undefined。

修复方法:定时器使用箭头函数或绑定 this:

setTimeout(() => {
  console.log(this.name); // 输出 'David'
}, 100);

5:构造函数中的 this

function Person(name) {
  this.name = name;
  this.greet = function () {
    console.log(this.name);
  };
}
const alice = new Person("Alice");
alice.greet(); // 1)输出什么?  
const greetFunc = alice.greet; 
greetFunc(); // 2)输出什么?

结果输出:
1)输出:‘Alice’,方法调用,this 指向实例 alice。
2)输出:undefined, 函数调用,this 默认指向全局对象或 undefined。

6:多层 call 绑定

const obj1 = { name: "Frank" };
const obj2 = { name: "Grace" };
function logName() {
  console.log(this.name);
}
logName.call(obj1).call(obj2); // 输出什么?

结果输出: ‘Frank’
logName.call(obj1) 立即执行,输出 ‘Frank’。 由于 logName 没有返回值,后续的 .call(obj2) 会报错(实际题目可能有陷阱)。

7:事件监听中的 this

<button id="btn">Click Me</button>
<script>
  const button = document.getElementById('btn');
  button.addEventListener('click', function() {
    console.log(this); // 输出什么?
  });
</script>

结果输出: <button id="btn">
事件监听回调中,this 指向触发事件的 DOM 元素(即按钮本身)。

8:箭头函数&普通函数&&call大汇总

var name = 'window'
var person1 = {
    name: 'person1',
    foo1: function () {
        console.log(this.name)
    },
    foo2: () => {
        console.log(this.name)
    },
    foo3: function () {
        return function () {
            console.log(this.name)
        }
    },
    foo4: function () {
        return () => {
            console.log(this.name)
        }
    }
}

var person2 = { name: 'person2' }

// 正题来咯
person1.foo1(); // 1)输出什么?
person1.foo1.call(person2); // 2)输出什么?

// 箭头函数person1的this
person1.foo2(); // 3)输出什么?
person1.foo2.call(person2); //  4)输出什么?

// 多个嵌套函数,则是指向最里一层调用
person1.foo3()();  // 5)输出什么?
person1.foo3.call(person2)();  // 6)输出什么?
person1.foo3().call(person2); // 7)输出什么?

// 箭头函数的this取值就是定义时候所在的对象
person1.foo4()(); // 8)输出什么?
person1.foo4.call(person2)(); // 9)输出什么?
person1.foo4().call(person2); // 10)输出什么?

结果输出:

  • 分析1\2,属于普通方法调用,所以this指向调用者,以及call绑定者,所以1)是person1,2)是person2
  • 分析3\4,属于箭头函数调用,定义的时候就已经确定了,this指向的是全局,故3和4都是window
  • 分析5\6\7,属于嵌套函数的调用,指向的是最里层的this,除了7改变了最里层的this以外,其他都属于无效操作,指向还是全局,故结果为5):window, 6):window, 7):person2
  • 分析8\9\10,属于箭头嵌套函数的调用,this指向的始终是foo4的this,故结果为8):person1, 而9)改变了foo4的指向所以结果为:person2, 但是10)改的是箭头函数的this属于无效改动:所以结果还是10)person1

总结

做了那么几道题,有点意思了吧,要还是不会的话评论一下,我再找找题~

所有的this指向基本就是如下几个规则

  • 默认绑定:函数直接调用时,this 指向全局对象(非严格模式)或 undefined(严格模式)。
  • 隐式绑定:方法调用时,this 指向调用该方法的对象。
  • 显式绑定:通过 call、apply、bind 显式指定 this。
  • new 绑定:构造函数中,this 指向新创建的实例。
  • 箭头函数:继承外层作用域的 this,无法通过调用方式改变。

默认绑定、隐式绑定、显示绑定、new 绑定。优先级从低到高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值