文章目录
this的指向问题
this的指向实在让人脑阔痛,害我掉了3根头发,目前也才弄懂了一丢丢
本文只是博主个人学习过程中的简单总结,知识点并不深入,文章仅供参考,有问题可指出改正哦,其他情况以后遇到再补充哈。。。
1、概述
this是函数运行时自动生成的一个内部对象,只能在函数内部使用,指向调用它的对象,并且指向的是最后调用它的对象。
为什么javascript中要this这个设计? 看如下例子,虽然运行的都是同一个函数,但执行的结果却可能会不同。
var obj = {
name: 1,
say: function() {
return this.name;
}
};
window.name = 2;
window.say = obj.say;
console.log(obj.say()); // 1
console.log(window.say()); // 2
分析:
1、javascript内存结构中的堆栈(1)堆heap是动态分配的内存,大小不定也不会自动释放,栈stack为自动分配的内存空间,在代码执行过程中自动释放。JavaScript在栈内存中提供一个供Js代码执行的环境,关于作用域以及函数的调用都是栈内存中执行的。
(2)Js中基本数据类型String、Number、Boolean、Null、Undefined、Symbol,占用空间小且大小固定,值直接保存在栈内存中,是按值访问,对于Object引用类型,其指针放置于栈内存中,指向堆内存的实际地址,是通过引用访问。
==========================================
2、针对上面题目分析
内存中对于obj对象是存放在堆内存的,如果在对象中的属性值是个基本数据类型,那么其会跟这个对象存储在同一块内存区域,但是这个属性值同样可能是一个引用类型,那么对于say这个函数也是存在于堆内存中的,实际上在此处我们可以将其理解为这个函数的实际定义在一个内存区域(以一个匿名函数的形式存在),而obj这个对象同样在其他的一个内存区域,obj通过say这个属性指向了这个匿名函数的内存地址,obj --say–> funtion,那么此时问题来了,由于这种内存结构,我们可以使任何变量对象等指向这个函数,所以在JavaScript的函数中是需要允许我们取得运行环境的值以供使用的,我们必须要有一种机制,能够在函数体内部获得当前的运行环境context,所以this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。
2、正常模式下的this指向
2.1 普通函数this
1、总是代表直接调用者,谁调用就指向调用它的对象
var obj = {
name:'张三',
sayMyName:function(){
console.log(this.name);
}
}
obj.sayMyName(); // 张三
obj调用了sayMyName方法,所以sayMyName方法中的this指向了obj,而obj中有属性name,所以this.name就相当于obj.name.
2、默认情况下,如果没有直接调用者,this指向window/global
示例一:
function myMethods(){
console.log(this);
}
myMethods(); // global/window
分析:可以看到默认情况无直接调用者时this是指向全局对象的,node环境下指向global,浏览器环境下指向window。
示例二:
function myMethods(){
var a = 0;
console.log(this);
console.log(this.a);
}
myMethods(); // global undefined
分析:这个例子中的a是个局部变量,而this指向的是全局对象global,而在全局作用域下找不到a,所以返回undefined
示例三:
function a(){
age = 12;
function b(){
return this.age;
}
console.log(b()); //12
}
a()
分析:结果输出的是12,因为age变量会提升为全局变量,所以可以通过全局对象this(global)来调用这个全局变量(age)。
3、当使用call,apply,bind绑定对象时,this指向绑定的对象
var person1 = {
fullName:function(){
return this.firstName + " " + this.lastName;
}
};
var person2 = {
firstName:"jack",
lastName:"james",
}
console.log(person1.fullName()); //undefined undefined
var name = person1.fullName.call(person2);
console.log(name); //jack james
2.2 箭头函数中的this
1、沿着作用域链一层层往上找,直到找到合适的对象,那么this指向这个对象
2、如果沿着作用链一直找直到window全局对象,那么this指向全局对象
a = 10; // 全局a
b = 30; // 全局b
var func = () => {
var b = 20; // 局部b
console.log(a); // 10
console.log(b); // 30
}
func()
可以看到
(1)箭头函数中是没有定义a变量的,但却能拿到a的取值,这就是沿着作用域往上找,找到了位于全局中的变量a
(2)如果既有局部变量b又有全局变量b,那么就近输出局部变量b的值。
3、all、apply、bind等方法也改变不了箭头函数this的指向
var person1 = {
fullName: () => {
return this.firstName + " " + this.lastName;
}
};
var person2 = {
firstName: "jack",
lastName: "james",
}
console.log(person1.fullName()); //undefined undefined
var name = person1.fullName.call(person2);
console.log(name); // undefined undefined
2.3 new构造函数中的this
指向构造出来的实例对象。
const obj = new Object();
obj.name = "张三"
obj.sayHello = function(){
console.log(this); // { name: '张三', sayHello: [Function (anonymous)] }
console.log(this.name); // 张三
}
obj.sayHello();
/*
{ name: '张三', sayHello: [Function (anonymous)] }
张三
*/
2.4 事件绑定中的this
this指向触发事件的目标对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>this的使用</title>
</head>
<body>
<button id="btn">点击</button>
<script>
const btn = document.getElementById('btn')
btn.onclick = function(){
console.log(this); // <button id="btn">点击</button>
}
</script>
</body>
</html>
这里触发事件的目标对象就是button标签
2.5 立即执行函数中的this
指向的是全局对象global
(function(){
console.log(this); // global
console.log('hello');
})()
2.6 定时器函数中的this
指向的是全局对象global
function delayOutput(){
setTimeout(()=>{
console.log('hello');
console.log(this);
},3000)
}
delayOutput()
3、严格模式下的this指向问题
3.1 全局上下文中的this
在严格模式下,在全局作用域中,node环境下this指向{}对象,浏览器环境下指向window
- node环境下:
"use strict"
console.log(this); // {}
- 浏览器环境下:
"use strict"
console.log(this) // window
3.2 函数上下文中的this
函数上下文中的this默认指向undefiend
"use strict"
function f1(){
console.log(this); // undefined
}
f1()
3.3 对象的函数中的this
默认指向调用函数的对象实例。
"use strict"
var obj = new Object();
obj.a = 10;
obj.func = function(){
return this.a
}
console.log(obj.func()); // 10
3.4 事件处理函数中的this
在严格模式下,在事件处理函数中,this指向触发事件的目标对象。
3.5 内联事件处理函数中的this
在严格模式下,在内联事件处理函数中,如果use strict
的位置不同,会出现以下两种情况:
<button onclick="alert((function(){
'use strict'; return this})());">内联事件处理1
</button>
<!-- 警告窗口中的字符为undefined -->
<button onclick="'use strict'; alert(this.tagName.toLowerCase());">
内联事件处理2
</button>
<!-- 警告窗口中的字符为button -->