最近在拜读《你不知道的js》,而此篇是对于《你不知道的js》中this部分的笔记整理,但愿能有效的梳理,而且巩固关于this的知识点bash
一、this是在运行时进行绑定的,并不是在编写时绑定,它的上下文取决于函数调用时的各类条件,它指向什么彻底取决于函数的调用位置;ide
二、this的绑定与函数申明位置无关系,只取决于函数的调用方式;函数
三、当函数被调用时,会建立一个活动记录,即执行上下文。这包括函数在哪被调用、函数调用方式、传入的参数信息等。this则为其记录的一个属性,会在函数执行的过程当中用到;ui
首先看一段代码: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();spa
若不使用this,可将代码变换以下:code
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能够以一种更优雅的方式来传递上下文对象,使代码变得简洁且易于复用对象
先来看一段代码:作用域
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呢?string
执行foo.count时,的确向函数对象foo添加一个属性count,但函数内部代码的this并不是指向foo,而this.count是建立了一个全局变量,因此this指向了window
此时this.count的值为NaN
若要实现foo.count = 4 ,则将代码变化以下:
方法1、
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
方法2、
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的问题
方法3、
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的指向
这个问题在某些状况下是正确的,但也有错误的状况,例:
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在任何状况下都不指向函数的词法做用域
词法做用域:定义在词法阶段的做用域,即由你在写代码时将变量和块做用域写在哪里来决定