在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);
分享到:
相关推荐
HTML+CSS+JavaScript教程学习笔记HTML+CSS+JavaScript教程学习笔记 HTML+CSS+JavaScript教程学习笔记HTML+CSS+JavaScript教程学习笔记 HTML+CSS+JavaScript教程学习笔记HTML+CSS+JavaScript教程学习笔记 ...
JavaScript基础知识点总结 JavaScript是一种高级的、动态的、基于对象的客户端脚本语言。它是在网页上执行的脚本语言,能实现网页的交互功能。下面是该资源中的重要知识点总结: 一、 JavaScript 基本概念 * ...
Javascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript学习笔记PPTJavascript...
JavaScript学习笔记讲解版参考.pdf是一份详尽的教程,涵盖了从基础到进阶的JavaScript知识。这份笔记首先从CSS样式表开始,引导读者理解网页样式的设置与应用。 1. CSS(Cascading Style Sheets)样式表是用于控制...
JavaScript学习笔记是一本关于JavaScript编程语言的教材,该教材通过丰富的实例,系统地介绍了JavaScript的基础知识和实际应用技巧,帮助读者一步步掌握客户端编程技术。本书共分为九章,每一章都有其特定的主题,...
根据提供的文件信息,可以看出这份“我的javascript学习笔记”主要涵盖了JavaScript中的几个关键概念和技术要点,包括正则表达式、AJAX以及一些JavaScript的核心语言特性。接下来将这些知识点进行详细的整理和解释。...
前端学习笔记网站(HTML5+CSS3+JavaScript前端网页web课程设计).rar前端学习笔记网站(HTML5+CSS3+JavaScript前端网页web课程设计).rar前端学习笔记网站(HTML5+CSS3+JavaScript前端网页web课程设计).rar ...
<a href="javascript:prompt('What is your name?')">Click ``` - **解释:** 用户点击链接后会弹出一个输入对话框让用户输入名字。 ### JavaScript与DOM操作 JavaScript可以用来动态地修改文档对象模型(DOM),...
"Javascript学习笔记(传智播客视频学习笔记+代码)"是一份全面介绍JavaScript基础知识的学习资源,适用于初学者。这份笔记结合了传智播客的web前端培训视频内容,提供了丰富的理论讲解和实践代码,帮助读者从零开始...
这个“JavaScript学习笔记集和代码库”涵盖了该语言的基础知识、进阶技巧以及实用示例,对于想要深入理解和掌握JavaScript的初学者或有经验的开发者来说,都是一个宝贵的资源。 首先,让我们来讨论JavaScript的基础...
javascript学习笔记
本学习笔记专为初学者设计,旨在帮助新接触JavaScript的人快速掌握这门语言的核心概念和实用技巧。 首先,"JavaScript特效.chm"可能是一份关于JavaScript实现的各种网页特效的教程。这些特效可能包括图片轮播、下拉...
这篇"JavaScript入门新手学习笔记"提供了全面的学习资源,适合初学者系统性地掌握这一技术。 笔记可能包含了以下关键知识点: 1. **基础语法**:JS的基础包括变量(var、let、const)、数据类型(如字符串、数字、...
JavaScript学习笔记——深入理解基础与函数 在JavaScript中,学习基础知识是至关重要的,因为它是所有进一步编程技巧的基础。首先,我们需要了解JavaScript中的数据类型。在JavaScript中,有五种简单的数据类型:...
### JavaScript 学习笔记知识点详解 #### 一、JavaScript 基础概念 - **JavaScript 与 Java 的区别**:JavaScript 和 Java 是两种完全不同的编程语言。Java 是一种静态类型语言,而 JavaScript 是动态类型的解释性...
JavaScript学习笔记,当时看黑马的视频记录的