LZ说来说去就是不理解对象的作用域 var a = 'a', b = 'b'; function fn(){ a = 'aa'; var b = 'bb'; } fn(); alert(a); // -> aa alert(b); // -> b
就像div层一样,一层套一层,如果内层设置的话,就默认采用上层的样式 函数也是一层层嵌套的,子层的函数只能调用和改变父层和自身的变量,而不能改变并列层和下 层的变量 function haha(){ var wo = "我是家长"; alert(wo); if(wo=="男"){ wo = "爸爸"; }else{ wo = "妈妈"; } alert(wo);}
我们再来看看JavaScript中的作用域链Scope Chain<script type="text/javascript">/* 作用域链(Scope Chain) JavaScript中的一种重要机制,JS中所有的标识符(Identifier)都是通过Scope Chain来查找值的。 */var i = "w i";/* 词法作用域(Lexical Scoping) JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里. 这个作用域我们称之为[[scope]] 非内嵌函数的[[scope]]都是宿主对象,不同的宿主会有不同的内容 */ var a =function(){ alert(i); }var b = function(){ var i = "b i"; a(); }var c = function(){ a(); }a(); /* 函数在运行的时候,会先创建一个call Object, 将函数的形参、变量和函数声明的结果都添加到call Object作为属性; 把call Object添加到该函数的作用域链的最前面; 然后,再将函数定义时的[[scope]]添加到它的作用域链中; 函数体内的标识符查找 先从Scope Chain中第一个对象找,存在则返回,否则 继续查找下一个对象,存在则返回,否则(重复此步骤) 最后找不到则返回undefined */ b(); c();/* JavaScript中的scope Chain的机制使得闭包得以实现 */ var d = function(){ var i = "d i"; var e = function(){ alert(i); } return e; }var f = d(); f(); /* f是function e的引用 call Object部分:没有形参、变量声明和内部函数; [[scope]]部分:e定义在函数d体内,e的[[scope]]中可以访问到d,i,e,然后d也会有一个[[scope]],又可以接着往上访问,这样,便形成一条链 */</script>
var a = 'a',
b = 'b';
function fn(){
a = 'aa';
var b = 'bb';
}
fn();
alert(a); // -> aa
alert(b); // -> b
函数也是一层层嵌套的,子层的函数只能调用和改变父层和自身的变量,而不能改变并列层和下 层的变量
function haha(){
var wo = "我是家长";
alert(wo);
if(wo=="男"){
wo = "爸爸"; }else{
wo = "妈妈";
}
alert(wo);}
作用域链(Scope Chain)
JavaScript中的一种重要机制,JS中所有的标识符(Identifier)都是通过Scope Chain来查找值的。
*/var i = "w i";/*
词法作用域(Lexical Scoping)
JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里. 这个作用域我们称之为[[scope]]
非内嵌函数的[[scope]]都是宿主对象,不同的宿主会有不同的内容
*/
var a =function(){
alert(i);
}var b = function(){
var i = "b i";
a();
}var c = function(){
a();
}a();
/*
函数在运行的时候,会先创建一个call Object,
将函数的形参、变量和函数声明的结果都添加到call Object作为属性;
把call Object添加到该函数的作用域链的最前面;
然后,再将函数定义时的[[scope]]添加到它的作用域链中; 函数体内的标识符查找
先从Scope Chain中第一个对象找,存在则返回,否则
继续查找下一个对象,存在则返回,否则(重复此步骤)
最后找不到则返回undefined
*/
b();
c();/*
JavaScript中的scope Chain的机制使得闭包得以实现
*/
var d = function(){
var i = "d i";
var e = function(){
alert(i);
}
return e;
}var f = d();
f();
/*
f是function e的引用
call Object部分:没有形参、变量声明和内部函数;
[[scope]]部分:e定义在函数d体内,e的[[scope]]中可以访问到d,i,e,然后d也会有一个[[scope]],又可以接着往上访问,这样,便形成一条链
*/</script>
具名函数表达式与匿名函数表达式和函数申明的区别
winter:
正常的函数定义时是直接把[[scope]]设为定义时的scope chain
但是具名函数表达式是先给scope chain加入一个new Object
之后再将[[scope]]设为新的scope chain
设完后再将[[scope]]还原到正常函数定义时的[[scope]]
等于是在正常函数定义时的[[scope]]添加了一个new Object到最前面 在不同浏览器中对具名函数表达式的处理方式都太一样,都没太按ECMAScript中的规定去实现
ECMAScript中关于具名函数表达式实现的规定大致如下:
1、创建一个new Object
2、将这个new Object插入到scope chain
3、创建一个new Function,将scope chain设为[[scope]]
4、为new Object添加一个属性,function name:function body(readOnly、don't Delete)
5、移除new Object
6、返回Function
*/var test="wrong"Object.prototype.test="right";var f = function(){
alert(test);
}
f();
/*
正常函数申明运行时的作用域链
call Object
[[scope]]
*/
var f1 = function f0(){
alert(test);
}
f1();
/*
具名函数表达式运行时的作用域链
call Object
new Object
[[scope]]
*/</script>
1). 定义函数的时候-------函数的作用域链
2). 调用函数的时候-------函数的执行环境 == 调用对象, 创建属性"作用域" == 函数的作用域链
3). 添加arguments属性到调用对象上
4). 如存在嵌套函数 则完成内部函数的定义(重复步骤), 将函数参数及内部定义作为调用对象的属性将调用对象加入到 "作用域链的头部" 1)的前面