导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

前言

全局 this

⭐️ 获取全局对象 this

web

var a = 1;
var b = function() { console.log('fun b中的this:', this) }
c = {};
console.log('this === window', this === window);
console.log('window.a === a:', window.a === a);
b();
console.log('window.c === this.c:', window.c === this.c);

Untitled

严格模式下:

"use strict";
c = 123;

Untitled

"use strict";
var b = function() { console.log('fun b中的this:', this) }
b();

Untitled

function test() {
  "use strict";
  return this;
}

window.test(); // window

// 谁调用函数,函数内部的this指向谁

⭐️ node

var a = 1;
b = function() { console.log(this) };
global.c = 2;
console.log(a);
console.log(b);
console.log(c);
console.log(global.a);
console.log(global.b);
console.log(global.c);
b();

Untitled

"use strict";
var b = function() { console.log(this) };
b(); // undefined

⭐️ class 中 this

class Father {
  constructor(age) {
    this.age = age;
  }
  swim() {
    console.log('Go swimming!!!');
  }
}

class Son extends Father {
  constructor() {
    super(23);
    this.hobby = 'travel';
    console.log(this.age);
  }
  study() {
    console.log(this);
    this.swim();
  }
}

const son = new Son();
son.study();

Untitled

Untitled

不能调换 super 顺序,得首先调用 super:

class Son extends Father {
  constructor() {
    this.hobby = 'travel';
    super(23);
  }
}

Untitled

原因是按照正常顺序:

  1. super() 被调用
  2. 调用父类 constructor
  3. 实例化父类 this,给父类 this 挂上 age 属性
  4. 再执行子类 constructor 中代码
  5. 先把父类 this 指向子类实例化的 this
  6. 给子类 this 添加上 hobby 属性
  7. 现在子类上有两个属性了,分别是 age、hobby

而如果先执行子类 constructor 中代码,后执行 super,就会导致先实例化了子类 this,再实例化父类 this,这样逻辑就不对了。

类之间操作 this

class Father {
	get fruit() {
  	return 'apple';
  }
  eat() {
  	console.log('I am eating an ' + this.fruit);
  }
}

class Son {
	get fruit() {
  	return 'orange';
  }
}

const father = new Father();
const son = new Son();

father.eat(); // apple
son.eat = father.eat;
son.eat(); // orange

⭐️ 固定 this - 常用绑定、解绑定事件

如果希望son调用eat时,还是拿的 father 中的 apple,可以在constructor中bind固定this:

class Father {
  constructor() {
    // 让函数内部的this指向固定
    // 这样无论再把eat赋给谁,this都不会改变了
    this.eat = this.eat.bind(this);
  }
	get fruit() {
  	return 'apple';
  }
  eat() {
  	console.log('I am eating an ' + this.fruit);
  }
}

class Son {
	get fruit() {
  	return 'orange';
  }
}

const father = new Father();
const son = new Son();

father.eat(); // apple
son.eat = father.eat;
son.eat(); // apple

Untitled

⭐️ call、apply、bind 的 this

var obj = {
	a: 1
}
var a = 2;

function test(b, c) {
	console.log(this);
}

test();
test.call(obj, 3, 4);
test.apply(obj, [3, 4]);

Untitled

var obj = {
	a: 1
}
var obj2 = {
	a: 100
}

function test(b, c) {
	console.log(this, b, c);
}

var test1 = test.bind(obj, 3, 4);
test1();
var test2 = test1.bind(obj2, 3, 4);
test2();

Untitled

var obj = {
	a: 1
}
var obj2 = {
	a: 100
}

function test(b, c) {
	console.log(this, b, c);
}

var test1 = test.bind(obj2, 3, 4).bind(obj, 3, 4);
test1();

Untitled

箭头函数中 this

不管是否是严格模式,全局下箭头函数的this都为window

const test = () => {
	console.log(this);
}
test(); // window
"use strict";
const test = () => {
	console.log(this);
}
test(); // window

箭头函数忽略任何形式的this指向的改变(apply,call,bind):

var obj = {
	a: 1
}

const test = () => {
	console.log(this.a);
}
test.call(obj); // undefined
test.apply(obj); // undefined
var test1 = test.bind(obj);
test1(); // undefined

箭头函数中 this 不是在执行期确定,而是声明时就已确定,而且无法更改:

var obj = {
	a: 1
}

obj.test = () => {
	console.log(this);
}
obj.test(); // window
var obj = {
	a: 1
}

obj.test = function() {
	var t = () => {
  	console.log(this); // obj
  }
  t();
}
obj.test();
var obj = {
	a: 1
}

obj.test = function() {
	var t1 = () => {
  	var t2 = () => {
    	console.log(this); // obj
    }
    t2();
  }
  t1();
}
obj.test();
var obj = {
	a: 1
}

obj.test = function() {
	var t1 = function() {
  	var t2 = () => {
    	console.log(this);
    }
    t2();
  }
  t1();
}
obj.test();

Untitled

⭐️ 对象中的 this

var obj = {
	a: 1,
  b: 2,
  test: function() {
  	console.log(this.a); // 1
  },
  test2: test2,
  c: {
  	d: 4,
    test3: function() {
    	console.log(this);
      console.log(this.d);
    }
  }
}
function test2() {
	console.log(this.b);
}
obj.test();
obj.test2();
obj.c.test3();

Untitled

var obj2 = {
	a: 1,
  b: 2,
  test3: function() {
  	function t() {
      // 这个函数t是孤立的,不是 obj2 内部的成员
      // 并不存在 obj2.t,  t()自调用,默认this为window
    	console.log(this);
    }
    t(); // window
  }
}
obj2.test3();
var a = 8;
var o = {
	a: 10,
  b: {
  	fn: function() {
    	console.log(this.a);
    }
  }
}
o.b.fn(); // undefined

原型 this

var obj = {}
obj.__proto__ = {
	e: 20
}
console.log(obj.e); // 20 原型继承
var obj = Object.create({
	test4: function() {
  	console.log(this.a + this.b);
  }
});
obj.a = 1;
obj.b = 2;
obj.test4(); // 3

⭐️ 构造函数 return this

function Test() {
	this.a = 1;
  this.b = 2;
  console.log(this); // {a:1,b:2}

  return {
  	c: 3,
    d: 4
  }
}
var test1 = new Test();
console.log(test1); // {c:3,d:4}

⭐️ 事件处理函数中的 this

<body>
  <button id="btn">点我</button>
</body>
var btn = document.getElementById('btn');
btn.onclick = function() {
  console.log(this); // btn元素
}
btn.addEventListener('click', function() {
  console.log(this); // btn元素
}, false);

Untitled

直接在元素上绑定,this 还是 btn: