开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 5 天,点击查看活动详情
this是什么
在 JavaScript 中,this 是一个动态型变量指针,this的指向是在函数被调用的时候确定的,动态指向当前函数的运行环境,这就导致this的指向会让人迷惑,可以说this具有运行期绑定的特性。
1. 全局
全局环境中的 this 指向它本身,在浏览器里面 this 等价于window对象, var === this === winodw,如果你声明一些全局变量,这些变量都会作为this的属性。
a = 1
var b = 2;
this.c = 3;
window.d = 4;
console.log(window === this); // true
console.log(a,b,c,d); // 1,2,3,4
2. 函数
this的指向,是在函数被调用的时候确定的。 来两个栗子瞅瞅↓
// 栗子一
var a = 1
function fn() {
let a = 2
console.log(this.a)
}
fn() // 1
调用
fn()相当于window.fn(),fn可以说是被window所拥有,所以this指向window全局对象。
// 栗子二
var a = 1
function fn() {
let a = 2
function foo() {
console.log(this.a)
}
foo()
}
fn() // 1
在一个函数上下文中,
this由调用者提供,由调用函数的方式来决定,如果函数独立调用,那么该函数内部的this则指向undefined。但是在非严格模式中,当this指向undefined时,它会被自动指向全局对象。
3. 作为对象的一个方法
如果调用者函数,被某一个对象所拥有,那么该函数在调用时,内部的this指向该对象。
var a = 1
var obj = {
a: 2,
c: this.a + 10,
fn: function () {
return this.a
}
}
console.log(obj.c) // 11
console.log(obj.fn()) // 2
注意:单独的
{}不会形成新的作用域,计算obj.c,因为没有作用域限制,此时this还是指向全局,即打印11。调用fn()被obj对象所拥有,this即指向obj
特殊栗子
var num = 10;
var obj = {
num: 20,
getNum: function(){
return this.num;
}
}
var test = obj.getNum;
console.log(test()); // 10
注意,
test是独立调用的,因此this指向undefined,在非严格模式,自动转向全局window。
4. 作为一个构造函数
构造函数的this永远指向实例化对象
why?我们一起来看看,通过构造函数创建一个实例对象的几个步骤:
一个构造函数使用new操作符调用的时候,会生成一个具有构造函数相同属性的新对象。
- 创建一个新的对象
- 将构造函数的this指向这个新对象
- 给新对象赋值(属性、方法)
- 返回这个对象
function Member(name, age = 18) {
this.name = name;
this.age = age;
this.info = function () {
console.log(this.name + "," + this.age);
}
}
var member = new Member("xiaoyu");
console.log(member); // Member { name: 'xiaoyu', age: '18',info: ƒ () }
member.info() // xiaoyu,18
5. 作为一个DOM事件处理函数
this指向触发事件的元素
var el = document.getElementById("box");
el.addEventListener("click",function(e){
console.dir(this); // duv#box
console.log(this === e.target); // true
})
6. 箭头函数
所有的箭头函数都没有自己的this,它不会创建自己的this,只能捕获其所在上下文的this值
栗子
var name = '123';
var obj = {
name: '456',
print: function() {
function a() {
console.log(this.name);
}
a();
}
}
obj.print(); // 123
这里是普通函数调用,调用 a 相当于 window.fn(),获取全局的 name 所以打印 123,但是我们把它改造成箭头函数↓
var name = '123';
var obj = {
name: '456',
print: function() {
const a = () => {
console.log(this.name);
}
a();
}
}
obj.print(); // 456
可以看到结果是456,因为箭头函数不会创建自己的this,所以它没有自己的this,它只会从自己的作用域链的上一层继承this,所以是 obj
7. apply()、call()、bind()
this绑定到指向的对象上。
apply() 和 call() 的第一个参数都是 this,区别在于通过 apply 调用时实参是放到数组中的,而通过 call 调用时实参是逗号分隔的。
function fn(sex, age) {
console.log(this.name , sex , age);
}
var obj = {
name: 'xiaoyu'
}
fn.call(obj, '男', 20); // xiaoyu 男 20
fn.apply(obj, ['女', 30]); // xiaoyu 女 30
可以看到,fn并非属于对象 obj 的方法,但是通过 call/apply 我们可以将 fn 内部的 this 绑定为 obj,因此就可以使用 this.name 访问 obj 的 name 属性了。
bind和call、apply有些相似,只是绑定方式不同, bind() 方法创建一个新的函数, 当被调用时,将其this 关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列,需要手动调用
function say(){
console.log(this.name);
}
var f = say.bind(obj);
console.log(f()); // xiaoyu
总结
都放在每一个点的第一句话了,总结完毕。