js 变量提升与函数声明提升

js中变量的处理机制,你是否想了解下,想的话上车!!!
在聊到变量提升的时候,我们先聊下LHSRHS

1、LHSRHS

javascript中两种查找类型,含义是赋值操作的左侧和右侧

  • LHS: 对那个赋值对那个进行LHS引用,可以理解为赋值操作的目标 如:a = 2,如果找不到在非严格模式会声明一个全局变量
  • RHS: 需要获取那个变量的值,就对哪个变量进行RHS引用,理解为赋值操作的源头,如果找不到对应的标识符,就会抛出异常:ReferenceError

简单的讲:赋值就是LHS,找值就是RHS
来个例子分析分析:

function foo(a) {
    var b = a;
    return b + a;
}
var c= foo()

以上代码有3个LHS和4个RHS,分析如下:

  • 1、var c中需要被赋值,在赋值操作的左侧,所以对c进行LHS引用
  • 2、变量c需要被赋值,它的值是foo(2),那么foo(2)的值是多少呢?,需要查找foo(2)的值,在赋值操作的右侧,所以对foo(2)进行RHS引用
  • 3、隐含赋值操作,将2传递给function foo(a){...}函数的参数aa在赋值操作的左侧,对a进行LHS引用
  • 4、var b = a,b需要被赋值,处于赋值操作的左侧,所以对b进行LHS引用,b的值是a,那么a是多少呢,需要对a进行RHS引用
  • 5、return b + a中,需要找到ab的来源,ab都在赋值操作的右侧,对b + a进行RHS引用

2、变量提升

js中变量提升到当前作用域的顶部,而赋值操作在原处不变
举个例子:
console.log(a) ;var a = 2;输出的值是什么?
很多人可能会报错ReferenceError,但是不是,后面定义了a,所以变量会提升,就是在console.log(a)前面多写了一行代码var a,如果是console.log(a); a = 2;没有var的情况下,会报//ReferenceError: a is not defined
再来一个例子:

var name="Bob";  
(function(){  
    if(typeof name=== 'undefined'){  
        var name='Jack';//此处增加name声明  
        //  name = 'Jack'  
        console.log('Goodbye'+name);  
    }else{  
        console.log('hello'+name);  
    }  
})()   // 输出:GoodbyeJack

等价于==>

var name="Bob";  
(function(){  
	var name    // name先找自己的作用域,然后再找全局
    if(typeof name=== 'undefined'){  
        name='Jack';//此处为赋值操作
        //  name = 'Jack'   
        console.log('Goodbye'+name);  
    }else{  
        console.log('hello'+name);  
    }  
})()   // 输出:GoodbyeJack

修改一下:

(function(){  
           name='Jack';   //没有使用var ,默认声明为全局变量 window.name = 'Jack'
           if(typeof name=== 'undefined'){  
                console.log('Goodbye'+name);  
            }else{  
                console.log('hello'+name);  
            }  
    })(); // helloJack  
    

注意:多个script不可以跨越

`<script>`

`console.log(a)`

`</script>`

`<script>`

`var``a = 1;`

`</script><br>``// 控制台报错`ReferenceError: a is not defined

3、函数提升

变量提升了,那么函数的声明也会提升。

函数的声明有两种方式:

  • 1、命名函数式
// 声明式
function foo() {
    .....
}

  • 2、函数字面量式(即函数表达式)
// 字面量式
var foo = function() {
    .....
}

那么重点来了,先看例子:

console.log(bar);  // f bar() { console.log(123) }
console.log(bar()); // undefined
var bar = 456;
function bar() {
    console.log(123); // 123
}
console.log(bar); // 456
bar = 789;
console.log(bar); // 789
console.log(bar()) // bar is not a function

相当于:

// js执行步骤
 
// 函数提升,函数提升优先级高于变量提升
var bar = function() {
    console.log(123)
};
// 变量提升,变量提升不会覆盖(同名)函数提升,只有变量再次赋值时,才会被覆盖
var bar;
console.log(bar);
console.log(bar());
// 变量赋值,覆盖同名函数字面量
bar = 456;
console.log(bar);
// 再次赋值
bar = 789
console.log(bar);
console.log(bar());

两个例子得到的结果:

// js执行结果
 
f bar() { console.log(123) }
123  // 执行bar()里的console.log
undefined // bar()的返回值,如果函数没有返回值,默认为:undefined
456
789
[typeError]:bar is not a function

得出结论:

函数的提升优先级高于变量的提升,且不会被同名变量声明时覆盖,但是会被变量赋值后覆盖

???那么命名函数和字面量式函数的提升有什么不同呢?

  • 1、先看命名函数式
foo()  // 1
function foo() {
  console.log('1')
}

说明命名函数式的函数本身也会提升到当前作用域的最前面

  • 2、再看下字面量式(表达式):
foo() // Uncaught TypeError: foo is not a function, 此时的foo为undefined
var foo = function() {
  console.log('1')
}
<=>相当与以下代码
var foo
foo()
foo = function() {
  console.log('1')
}

注意:同名函数声明,则覆盖之前的函数声明

foo() // 4
function foo() {
  console.log('3')
}
function foo() {
  console.log('4')
}

但是同名不同形式的声明方式是不一样的

foo() // 3  函数提前不覆盖
function foo() {
  console.log('3')
}
var foo = function() {
  console.log('4')
}
foo()  //4  覆盖前面的方法

总结:命名函数式直接一整个函数申明提前,后面没有赋值操作,但是字面量式首先变量先申明提前,赋值操作在后面

最后用一个面试题结尾:

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(); // 2  => Foo的静态属性getName
getName(); // 4  => 执行全局环境下的getName
Foo().getName(); //  1    <=>window.getName()
getName(); // 1  => 执行全局环境下的getName
new Foo.getName(); // 2 => 执行Foo的静态属性getName的构造函数
new Foo().getName(); // 3 相当于Foo实例原型上的getName
new new Foo().getName(); // 3 相当于Foo实例原型上的getName的构造函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值