一:概念
this是JavaScript关键字;this是当前执行期上下文对象的一个属性;this在不同的环境、不同作用下表现是不同的;
二:this的表现
1. 全局上下文
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。
console.log(this === window); // true
var a = 1;
var b = function () {
return 'function'
};
console.log(window.a === a); //true
console.log(window.b === b); //true
如何获取不同环境下的全局对象?
- web浏览器:
window、self、frames、this - Node:
global - worker:
self - 通用:
globalThis
// web
var a = 'global-a';
var obj = {
a:'obj-a',
test: function () {
console.log(this.a); //obj-a
console.log(window.a); //global-a
console.log(self.a); //global-a
console.log(frames.a); //global-a
console.log(globalThis.a); //global-a
}
};
obj.test();
// node
var a = 'global-a';
global.b = 'global-b';
var obj = {
a:'obj-a',
test: function () {
console.log(this.a); //obj-a
console.log(global.a); //undefined
console.log(globalThis.a); //undefined
console.log(global.b); //global-b
console.log(globalThis.b); //global-b
}
};
obj.test();
2. 函数上下文
严格模式:如果进入执行环境时没有设置 this的值(直接调用的),this会为undefined;
非严格模式:如果进入执行环境时没有设置 this的值(直接调用的),this会为window;
'use strict';
function test() {
return this;
}
console.log(test()); //undefined
function test() {
'use strict';
return this;
}
console.log(test()); //undefined
// 谁调用函数,函数内部的执行默认就是谁(默认绑定)
window.test = function () {
'use strict';
return this;
};
console.log(window.test());
3. 类上下文(new 绑定)
类本质上也是函数; 类可以理解为一个容器/模块/壳子/作用域;
// 以下两种方式是等价的;
class Test{
constructor() {}
say(){}
static do(){}
}
const Test = (function(){
function Test(){}
Test.prototype.say = function(){}
Test.do = function(){}
window.Test = Test;
}());
this绑定:new出来的实例对象;
class Test {
constructor(){
// 实例话的时候会调用constructor函数,生成一个this对象;把属性或者方法放进去;
// this = {
// test: function(){...}
// }
this.test = function () {
console.log('11111:' + this); // 11111:[object Object]
}
}
// 这里添加的方法是在构造函数的原型上添加的
// Test.prototype = {
// test: function(){...}
// }
// 因为在自己的this中能找到test方法,就不会来找原型上的。
test(){
console.log('2222:' + this);
}
}
var obj = new Test();
obj.test();
4. 显示绑定:call、apply、bind(只生效一次)
var a = 2;
var obj = {
a: 1,
};
var obj2 = {
a: 100
};
function test() {
console.log(this.a)
}
test(); //2
test.call(obj); //1
test.apply(obj); //1
// bind只会生效一次
var test1 = test.bind(obj);
test1(); //1
var test2 = test1.bind(obj2);
test2(); //1
var t = test.bind(obj2).bind(obj);
t(); //100
5. 箭头函数
- 严格模式下也指向
window;
'use strict';
const test = ()=>{
console.log(this); //window
};
test();
const test = ()=>{
'use strict';
console.log(this); //window
};
test();
- 忽略任何形式的显示绑定更改
this;
var obj = {a:1};
var a = 2;
const test = ()=>{
console.log(this.a)
};
test(); //2
test.call(obj); //2
test.apply(obj); //2
test.bind(obj)(); //2
- 箭头函数一定不是一个构造函数;
new test(); //Uncaught TypeError: test is not a constructor
- 指向外层非箭头函数的作用域的
this指向;
var obj = {
a: 1
};
obj.test = function () {
var t1 = () => {
var t2 = () => {
// this -> obj
console.log(this);
};
t2();
};
t1();
};
obj.test();
obj.test = function () {
var t1 = function(){
var t2 = () => {
// this -> window
console.log(this);
};
t2();
};
t1();
};
obj.test();
6. 对象的方法、原型链、getter setter
取最近的引用;
var o = {prop: 37};
function independent() {
return this.prop;
}
o.b = {g: independent, prop: 42};
console.log(o.b.g()); // 42 函数中的`this`将指向`o.b`
var o = {
f: function() {
return this.a + this.b;
}
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
var obj = {};
Object.defineProperty(obj, 'a', {
get: function () {
console.log(this); //obj
}
});
obj.a;
7. 事件处理函数
当函数被用作事件处理函数时,它的this指向触发事件的元素;
var OBtn = document.getElementById('btn');
OBtn.onClick = function () {
console.log(this); // button的dom元素
};
OBtn.addEventListener('click', function () {
console.log(this); // button的dom元素
}, false);
内联事件:
<!--dom元素-->
<button onclick="console.log(this)">test</button>
<!--window-->
<button onclick="(function(){console.log(this)}())">test1</button>
优先级:new绑定 > 显示绑定(call、apply、bind) > 隐式绑定(谁调用指向谁)> 默认绑定(非严格模式window)