一、什么是作用域?
指的就是变量起作用的范围。在JS中有且只有函数可以创建作用域。
JS中的作用域是词法作用域。词法作用域就是一旦代码写好,可以根据代码的结构就可以看出的变量作用域就是词法作用域。JS中没有动态作用域。
二、js执行分两个阶段:
1.预解析阶段:会将函数声明,以及变量的声明提升到其所在的作用域的最顶上。
2.执行阶段
注意几点:函数声明会被提升;但是函数表达式不会被提升;new Function这种形式创建的函数不能被提升
三、变量提升中的特殊情况处理:
1.当函数同名的时候,都会被提升,但是后面的会把前面的给覆盖掉。
2.当函数和变量同名的时候,只会提升函数声明,忽略变量。
四、作用域链:
函数可以创造作用域,函数中又可以声明函数,这样就形成了作用域套作用域的链式结构,称作作用域链。
五、变量的搜索原则:
1.当遇到一个变量的使用的时候,首先在当前的作用域中去找这个变量,如果找到了,就直接使用;
2.如果没有找到,就去外层的作用域中进行查找,如果找到了就直接使用;
3.如果没有找到就继续沿着作用域链往上查找,直到找到0级作用域链。
六、条件式函数声明:
在条件语句中声明的函数 就是条件式函数声明。能否被提升,取决于浏览器,现在的浏览器 都不会进行提升
七、案例分析:
1.案例1:
var scope = "global";
function foo() {
console.log(scope); //undefined
var scope = "local";
console.log(scope); //local
}
foo();
变量提升后的代码为:
var scope;
function foo() {
var scope;
console.log(scope); //
scope = "local";
console.log(scope); //
}
scope="global";
foo();
所以结果就显而易见了。
案例2:
function Foo() {
getName = function(){ alert(1); };
return this;
}
Foo.getName = function() { alert(2); };
Foo.prototype.getName = function(){ alert(3); };
var getName = function() { alert(4); };
function getName(){ alert(5); }
Foo.getName(); // ?
getName(); // ?
Foo().getName(); //?
new Foo.getName(); // ?
new Foo().getName(); // ?
new new Foo().getName(); // ?
首先进行改写变量提升后的代码:
function Foo() {
getName = function(){ alert(1); };
return this;
}
function getName(){ alert(5); }
Foo.getName = function() { alert(2); };
Foo.prototype.getName = function(){ alert(3); };
getName = function() { alert(4); };
1.Foo.getName(); //2
2.getName(); //4
3.Foo().getName(); //1
构造函数如果当构造函数来调用,也就是和new一起使用的时候,this指向的是new创建的对象;但是如果构造函数不和new一起使用,像普通函数一样去调用的时候,这个this就指向window对象。调用Foo()就是返回this,就是window,然后Foo().getName()就相当于window.getName();所以getName=function(){ alert(1) };就相当于定义了全局getName函数返回1.
4.new Foo.getName();//2 (执行顺序是先Foo.getName()后new)
5.new Foo().getName(); //3 (执行顺序是先new Foo()后getName(),去原型中找到了)
6.new new Foo().getName(); //3 (执行顺序是先new Foo().getName()后new)