一、作业域初探
作用域定义:变量(变量作用于又称上下文)和函数生效(能被访问)的区域
全局、局部变量
作用域的访问顺序
作用域:函数里面的可以访问外面的全局变量
函数外面不能用函数里面的。里面的可以访问外面的,外面的不能访问里面的,彼此独立的区间不能相互访问
test{}和demo{}不能互相访问,但是可以访问外面的全局变量
例:彼此独立的区间不能相互访问,全局变量都可以访问
function test(){
var a =123;
function demo(){
var b = 234;
document.write(a);
}
demo();
document.write(b);
}
上面的 document.write(b);不能访问 var b ,
上面的 document.write(a);可以访问 a
外层函数不能访问里层的,里层的可以访问外层的,越往里权限越大
作业:要求输入一串低于10位的数字,输入这串数字的中文大写
例如:input :10000 output:壹万
例如:input :1001010 output:壹佰万壹仟零壹拾
千分位如果是 0 必须读零
二、js 运行三部曲
1 语法分析 → 2 预编译 → 3 解释执行
三、预编译前奏
例
function test(){
console.log('a');
}
test();
//a
//可以执行
例
test();
function test(){
console.log(‘a’);
}
//也能执行,因为有预编译的存在
例
var a = 123;
console.log(a);
//答案 123
例
console.log(a);
var a = 123;
//答案 undefined
例
console.log(a);
//Uncaught ReferenceError: a is not defined
函数声明整体提升函数不管写在哪里,都会被提升到逻辑的最前面。所以不管在哪里调用,本质上都是在后面调用
变量 声明提升把var a提升到最前面
var a=123;
这是变量声明再赋值
变量 声明提升是把它拆分成var a; a=123;然后把 var a 提升到最前面
上面这两句话没办法解决下面例子的问题
function a(a) {
var a = 234;
var a = function() {
}
a();
}
var a=1232;
1.imply global
imply global 暗示全局变量 :即任何变量,如果变量未经声明就赋值,此变量就为全局对象(就是window)所有
全局变量是window
window.a = 10;
a = 10; === > windows.a = 10;
2.一切声明的全局变量,全是window的属性
var a=123;==>window.a=123;
window就是全局的域
如果在全局变量中var a=123;那么就会返回到window
例 var a = 123
console.log(a) ===> window.a
例 var a = b = 234;
是把 234 的值赋给 b,在把 b 的值赋给 a
此时访问a和b都属于window域
例 function test(){
var a = b = 123;
}
test()
写test()代表执行test,赋值是自右向左的,上面先把123赋值给b的时候,b未经声明,然后再声明a,再把b的值赋给a,导致b未经声明,所以b归window所有
访问window.a是undefined,访问window.b是123
例
function test(){
var b = 123;
}
test();
console.log(window.b);
//答案 undefined
//window 就是全局
例 var a = 123;
console.log(a); → console.log(window.a);
例 var a = 123;
var b = 234;
var c = 345;
window{
a : 123,
b : 234,
c : 345
}
//如果 var a 对应会有 window.a
四、预编译(解决执行顺序问题)
例
function fn(a){
console.log(a);
var a = 123;
console.log(a);
function a (){}
console.log(a);
var b = function (){}
console.log(b);
function d() {}
}
fn(1);
//答案是 function a(){}//123//123//function (){}
这个例子的形参是(a),变量声明也是 a
上面的例子按四部曲变化如下:
找形参和变量声明,将变量和形参(a)名作为 AO 属性名,值为 undefined ,AO{
a : undefined,
b : undefined,
}
(把实参值传到形参里)AO{
a : 1,
b : undefined,
}
function a () {}和 function d () {}都是函数声明,但是 var b = function (){}不是。AO{
a : function a () {},
b : undefined,
d : function d () {}
}
执行第一行 console.log(a);时,用的是 AO{
a : function a () {},
b : undefined,
d : function d () {}
}
执行 var a =123;改变的是 AO{
a : 123,
b : undefined,
d : function d () {}
}
在 b = function (){}时 AO{
a : 123,
b : function () {},
d : function d () {}
}
预编译发生在函数执行的前一刻
五、(函数)预编译的四部曲:
1.创建 AO 对象 Activation Object(执行期上下文,作用是理解的作用域,函数产生的执行空间库)
2.找形参和变量声明,将变量和形参名作为 AO 属性名,值为 undefined
相当于 AO{
a : undefined,
b : undefined
}
3.将实参值和形参统一(把实参值传到形参里)
4.在函数体里面找函数声明,值赋予函数体
(先看自己的 AO,再看全局的 GO)
答题过程:找形参和变量声明,将变量和形参名作为 AO 属性名,值为 undefined, AO{
a : 1,
b : undefined,
c : undefined
}
函数声明 function b(){}和 function d(){},AO{
a : 1,
b : function b(){},
c : undefined,
d : function d(){}
}
执行 console.log(a);答案是 1
执行 c = 0;变 AO{
a : 1,
b : function b(){},
c : 0,
d : function d(){}
}
var c 不用管,因为 c 已经在 AO 里面了
执行 a = 3;改 AO{
a : 3,
b : function b(){},
c : 0,
d : function d(){}
}
执行 b = 2;改 AO{
a : 3,
b : 2,
c : 0,
d : function d(){}
}
执行 console.log(b);答案是 2
function b () {}和 function d(){}已经提过了,不用管
执行 console.log(b);答案是 2
一旦有重名的,一但有 a 变量又有 a 函数【如 function a (){}】,又在第一条访问的是a,一定是函数
答题过程: 将变量和形参名作为 AO 属性名,AO{
a : undefined,
b : undefined
}
将实参值和形参统一,AO{
a : 1,
b : undefined
}
找函数声明 function a (){},AO{
a : function a (){},
b : undefined
}
执行 console.log(a);答案是 function a (){}
执行 console.log(b);答案是 undefined
执行 var b = 234;变 AO{
a : function a (){},
b : 234
}
执行 console.log(b);答案是 234
执行 a = 123;变 AO{
a : 123,
b : 234
}
执行 console.log(a);答案是 123
然后 function a (){};var a ;都可以不看了
执行 b = 234,b 值还是 234,不变
执行 var b = function (){},变 AO{
a : 123,
b : function (){}
}
执行 console.log(a);答案是 123
执行 console.log(b);答案是 function (){}
下面开始讲全局的预编译
例 console.log(a);
var a = 123;
答案 undefined
例 console.log(a);
var a = 123;
function a (){}
答案是打印 a 是 function a (){}
全局的预编译三部曲:
1、生成了一个 GO 的对象 Global Object(window 就是 GO)
2、找形参和变量声明,将变量和形参名作为 GO 属性名,值为 undefined
3、在函数体里面找函数声明,值赋予函数体
例 console.log(a);
var a = 123;
function a (){}
答案过程,GO{
a : undefined
}
函数声明 GO{
a : function a (){}
}
执行 var a = 123;变 GO{
a : 123
}
执行 console.log(a);就是 123
GO === window, GO 和 window 是一个东西
console.log(a);和 console.log(window.a);和 console.log(go.a);是一样
任何全局变量都是 window 上的属性
没有声明就是赋值了,归 window 所有,就是在 GO 里面预编译
例 function test(){
var a = b =123;
console.log(window.b);
}
test();
答案 a 是 undefined,b 是 123
先生成 GO{
b : 123
}
再有 AO{
a : undefined
}
先生成 GO 还是 AO?
想执行全局,先生成 GO,在执行 test 的前一刻生成 AO
在几层嵌套关系,近的优先,从近的到远的,有 AO 就看 AO,AO 没有才看 GO
答题过程:想执行全局,先有 GO,GO{
test : undefined
24
}
发现有函数声明 GO{
test : function (){
.....
} }
执行 console.log(test),
执行 test(1)之前生成 AO{
test : function (){}
}
执行 var test = 234;变成 234
AO 上面有就用 AO 的,没有就看 GO 的 例 var global = 100;
function fn(){
console.log(global);
}
fn();
答题过程 GO{
global : undefined,
fn : function(){.....}
}
执行 var global = 100;变 GO{
global : 100,
fn : function(){.....}
}
不看 function fn(){...}里面的东西
执行 fn()之前 AO{
访问 GO 的 global
}
答题过程,GO{
global : undefined
fn : undefined(没用可以不写) }变 GO{
global : 100
fn : undefined
}
执行 fn()之前,AO{
global : undefined
}
执行结果是 undefined,200
答案//undefined //undefined //234 //234
过程 GO{
a : undefined
test:undefined(没用可以不写) }
AO{
b : undefined //不管 if(a){},可以提出 var b 的 b }
执行到 c=234,GO{
a : undefined
c : 234
}
执行到 a=10,GO{
a : 10
c : 234}
25
例 function bar(){
return foo;
foo = 10;
function foo(){}
var foo = 11;
}
console.log(bar());
答案:function foo(){}
如果在第一行 return foo,下面有 foo 这个函数,一定打印这个函数
例 console.log(bar());
function bar(){
foo = 10;
function foo(){}
var foo = 11;
returm foo;
}答案 11
例 console.log(b);
var b = function (){}
答案是 undefined
例 现在在 if 里面定义函数声明 function 是不允许的,但是过去可以,下面就是过去的旧题,按可以来做
GO{
a : undefined
}
GO{
a : undefined
demo : function (){}
}
开始执行 a=100,GO{
a : 100
demo : function (){}
}
AO{
e : undefined,
b : undefined,
c : undefined,
a : undefined
}
形参实参相统一,AO{
e : 1,
b : undefined,
c : undefined,
a : undefined
}
赋值 AO{
e : function e (){},
b : undefined,
c : undefined,------旧规则里面可以提出 function(){}
a : undefined
}
执行 arguments[0] = 2;实参列表和传参是否相映射,变 AO{
e : 2,
b : undefined,
c : undefined,
a : undefined
}
执行 console.log(e);答案 2
if(a)由于 a 在 AO 里面是 undefined,所以不走 if
26
执行 a = 10;变 AO{
e : 2,
b : undefined,
c : undefined,
a : 10
}
执行 console.log(b),答案 undefined
执行 f = 123,变 GO{
a : 100,
demo : function (){},
f : 123
}
执行 console.log(c); 之前打印 function(){},改语法后打印 undefined
执行 console.log(a); 答案 10
执行 console.log(a); 因为在外面是全局的,答案 100
执行 console.log(a); 答案 123
//1 false+1 因为有+,两边都不是字符串,就转换成数字,false 是 0
//false false==1,false 肯定不等于 1,所以把 false 再赋给 demo
//undefined
typeof(a) 出现”undefined” -true 转换成数字是-1 +undefined 显示“NaN” -1 + NaN = NaN
-1 + NaN + “” = “NaN” “undefined” && “NaN”转换成 boolean,就都是 true
“11”* 2 是*把两边转换成了数字,所以 11 +“11”* 2 =33,33 == 33,两边相等
!!非非就是正
“ ”这不是空串,是空格字符串
!!” ”转换成 Boolean 为 true
!!””非非空串,转换为 Boolean 为 false
!!false 就是 false
true + false - false = 1 + 0 – 0 =1
11|| document.write(‘你觉得能打印?’)
||遇到真就听,1 为真,所以返回 1
例(window.foo || (window.foo = ‘bar’));
求 window.foo
答案”bar”
这道题要先看(window.foo = ‘bar’)这一边的,再看左边的 window.foo,因为运算符的顺序;但是这道题错误的读法(从左到右)也是 bar
(window.foo || window.foo = ‘bar’);这么写就报错;||或运算符优先级高于=等号