您的位置:首页 > Web前端 > JavaScript

js变量声明提升

2017-03-15 21:06 316 查看
通常分析作用域链,要结合变量声明提升,看看下面几个题,把你绕晕没?

其中问题7最经典,如果你能明白,说明原型链你掌握的差不多了。

// --------------------1-----------------
function foo() {
var num = 123;
console.log(num); //?
}
foo();
console.log(num); //?

//提升后的代码
function foo() {
var num;
num = 123;
console.log(num); //?123
}
foo();
console.log(num); //?num is not defined

//is not defined 没有定义
//undefined  定义了没有赋值

// --------------------2-----------------

var scope = "global";

foo();

function foo() {

console.log(scope); //?
var scope = "local";
console.log(scope); //?
}

//提升后的代码
var scope;
function foo(){
var scope;
console.log(scope); //?undefined
scope = "local";
console.log(scope); //?local
}
scope = "global";
foo();

// --------------------3-----------------
//in 关键字 判断某个对象中是否有某个属性

function f1(){
if("a" in window){
var a = 10;
}
alert(a); //undefined
}
f1();

// --------------------4-----------------

if("a" in window){
var a = 10;
}
alert(a);

//预解析
var a;
if("a" in window){
a = 10;
}
alert(a); // 10

// --------------------5-----------------
if(!"a" in window){
var a = 10;
}
alert(a);

//预解析
var a;
if(!"a" in window){
a = 10;
}
alert(a); // ?undefined

// --------------------6-----------------
var foo = 1;
function bar() {
if(!foo) {
var foo = 10;
}
alert(foo); //??10
}
bar();

//提升后的代码
var foo;
function bar(){
var foo;
if(!foo) {
foo = 10;
}
alert(foo); //??10
}
foo = 1;
bar();

// --------------------7-----------------
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(); // ?  alert 2
getName(); // ? 4
Foo().getName(); // ? 1
getName(); // ? 4  //1
new Foo.getName(); // ? 2 //先执行Foo.getName(),再new。new 2,还是2
(new Foo).getName(); //
new Foo().getName(); // ? 3 //先创建Foo对象,在调用函数
new new Foo().getName(); // ?  3 //先创建对象,调用函数,再new

//等价于
function Foo() {
getName = function(){ alert(1); };
return this;
}
var getName;
function getName(){ alert(5); }

Foo.getName = function() { alert(2); };
Foo.prototype.getName = function(){ alert(3); };
getName = function() { alert(4); };

Foo.getName(); // ?  alert 2
getName(); // ? 4
Foo().getName(); // ? 1
getName(); // ? 4  //1
new Foo.getName(); // ? 2 //先执行Foo.getName(),再new。new 2,还是2
(new Foo).getName(); //3
new Foo().getName(); // ? 3 //先创建Foo对象,在调用函数
new new Foo().getName(); // ?  3 //先创建对象,调用函数,再new


知识点:局部变量声明提前后不会覆盖原来的全局变量

例1 :参数是引用参数

var foo={n:1};
(function (foo) {
console.log(foo.n);
foo.n=3;
var foo={n:2};
console.log(foo.n);
})(foo);
console.log(foo.n);


解析:变量提升以后:(局部变量声明提前后不会覆盖原来的全局变量)

var foo = {n:1};
(function(foo){            //形参foo同实参foo一样指向同一片内存空间,这个空间里的n的值为1
var foo;               //局部变量声明提前后不会覆盖原来的全局变量,赋值才会覆盖
console.log(foo.n);    //输出1
foo.n = 3;             //形参与实参foo指向的内存空间里的n的值被改为3
foo = {n:2};           //形参foo指向了新的内存空间,里面n的值为2.
console.log(foo.n);    //输出新的内存空间的n的值
})(foo);
console.log(foo.n);        //实参foo的指向还是原来的内存空间,里面的n的值为3.

//所以答案为: 1 2 3


例2: 参数是传值参数

var foo=1;
(function (foo) {
console.log(foo);
foo=3;
var foo=2;
console.log(foo);
})(foo);
console.log(foo);

//答案为1 2 1
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: