js变量的作用域(let、const关键字)/变量的提升、函数的提升

导读:本篇文章讲解 js变量的作用域(let、const关键字)/变量的提升、函数的提升,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

1 参数问题

可以传递任意一个参数,也可以不传递参数。

(1)假设不存在参数,如何避免?可以手动抛出异常
var abs = function(x){
  	//手动抛出异常,增加一层判断
    if(typeof x!=='number'){
        throw 'not a number';
    }
    if(x>=0){
        return x;
    }else{
        return -x;
    }
}
(2)存在多个参数问题

arguments 是js免费赠送的关键词,代表传递进来的所有参数是一个数组!

var abs = function(x){
    console.log("x=>"+x);
   	for( var i = 0;i < arguments.length; i++){
        console.log(arguments[i]);
    }
    if(x>=0){
        return x;
    }else{
        return -x;
    }
}
(3)ES6的新特性—rest

用来获取除了已经定义的参数之外的的所有参数

书写规范:rest参数只能写在最后面,必须用…rest标识

2 变量的作用域
(1)var定义变量实际是有作用域的,在函数体中声明,则在函数体外不可以使用~,如果想使用,涉及到闭包。
function a(){
    var x = 1;
    x = x + 1;
}
x = x + 1;//Uncaught ReferenceError:x is not defined
(2)如果两个函数使用了相同的变量名,只要在函数内部,就不冲突。
function a(){
    var x = 1;
    x = x + 1;
}

function b(){
    var x = 'A';
    x = x + 1;
}
(3)内部函数可以访问外部函数,反之则不可以
function a(){
    var x = 1;
    function b(){
        var y = x + 1;
    }
    var z = y + 1;//Uncaught ReferenceError:y is not defined
}
(4)内部函数使用的变量名与外部函数使用的变量名,重名

在js中函数查找变量从自身开始,有内向外查找,假设外部存在这个同名的函数变量,则内部函数会屏蔽外部函数的变量。

function a(){
    var x = 1;
    function b(){
        var x = 'A';
        console.log('inner'+x);//inner1
    }
    console.log('outer'+x);//outerA
    b();
}
a();
  • 提升变量的作用域(js变量提升)js执行引擎,自动提升了y的声明,但是不会提升变量的赋值
  • 这是在js建立之初就存在的特性。养成书写规范:所有的变量定义都放在函数的头部,不要乱放位置,便于代码的维护!!
function a(){
    var x = "x" + y;
    console.log(x);
    var y = "y";
}//结果xundefined

//变量提升
function a(){
    var y
    var x = "x" + y;
    console.log(x);
    y = 'y';
}
(5)全局函数
//全局变量
x = 1
function f(){
    console.log(x);
}
f();
console.log(x);

全局对象window(默认所有的全局变量,都会自动绑定在window对象下)

var x = 'xxx';
//两种方法等价
alter(x);
alter(window.x);
//补充:alter能被调用,说明本身也是window的变量

js实际上只有一个全局作用域,任何变量(函数也可以看作变量),假设没有在函数作用范围内找到,就会向外查找,如果在全局作用域都没有找到,则会报错RefrenceError。

规范:由于所有的全局变量都会绑定到window上。如果不同的js文件,使用了相同的全局变量,就会发生冲突。

解决方法:把自己的代码全部放入自己定义的唯一空间名字中,降低全局命名冲突问题。(框架也是这么书写规范,防止冲突)

//唯一全局变量
var xiaohang = {};
//定义全局变量
xiaohang.name = 'wang';
xiaohang.add = function(a,b){
    return a + b;
}
(6)局部作用域let
function a(){
    for(var i = 0; i < 100; i++){
        console.log(i)
    }
    console.log(i + 1);//i出了这个作用域还可以使用,这就产生问题。
}

解决问题:ES6新特性引入let关键字,解决局部作用域冲突问题。(建议使用let去定义)

function a(){
    for(let i = 0; i < 100; i++){
        console.log(i)
    }
    console.log(i + 1);//Uncaught RefrenceError: i is not defined
}

