最近在拜读《你不知道的js》,而此篇是对于《你不知道的js》中this部分的笔记整理,希望能有效的梳理,并且巩固关于this的知识点
一、this是一种怎样的机制
1、this是在运行时进行绑定的,并非在编写时绑定,它的上下文取决于函数调用时的各种条件,它指向什么完全取决于函数的调用位置;
2、this的绑定与函数申明位置无关系,只取决于函数的调用方式;
3、当函数被调用时,会创建一个活动记录,即执行上下文。这包括函数在哪被调用、函数调用方式、传入的参数信息等。this则为其记录的一个属性,会在函数执行的过程中用到;
二、this的作用
首先看一段代码:
function identify() {
return this.name.toUpperCase();
}
function speak() {
var greeting = "Hello, I'm " + identify.call(this);
console.log(greeting);
}
var me = {
name: "Mike"
};
var you = {
name: "Jenny"
};
identify.call(me); // Mike
identify.call(you); // Jenny
speak.call(me); // Hello, I'm Mike
speak.call(you); // Hello, I'm Jenny
这段代码可在不同的上下文对象中重复使用identify(),speak();
若不使用this,可将代码变换如下:
function identify(con) {
return con.name.toUpperCase();
}
function speak(con) {
var greeting = "Hello, I'm " + identify.call(con);
console.log(greeting);
}
var me = {
name: "Mike"
};
var you = {
name: "Jenny"
};
identify(me); // Mike
speak(you); // Hello, I'm Jenny
this可以以一种更优雅的方式来传递上下文对象,使代码变得简洁且易于复用
三、对于this的误解
误解一、this指向函数自身(仅从字面上理解this的含义)
先来看一段代码:
function foo(num) {
console.log("foo: " + num);
// 记录foo被调用的次数
this.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 0; i++) {
if(i > 5) {
foo(i);
}
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);
// foo被调用了几次?
console.log(foo.count); // 0
为什么此处的foo.count值为0呢?
执行foo.count时,的确向函数对象foo添加一个属性count,但函数内部代码的this并非指向foo,而this.count是创建了一个全局变量,所以this指向了window
此时this.count的值为NaN
若要实现foo.count = 4 ,则将代码变化如下:
方法一、
function foo(num) {
console.log("foo: " + num);
// 记录foo被调用的次数
data.count++;
}
var data = {
count: 0
};
var i;
for(i = 0; i < 0; i++) {
if(i > 5) {
foo(i);
}
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);
// foo被调用了几次?
console.log(data.count); // 4
此写法虽然达到了理想的状态,但却忽略了this
方法二、
function foo(num) {
console.log("foo: " + num);
// 记录foo被调用的次数
foo.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 0; i++) {
if(i > 5) {
foo(i);
}
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);
// foo被调用了几次?
console.log(data.count); // 4
这种写法同样回避了this的问题
方法三、
function foo(num) {
console.log("foo: " + num);
// 记录foo被调用的次数
this.count++;
}
foo.count = 0;
var i;
for(i = 0; i < 0; i++) {
if(i > 5) {
// 使用call(...)可以确保this指向函数对象foo本身
foo.call(foo, i);
}
}
// foo(6);
// foo(7);
// foo(8);
// foo(9);
// foo被调用了几次?
console.log(data.count); // 4
此方法使用call,改变了上下文对象,强制将this指向foo函数对象
总结:通过以上例子说明,仅仅从字面意思来解释this是不准确的,而是要通过关注执行上下文,以及函数的调用位置来判断this的指向
误解二、this指向函数的作用域
这个问题在某些情况下是正确的,但也有错误的情况,例:
function foo() {
var a = 2;
this.bar();
}
function bar() {
console.log(this.a);
}
foo(); // RefrenceError: a is not defined
这段代码试图使用this联通foo()、bar()的词法作用域,从而让bar()可以访问foo()作用域中的变量。但this不可能在词法作用域中查到什么。因为this指向全局,而a属于foo作用域中的变量,所以无法查到
总结:this在任何情况下都不指向函数的词法作用域
词法作用域:定义在词法阶段的作用域,即由你在写代码时将变量和块作用域写在哪里来决定