javascript 作用域与闭包
时间:
[TOC]
第一章 作用域是什么
js编译原理
- 到底是什么类型的语言?
动态、解释型语言?
no,它是编译型的语言
why?不是提前编译的,编译在执行之前的几微妙甚至更短
编译结果不能移植
- 编译的过程
词法分析->语法分析->代码生成
理解作用域
js的执行参与者
- js引擎(v8、xx):负责编译和执行的过程
- 编译器:词法分析、语法分析、代码生成
- 作用域:收集和维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限
code
1
var a=2;
词法分析: var a = 2
语法分析:var a; 作用域是否有a?有忽略,没有声明后放到作用域中
生成代码:a=2;
执行:js引擎会询问作用域有没有a,然后再赋值,如果没有就异常了。code 2
1
2
3
4
5function foo(a){
console.log(a+b);
b=a;
}
foo(2);ReferenceError异常
LHS和RHS
LHS:查找赋值操作的目标是谁? a=
RHS:查找谁是赋值操作的源头 console.log(a) 或者 =afunction的LHS和RHS
1
2
3
4
5function foo(a){
console.log(a+b);
b=a;
}
foo(2);LHS: foo(.. a.. b=..
RHS: foo.. console.. log… a b a
不具有一般意义的一些代码
1 | var foo = function(a){ |
LHS:foo.. foo(.. a.. b..
RHS:function(.. console.. …
注意:上面的LHS和RHS对于最后一个就不对了,编译器可以在代码生成时同时处理声明和值的定义。
- 作用域的嵌套
向上找一直到全局作用域
异常
LHS和RHS在嵌套时的不同
LHS:如果到最后没有找到,那就创建一个(非严格模式)或者抛一个异常(ReferenceError,严格模式);
RHS:如果到最后没有找到,那就抛一个异常(ReferenceError)
可以理解code2的代码
小结
- javascript的编译过程包括:词法分析->语法分析->代码生成
- 作用域可以理解成一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称进行变量的查找
- 变量查找方法:LHS和RHS
- 作用域的嵌套
第二章 词法作用域
作用域的工作模型:
- 词法作用域
代码示例
1
2
3
4
5
6
7
8
9
10
11
12 function foo(a) {
var b=a*2;
function bar(c) {
console.log(a,b,c);
}
bar(b*3);
}
foo(2);
console.log(a);
console.log(b);
console.log(c);
>
- 输出结果是什么?
- LHS和RHS分别有哪些?
- 作用域有几个?
查找
- 遮蔽效应(全局如果被遮蔽,可以window.a访问)
- 词法作用域只由函数声明时的所处的位置决定
- 词法作用域查找只会查找一级标识符(对象的属性不会查找)
如何欺骗词法作用域—一定不要使用,只是为了了解
不管怎么说,都不要用
讲的目的只是为了看懂别人这么写的代码
在执行时,动态的修改词法作用域
####eval
功能:接收一个字符串作为参数,并将其中的内容看成在写代码时就加进去的一样
1 | function foo(str, a) { |
补充:
实际中可以执行一段代码后再传str
严格模式: eval会有自己的作用域,不会修改插入的作用域了
其它:
setTimeOut(..) setInterval(..),第一个参数可以接受字符串
new Function(..) 最后一个参数接受代码字符串
不管怎么说,都不要用
讲的目的只是为了看懂别人这么写的代码
####with
with 会根据你传递给他的对象中凭空创造一个新的词法作用域
正常写法
1
2
3
4
5
6
7
8var obj = {
a: 1,
b: 2,
c: 3
}
console.log(obj.a);
console.log(obj.b);
console.log(obj.c);简单写法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15var obj = {
a: 1,
b: 2,
c: 3
}
with(obj) {
console.log(a);
console.log(b);
console.log(c);
}
```
3. 所带来的问题
```javacriptfunction test(obj) {
with(obj) { a = 2; }}
var obj1 = {a: 1}
var obj2 = {b: 1}
test(obj1);
console.log(obj1.a);
test(obj2);
console.log(obj2.a);
console.log(a);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
>缺点:
* 欺骗词法作用域会导致不可预知的结果(对于不懂的人来说)
* 严格模式不支持
* 性能
**不管怎么说,都不要用**
*讲的目的只是为了看懂别人这么写的代码*
###小结
> * 定义
* 欺骗词法作用域 **千万不要使用**
### 补充知识
> 动态作用域
>> 不关心在何处声明,只关心在何处调用
>> ```javascriptfunction test1() {
console.log(a);}
function bar() {var a = 3; test1();}
var a = 2;
bar();1
2
3
4
5
6
7
8
9
## 函数作用域和块作用域
### 函数
## 提升
## 闭包
## 看代码说结果
####代码1:
```javascriptvar a = 1;
function foo() {var b = 2; function bar() { var b = 'bar2'; console.log(b); function baz() { console.log(a); } baz(); } bar(); console.log(b);}
foo();1
2
3
4
5
6bar2
1
2
####代码2:
```javascripta = 2;
var a;
console.log( a );1
2
32
####代码3:
```javascriptconsole.log( a );
var a = 2;1
2
3undefined
####代码4:
```javascriptfoo();
function foo() {console.log('foo');}
1
2
3foo
####代码5:
```javascript//foo();
bar();
var foo = function bar() {console.log('foo');};
1
2
3
4
5
6foo is not function
bar is not defined
####代码6:
```javascriptvar foo;
function foo() { console.log( “a” ); }
function foo() { console.log( “b” ); }foo();
foo = true;
if (foo) {}
else {}
foo();1
2
3
4
5b
foo is not a function
####代码7:
```javascriptvar i;
for (i=1; i<= 5; i++) {setTimeout( function timer(){ console.log( i ); }, i*1000);}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
185
5
5
5
5
####代码8:
var baz;
function foo() {
var a;
function bar() {
console.log( a );
}
a = 2;
return bar;
}
baz = foo();
baz();
```javascriptfunction foo(j){
function timer(){ console.log(j); } return timer();}
for (var i=1; i<=5; i++) {
setTimeout(foo(i), i*1000 );}
1
2
3
4
5
6
71
2
3
4
5
####代码9:
```javascriptfunction foo() {
var a = 2; function bar() { console.log( a ); } return bar;}
var baz = foo();
baz();1
2
32
####代码10:
```javascriptfunction foo(a){
console.log(a+b); b=a;}
foo(2);1
2
3
4b is not defined
####代码11:
```javascriptfunction foo(a){
window.b=a; console.log(a+b);}
a=2;
foo(2);1
2
34
####代码12:
```javascriptvar foo = function(a){
console.log(a+b); b=a; } foo(2);1
2####代码13:
```javascriptfunction foo(a) {
var b=a*2; function bar(c) { console.log(a,b,c); } bar(b*3); } foo(2); console.log(a); console.log(b); console.log(c);1
2
3
42,4,12
a is not defined;
####代码14:
```javascriptfunction foo(str, a) {
eval(str); console.log(a, b);}
var b = 2;
foo(“var b=3;”, 1);1
2
31,3
####代码15:
```javascriptfunction test(obj) {
with(obj) { a = 2; }}
var obj1 = {a: 1}
var obj2 = {b: 1}
test(obj1);
console.log(obj1.a);
test(obj2);
console.log(obj2.a);
console.log(a);1
2
3
4
5
62
undefined
2
####代码16:
词法作用域
```javascriptfunction test1() {
console.log(a);}
function bar() {var a = 3; test1();}
var a = 2;
bar();1
2
32
####代码17:
```javascriptfunction Person(name){
this.name=name; this.fn=function(){ alert(this.name); }}
var person1=new Person(‘Byron’);
console.log(person1.constructor==Person);
console.log(person1 instanceof Person);1
2
3
4true
true
####代码18:
```javascriptfunction Person(name){
this.name=name; this.fn=function(){ alert(this.name); }}
var person1=new Person(‘Byron’);
var person2=new Person(‘Frank’);
console.log(person1.fn==person2.fn);1
2####代码19:
```javascriptfunction Person(name){
this.name=name;}
Person.prototype.share=[];
Person.prototype.printName=function(){alert(this.name);}
var person1=new Person(‘Byron’);
var person2=new Person(‘Frank’);
console.log(person1.printName==person2.printName);1
2####代码20:
```javascriptvar myObj = {
get a() { return this.h; }, set a(val){ this.h=val*2; }}
Object.defineProperty(myObj, “b”, {get: function() { return 3; //enumerable: true }});
myObj.a=2;
console.log(myObj.a);
console.log(myObj.b);
myObj.hasOwnProperty(“a”);1
2####代码21:
```javascriptvar oneObj={
a:2}
var twoObj=Object.create(oneObj);
console.log(twoObj.a);1
2####代码22:
```javascriptfunction Test1(str) {
this.a = str;}
var myTest = new Test1(“test1”);
console.log(myTest.a);
function Test1WithoutNew(str) {this.a = str;}
var myTestWithoutNew = Test1WithoutNew(“test1”);
console.log(myTestWithoutNew.a);1
2####代码23:
```javascriptfunction Test1(str) {
this.a = str; return this.a;}
var myTest = new Test1(“test1”);
console.log(myTest);
function Test1WithoutNew(str) {this.a = str; return this.a;}
var myTestWithoutNew = Test1WithoutNew(“test1”);
console.log(myTestWithoutNew);1
2####代码24:
```javascriptfunction Test1(str) {
this.a = str; return new String(this.a);}
var myTest = new Test1(“test1”);
console.log(myTest);
```
test1闭包的作用(如何实现模块化)