likes
comments
collection

浅说this的5个场景的指向

作者站长头像
站长
· 阅读数 20

场景1、 函数直接调用时

  • this指向全局变量,node就是global,js就是window,
  • 严格模式下就是undefined

举个例子

  • 最普通的函数调用
function test () {
	console.log(this)
}
test() ; // undefined 或 Window(Object)
  • 嵌套函数调用
function son () {
	console.log(this)
}
function father () {
  son(); // 一样的,只要是普通的方法调用嵌套多少层都是这样
}
father(); // undefined 或 Window(Object)

场景2、 函数被其他对象调用时候

例如obj.fun(),这里的函数funobj点了,那么this就是指向obj这个对象,要注意是执行的时候被谁点,不是定义的时候,因为操作访问符访问方法时,方法会隐式绑定前面的对象

举例子

  • 调用对象里面的函数
const father = {
	type: 'person',
  buy: function() {
  	console.log(this)
  }
}
father.buy(); // {type: 'person', buy: ƒ}  指向了fahter这个对象
  • 调用对象里面的对象的函数
const father = {
	type: 'person',
  cat: {
  	type: 'animal',
      buy: function() {
      console.log(this)
    }
  }
}
// 注意这里是.的前面,也就是cat这个对象,而不是father
father.cat.buy(); //{type: 'animal', buy: ƒ}
  • 监听函数的时候
const father = {
  buy: function() {
  	console.log(this)
  }
}
window.addEventListener('scroll', father.buy); // undefined 或 Window(Object), 因为执行的时候是自然执行的
// 这个时候你是不是以为指向的
// 上面的函数翻译过来
window.addEventListener('scroll', function() {
  	console.log(this)
  });
// 在执行的时候其实就是自然执行,并没有被谁.fun这样执行,所以判去场景1,直接调用场景
// 这也印证了上面说的是执行时候的.(点),而不是定义时候的.(点)
  • 奇怪的语法 var a = (1, 2) 会返回第二个值
const father = {
  buy: function() {
  	console.log(this)
  }
}
// 这里也是上面的监听例子,一样,只是障眼法,实际是属于场景1的,自然执行调用 
(1, father.buy)(); // undefined 或 Window(Object), 因为执行的时候是自然执行的

\

场景3、 new一个实例的时候

this就是指向new出来的实例,因为:

new的过程

  1. 在内存中创建一个新的对象
  2. 把这个对象的prototype指向这个构造函数的prototype
  3. 然后把这个this指向新对象的this
  4. 然后执行里面的代码赋值
  5. 如果return非空对象,则正常return;如果没有return,则返回新创建的这个对象
  • new 实例
function Person(aa) {
	console.log(this)
}
let teacher = new Person('aa'); // Person {}  这里会打印出构造函数,实际上this就是指向新实例的,可以参考可以new过程发生的事情

场景4、call,apply,bind

这个三个函数可和之前的三个场景不同,这里可以去改变this的指向,要看最终他们究竟调用这三个函数把this的指向指去了哪里

call,apply

  • 改变this的指向,接受两个参数,一个是this的指向,一个是接受参数(call是接受一个一个参数,apply是接受一个数组作为参数)
  • 绑定了函数的this之后立刻执行

例子

  • call,apply
const obj = {name: 'one'}
function test (first, second) {
  console.log(first, second);
	console.log(this)
}
test.call(obj, 1, 2); // 1 2 {name: 'one'}
test.apply(obj, [1, 2]); // 1 2 {name: 'one'}

bind

  • 给你返回一个绑定了this的函数
  • bind直接传参不能动态传参
  • bind
// eg one
const obj = {name: 'one'}
function test (first, second) {
	console.log(this)
}
const fun = test.bind(obj, 1, 2);
fun(); // 1 2 {name: 'one'}

场景5、箭头函数

  • this指向离我的定义时候非箭头函数的上下文
  • apply,call,bind无效了

例子

  • 箭头函数普通场景
function one () {
  console.log(this); // {name: 'test', one: ƒ}
  // one才是arrow的定义时上下文
	const arrow = () => {console.log(this)} // {name: 'test', one: ƒ} 
  function two () {
  	console.log(this); // Window
    arrow();
  }
  two();
}

const test = {name: 'test'};
test.one = one;
test.one();

解释一下上面的例子 :

  1. 首先我们找到箭头函数 arrow
  2. arrow 定义时候最近的非箭头函数就是 one,就是指向one的this的指向
  3. one被赋值进了一个test对象的one属性里面
  4. test.one()的时候,one是指向.(点)他的对象,也就是test对象
  5. 那么arrow也是指向test对象
  • call无效了
const arrow = () => {console.log(this)};
const obj = {name: 'joe'};
arrow.call(obj); // window 绑定也没有效果

解释一下上面的例子

  1. 这里看似arrow使用call指向了this
  2. 但是call,apply,bind对箭头函数无效的
  3. 所以arrow还是指向定义时候的上一层非箭头函数的this,那么就是整个代码片段了,也就是window了

结尾

这样可以比较快速的分辨出来this的指向,但是实际比较深入我也懵懵懂懂,但是这个识别5个场景来快速辨别我是从直播课听的,感觉还是有点用,就分享一下!!!以后再深入学习。