JavaScript——变量作用域

我怕爱的太早我们不能终老 提交于 2020-01-15 14:36:44

在javascript中, var 定义变量实际是有作用域的。

1、var变量作用域问题

1.2、假设一个变量在函数体中声明,则该变量的作用域为整个函数体则在函数体外不可以使用。

function qj() {
    var x = 1;
    x = x + 1;
}

x = x + 2; //Uncaught ReferenceError: x is not defined    无法在函数体外引用变量x

1.2、如果两个函数使用了相同的变量名,只要在函数内部,就不冲突

function qj() {
    var x = 1;
    x = x + 1;
}

function qj2() {
    var x = 'A';
    x = x + 1;
}

1.3、内部函数可以访问外部函数的成员,反之则不行

function qj() {
    var x = 1;

    // 内部函数可以访问外部函数的成员,反之则不行
    function qj2() {
        var y = x + 1;  // 2
    }

    var z = y + 1; // Uncaught ReferenceError: y is not defined
}

1.4、假设,内部函数变量和外部函数的变量重名

function qj() {
    var x = 1;

    function qj2() {
        var x = 'A';
        console.log(' x in qj2()='+x); // x in qj()=1
    }
    console.log('x in qj()='+x); //x in qj2()=A
    qj2()

}

qj()

结论:假设在JavaScript 中 函数查找变量从自身函数开始,由 ‘’内‘’ 向 ‘’外‘’ 查找 . 假设外部存在这个同名的函数变量,则内部函数会屏蔽外部函数的变量。

2、提升变量的作用域

JavaScript的函数定义有个特点,它会先扫描整个函数体的语句,把所有申明的变量“提升”到函数顶部:

'use strict';
function qj() {
    var x = "x" + y;
    console.log(x);
    var y = 'y';
}

qj() //x undefined

问题:为什么会出现 x undefined?

说明:虽然是strict模式,但语句并不报错,var x = "x" + y;原因是变量y在稍后申明了。但是console.log显示x undefined,说明变量y的值为undefined。这正是因为JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值。

对于上述qj()函数,JavaScript引擎看到的代码相当于:

function qj() {
    var y;
    var x = "x" + y;
    console.log(x);
    y = 'y';
}

这个是在JavaScript建立之初就存在的特性。养成规范: 所有的变量定义都放在函数的头部,不要乱放,便于代码维护;

function qj2() {
    var x = 1,// x初始化为1
        y = x + 1,// y初始化为2
        z,i; //z和i为undefined

    //其他语句
}

3.全局函数

不在任何函数内定义的变量就具有全局作用域。实际上,JavaScript默认有一个全局对象window,全局作用域的变量实际上被绑定到window的一个属性:

x = 1;

function f() {
    console.log(x);
}
f();  //1
console.log(x);  //1

3.1、全局对象 window

var x = 'xxx';
alert(x);
alert(window.x); // 默认所有的全局变量,都会自动绑定在 window对象下;

3.2、alert() 这个函数本身也是一个 window 变量

var x = 'xxx';

window.alert(x);

var old_alert = window.alert;

old_alert(x);//xxx

window.alert = function () {

};
window.alert(123);// 发现 alert() 失效了

//恢复
window.alert =  old_alert;
window.alert(456);

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

4、规范

由于我们所有的全局变量都会绑定到我们的 window 上。如果不同的js 文件,使用了相同的全局变量,就会造成命名冲突,并且很难被发现

如何能够减少冲突?

把自己的代码全部放入自己定义的唯一空间名字中, 降低全局命名冲突的问题~

// 唯一全局变量
var MYAPP = {};

// 定义全局变量
GodlesApp.name = 'myapp';
//其他函数
MYAPP.add = function (a,b) {
    return a + b;
}

5、局部作用域 let

'use strict';
function aaa() {
    for (var i = 0; i < 100; i++) {
        console.log(i)
    }
    console.log(i+1); //101  
}

问题: 为什么i出了这个作用域还可以使用?

ES6let 关键字,用let替代var可以申明一个块级作用域的变量

'use strict';
function aaa() {
    for (let i = 0; i < 100; i++) {
        console.log(i)
    }
    console.log(i+1); //Uncaught ReferenceError: i is not defined
}

建议大家都是用 let 去定义局部作用域的变量;

6、常量 const

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

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

在 ES6 引入了常量关键字 const

const PI = '3.14'; // 只读变量
console.log(PI);  //3.14
PI = '123'; // TypeError: Assignment to constant variable.
console.log(PI); //3.14

7、解构赋值

从ES6开始,JavaScript引入了解构赋值,可以同时对一组变量进行赋值。

7.1、传统赋值

//如何把一个数组的元素分别赋值给几个变量?
var array = ['hello', 'JavaScript', 'ES6'];
var x = array[0];
var y = array[1];
var z = array[2];

7.2、ES6赋值

'use strict';
// 如果浏览器支持解构赋值就不会报错:
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];
// x, y, z分别被赋值为数组对应元素:
console.log('x = ' + x + ', y = ' + y + ', z = ' + z);
//x = hello, y = JavaScript, z = ES6

注意:对数组元素进行解构赋值时,多个变量要用[...]括起来。

7.2.1、如果数组本身还有嵌套,也可以通过下面的形式进行解构赋值,注意嵌套层次和位置要保持一致:

let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
x; // 'hello'
y; // 'JavaScript'
z; // 'ES6'

7.2.2、解构赋值还可以忽略某些元素:

let [, , z] = ['hello', 'JavaScript', 'ES6']; // 忽略前两个元素,只对z赋值第三个元素
z; // 'ES6'

7.2.3、如果需要从一个对象中取出若干属性,也可以使用解构赋值,便于快速获取对象的指定属性:

'use strict';

var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    password: '123456',
    school: 'No.1 middle school'
};
var {name, age, passport} = person// name, age, passport分别被赋值为对应属性
console.log('name = ' + name + ', age = ' + age + ', password = ' + password);
//name = 小明, age = 20, passport = 123456
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!