本文最主要讲讲JavaScript闭包和this绑定相关的个人小发现,鉴于这方面的基础知识已经有不少很好的文章讲过了,因此基本的就不讲了,推荐看看酷壳上的理解Javascript的闭包和阮一峰的学习Javascript闭包(Closure),写的都很是好。javascript
首先来说讲阮一峰的文章中的两道思考题。html
代码片断一java
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()());
这段代码最后输出的是shell
The Window
缘由在同一片文章的评论中已经有人指出了数据结构
George Wing 说:闭包
上面本人说得不太正确。
this的指向是由它所在函数调用的上下文决定的,而不是由它所在函数定义的上下文决定的。函数
对于最后返回的这个匿名函数学习
function(){ return this.name; };
它是做为一个独立的函数返回的,它的调用域是在全局上,因此会输出全局变量name。this
代码片断二spa
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()());
代码片断二最后输出的是
My Object
这里就要考虑var that = this;
这句的做用了,因为getNameFunc
是object
内部的函数,因此它调用的上下文this
保存的是object
的信息,将其保存到that
变量,这样做为内部函数的匿名函数就能够直接访问了。
能够注意到的是,阮一峰文章中的代码,都是将经过一个JSON对象来访问内部的函数,这样其实有些地方还不够清晰,毕竟不怎么严格地说,闭包就是函数内部的函数,因此我借用CoolShell上的文章中的例子来进一步说明。
代码片断三
function greeting(name) { var text = 'Hello ' + name; // local variable // 每次调用时,产生闭包,并返回内部函数对象给调用者 return function() { alert(text); } } var sayHello=greeting("Closure"); sayHello() // 经过闭包访问到了局部变量text
这段代码输出
Hello Closure
看上去好像很好理解,接下来看代码片断四:
代码片断四
var text = 'findingsea'; function greeting(name) { var text = 'Hello ' + name; // local variable // 每次调用时,产生闭包,并返回内部函数对象给调用者 return function() { alert(this.text); } } var sayHello=greeting("Closure"); sayHello() // 经过闭包访问到了局部变量text
这段代码输出
findingsea
这是为何呢?
针对代码片断三,CoolShell上的原文有解释:
文法环境中用于解析函数执行过程使用到的变量标识符。咱们能够将文法环境想象成一个对象,该对象包含了两个重要组件,环境记录(Enviroment Recode),和外部引用(指针)。环境记录包含包含了函数内部声明的局部变量和参数变量,外部引用指向了外部函数对象的上下文执行场景。全局的上下文场景中此引用值为NULL。这样的数据结构就构成了一个单向的链表,每一个引用都指向外层的上下文场景。
针对代码片断四,就是咱们以前讲过的,this
保存是调用环境下的上下文内容,因此会输出全局的text
。
本文想说明的是如下两点:
this
对变量进行访问时,函数会经过文法环境中的外部引用(指针),一级级地往上找(单向链表),直到找到(或者最终找不到)对应的变量。这个结构是在函数定义的时候就决定了的。this
对变量进行访问时,和绝大多数语言不一样,JavaScript的this
保存的是调用环境的上下文,也就是说this
中的内容是在调用的时候决定的,因此访问到的是当前环境下的对应变量,并不会像前一种状况同样进行逐级查找。