(7)常量const

在ES6之前,怎么定义常量?用全部大写字母命名的变量就是常量,建议不要修改这样的值。

var PI = '3.14';
console.log(PI)PI = '123';//可以改变值
console.log(PI);

在ES6引入了常量关键字const

const PI = '3.14';//只读常量
console.log(PI)PI = '123';
console.log(PI);

3 变量的提升和函数的提升
程序员都知道任何代码都分为编译阶段执行阶段也可以理解为词法分析(分析变量声明,分析函数声明,分析形参)执行阶段,引擎通过词法分析将我们编写的js代码转成可以执行的代码,然后再去执行代码。

(1) 变量提升

console.log(a);
var a = 123456;
//输出结果为undefined

Q:为什么输出结果是undefined?为什么不会报错?为什么输出结果不是null呢?

A:这时候就要引出变量提升的知识点了。代码执行第一阶段是编译阶段,js中变量的声明会被提升到当前作用域的最顶端(全局作用域)构建一个scope对象,把所有的变量放进去整理。给当前代码一个运行环境(执行上下文)。因为js的类型由值决定的,所以输出结果不是null。

//代码编译后是这样的,变量a的声明被提到了作用域的顶端。
var a;//声明的是一个没有值的变量
console.log(a);//执行阶段的执行语句
a = 123456;

(2) 函数提升

两种方式:【1】函数声明式,【2】函数字面量式

和普通变量a一样,提升的是一个没有值的变量。但是和普通变量有所区别,函数声明式会提升到作用域最前边,并且将声明内容一起提升到最左边。

我们先了解以下这两个知识点

  • 完整的函数声明
function fn(){
    console.log('fn');
}//这是一个完整的函数声明

//这样声明
function fn = function(){
    console.log('fn');
}
  • 包含变量声明和赋值
var fn = function(){
    console.log('fn');
}//包含变量声明和赋值

var  fn = undefined;//声明
fn = function(){console.log('fn');}//赋值

举个例子

showTime();
console.log(time);
var time = '北京时间'function showTime(){//函数可以调用,普通变量不可以,这也是区别之一
    console.log('展示北京时间')}

attention:函数在js是老大。函数和变量的区别在于它拥有再次创建上下文的权力,学过C或者java等高级编程语言都知道,函数创建的时候,会在内存中开辟一个空间,执行完之后会释放空间。函数会创建一个函数作用域(局部作用域),这也是函数拥有特权的原因。

//上述代码相当于这样执行
var time;
showTime();
console.log(time);
time = '北京时间';
function showTime(){
    console.log('展示北京时间')}
//因为 function showTime(){console.log('展示北京时间');} 是一个完整的函数生命
//所以输出结果 
//展示北京时间
//undefined

再看一段代码

showTime();
console.log(time);
var time = '北京时间'var showTime = function(){
    console.log('展示北京时间')}//包含变量声明和赋值的函数
//输出结果是 TypeError: showName is not a function

Q:为什么会报错呢?

A:JS的类型是由值决定的!由于编译阶段var showTime变量提升到了最顶端,并且赋予了一个undefined(var time; 在编译阶段 JS变量的类型由值决定 undefined),而showTime();是一个函数调用,与作用域中的showTime不匹配,所以它一定会报错。

总结

  1. 代码是按顺序逐行进行的。
  2. 任何代码都分为编译阶段和执行阶段
  3. 代码执行的阶段涉及变量的查找。
  4. 变量提升指的是把变量的声明部分和函数的声明部分提升到代码开头的行为,变量提升后默认值undefined。
  5. 同一个变量只会声明一次,其他的会被忽略或者覆盖。
  6. 函数声明的优先级高于变量声明的优先级。
    S变量的类型由值决定 undefined),而showTime();是一个函数调用,与作用域中的showTime不匹配,所以它一定会报错。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/16171.html

(0)
小半的头像小半

相关推荐

极客之家——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!