在JavaScript中,每当我们使用函数或者阅读已经写好的函数时,我们经常会看到里面用到this关键字的情况。
对于一个JS的初学者(尤其是对于有“主流”语言编程经验的人),会觉得this是让人凌乱的东西。
为了理解this,我们需要理解函数的调用方法。
在《Javascript Good Parts》一书中,将函数分为了四种调用方式:
方法调用;
函数式调用;
构造器调用;
apply(call)调用。
通读《Javascript Good Parts》的4.3节(2009年4月第一版)后,我对调用方式做了一个简短的总结。
当每个函数被调用的时候,他将会收到两个参数:this和arguments。为了方便起见,我们先写一个函数。
// 例1
var f = function(x, y) {
var count = x + y + this.z;
this.total = count;
console.log(this.total);
};
当函数被调用的时候,就会得到this和arguments。
一、arguments是什么?
arguments是比较好理解的,它是一个传入实际参数的数组。这里之所以用“实际参数”,是为了和this相对应,在我们的例子中,arguments就是x和y。
由于有arguments的存在,所以js可以不必在函数定义的时候规定参数,比如上一个函数完全可以写成。
// 例2
var f = function() {
var count = arguments[0] + arguments[1] + this.z;
this.total = count;
console.log(this.total);
};
虽然上面的函数可读性变差了,但是它和例1的功能是一样的。
基于以上原理,JS并不会支持如Java一样重载,如果有这样的代码:
// 例3
var o = {
f: function(){ console.log(1); },
f: function(){ console.log(2); },
};
//注意,这段代码没有错误的,JS真是自由的国度。
但是o只会承认第二的方法,即,后面的芳芳会覆盖前面的。
二、开始this吧
下面到了this,其实上面提到的四种调用方式的区别,从this的角度看,只是this所代表的地方不同。
2.1 方法式调用。
这要求函数必须在一个对象里面,比如:
// 例4
var o = {
f: function() {
console.log(this); //
}
};
当我们使用o.f()的时候,打印出来的就是对象o。
可以看出,函数作为方法调用中,函数使用的this就是函数所在的对象。
2.2 函数式调用。
// 例5
var f = function() {
console.log(this);
};
f()执行的时候,打印出来的是全局对象。如果你使用浏览器的开发者工具(比如打开Chrome,按F12后用Console界面)输入例子,你会得到Window对象。
2.3 构造器式调用。
// 例6
var Fun = function() {
console.log(this);
};
Fun.prototype.x = function() {
return 1;
};
Fun.prototype.y = 2;
对于例6中的函数,当我们执行var f = new Fun();的时候,this是什么呢?是Fun.prototype,即Fun的原型链。
2.4 apply/call式调用
我们先了解一下apply和call调用函数的方式:
Fun.apply(Obj, [x, y]);
Fun.call(Obj, x, y);
以上两个方式,都是以Obj为对象,以x和y为参数,调用方法Fun。所不同的是apply要求参数是数组,call要求参数挨个传入。
这样我们就可以方法式调用来理解apply式的调用。
我们大致可以了解this是什么了,this就是当前函数的执行环境。那么以下几个理解或许有助于我们记忆。
如例5中函数式调用,可以把f()看作是window.f();
例6中new的调用方式可以看成Fun.call(Fun.prototype, null),当然最后还有需要把生成结果返回给f;
再进一步,所有的前三种调用方式都可以用call来模拟。如例4中o.f()可以看做f.call(o, null),而例5中f()可以看做f.call(window, null);
而把this和arguments并列理解,也就可以解释为什么函数调用时,为什么要function.apply(object, arguments)了。
三、还有几个问题
以上的解释可以理解函数调用中大部分this的问题,但是我们要注意几个问题。
3.1 匿名函数的调用。
(function() { console.log(this); })();
JS很自由,它允许函数没有名字,这种情况下,this仍然指向全局对象(浏览器中为window)。
3.2 方法中函数式的调用。
这个说法很拗口,但是确有存在。
// 例7
var o = {
f: function() {
var innerF = function() {
console.log(this);
};
innerF();
}
};
当我们使用o.f();的时候,innerF也被顺便调用了,但是打印出来的结果仍然是全局对象。
这很让人头疼,如果说例5中f()打印出来的是全局对象是因为函数f就写在window下,这里innerF距离window隔了好几层。
但是现实如此,我们只能接受。具体原因估计要查ECMAScript最初开发者的交流邮件!
这里就引入了一个问题,如果innerF想调用对象o的代码怎么办?
好在可以“曲线救国”:
var o = {
f: function() {
var that = this;
var innerF = function() {
console.log(that);
};
innerF();
}
};
当使用o.f();的时候,打印出来的就是对象o,而不是全局对象。
3.3 回调函数中的this。
// 例8
var f = function(cb) {
cb();
};
var o = {
callback: function() {
console.log(this);
}
};
f(o.callback);的结果仍然是window,可见函数的调用方式决定着this,把this和arguments作为参数理解,就更容易理解了。
当然回调函数被调用的方式是由原函数决定的。
对例8稍作修改,就可以得到不一样的结果。
// 例9
var f = function(callback) {
var innerO = {
x: 1,
cb: callback
};
innerO.cb();
};
var o = {
callback: function() {
console.log(this);
}
};
f(o.callback);
var f = function(callback) {
var innerO = {
x: 1,
cb: callback
};
innerO.cb();
};
var o = {
callback: function() {
console.log(this);
}
};
执行例9的f(o.callback);,打印结果是innerO对象。所以回调函数的使用就要看原函数的作者的意图了。
以上对于this的理解只是表象的总结,深入的了解需要查阅资料和了解浏览器的解析器
诚所谓,路漫漫其修远兮,吾将上下而求索。
var f = function(cb) {
cb();
};
var o = {
callback: function() {
console.log(this);
}
};
f(o.callback);
var f = function(cb) {
cb();
};
var o = {
callback: function() {
console.log(this);
}
};
f(o.callback);
var f = function(cb) {
cb();
};
var o = {
callback: function() {
console.log(this);
}
};
f(o.callback);
var f = function(cb) {
cb();
};
var o = {
callback: function() {
console.log(this);
}
};
f(o.callback);
分享到:
相关推荐
个人Javascript学习笔记 精华版 本资源为个人Javascript学习笔记的精华版,涵盖了Javascript的基础知识、事件处理、对象和系统函数、浏览器对象等方面的内容。下面是对每个知识点的详细说明: 1. 什么是JavaScript...
HTML+CSS+JavaScript教程学习笔记HTML+CSS+JavaScript教程学习笔记 HTML+CSS+JavaScript教程学习笔记HTML+CSS+JavaScript教程学习笔记 HTML+CSS+JavaScript教程学习笔记HTML+CSS+JavaScript教程学习笔记 ...
以上是JavaScript学习笔记中提到的一些核心知识点,通过对这些知识点的理解和熟练应用,可以为进一步学习和掌握JavaScript打下坚实的基础。在实际开发过程中,结合具体的项目需求,这些知识会得到更深入的拓展和应用...
Javascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript...
JavaScript学习笔记讲解版参考.pdf是一份详尽的教程,涵盖了从基础到进阶的JavaScript知识。这份笔记首先从CSS样式表开始,引导读者理解网页样式的设置与应用。 1. CSS(Cascading Style Sheets)样式表是用于控制...
根据提供的文件信息,可以看出这份“我的javascript学习笔记”主要涵盖了JavaScript中的几个关键概念和技术要点,包括正则表达式、AJAX以及一些JavaScript的核心语言特性。接下来将这些知识点进行详细的整理和解释。...
前端学习笔记网站(HTML5+CSS3+JavaScript前端网页web课程设计).rar前端学习笔记网站(HTML5+CSS3+JavaScript前端网页web课程设计).rar前端学习笔记网站(HTML5+CSS3+JavaScript前端网页web课程设计).rar ...
JavaScript学习笔记主要涵盖了这门广泛应用于网页和网络应用开发的脚本语言的核心概念和技术。这篇笔记基于Jerry Zhang在iteye博客上分享的文章,旨在帮助读者深入理解和掌握JavaScript的基础及高级特性。 1. **...
JavaScript 学习笔记 前端程序员养成计划
这个“javaScript学习笔记.rar”压缩包显然包含了作者在学习JavaScript过程中的心得和记录,对于初学者或者想要深入理解JavaScript的人来说,是一份宝贵的资源。 JavaScript与Java虽然名字相似,但两者实际上是不同...
《javascript高级编程》学习笔记
"Javascript学习笔记(传智播客视频学习笔记+代码)"是一份全面介绍JavaScript基础知识的学习资源,适用于初学者。这份笔记结合了传智播客的web前端培训视频内容,提供了丰富的理论讲解和实践代码,帮助读者从零开始...
这篇"JavaScript入门新手学习笔记"提供了全面的学习资源,适合初学者系统性地掌握这一技术。 笔记可能包含了以下关键知识点: 1. **基础语法**:JS的基础包括变量(var、let、const)、数据类型(如字符串、数字、...
JavaScript学习笔记,当时看黑马的视频记录的
js笔记js笔记js笔记js笔记
尚硅谷JavaScript高级学习笔记
以上就是JavaScript学习笔记的主要内容,涵盖了从基础概念到具体应用的多个方面,是深入理解和掌握JavaScript不可或缺的知识点。通过不断实践和学习,可以逐步提升JavaScript编程能力,为Web开发打下坚实基础。
该项目是一个关于HomeAssistant的视频文档学习笔记源码,由150个文件组成,涵盖多种编程语言,包括86个Markdown文件、23个YAML配置、11个JavaScript脚本、4个Shell脚本、4个HTML文件、3个Python脚本、3个CSS样式表、...