变量声明

1 使用var的函数作用域声明

在使用var声明变量时,变量会被自动添加到最接近的上下文。在函数中,最接近的上下文就是函数的局部上下文。在with语句中,最接近的上下文也是函数上下文。如果变量未经声明就被初始化了,那么它就会自动被添加到全局上下文

function add(num1, num2) {
  var sum = num1 + num2;
  return sum;
}
let result = add(10, 20); // 30
console.log(sum);         //报错:sum在这里不是有效变量
复制代码

函数add()定义了一个局部变量sum,保存加法操作的结果。这个值作为函数的值被返回,但变量sum在函数外部是访问不到的。如果省略上面例子中的关键字var,那么sum在add()被调用之后就变成可以访问的了:

function add(num1, num2) {
  sum = num1 + num2;
  return sum;
}

let result = add(10, 20); // 30
console.log(sum); // 30
复制代码

这一次,变量sum被用加法操作的结果初始化时并没有使用var声明。在调用add()之后,sum被添加到了全局上下文,在函数退出之后依然存在,从而在后面可以访问到。

var声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前。这个现象叫作“提升”(hoisting)。提升让同一作用域中的代码不必考虑变量是否已经声明就可以直接使用。可是在实践中,提升也会导致合法却奇怪的现象,即在变量声明之前使用变量。下面的例子展示了在全局作用域中两段等价的代码:

var name = "Jake";

//等价于:

name = 'Jake';
var name;
复制代码
function fn1() {
  var name = 'Jake';
}

//等价于:
function fn2() {
  var name;
  name = 'Jake';
}
复制代码

2 使用let的块级作用域声明

ES6新增的let关键字跟var很相似,但它的作用域是块级的,这也是JavaScript中的新概念。块级作用域由最近的一对包含花括号{}界定。换句话说,if块、while块、function块,甚至连单独的块也是let声明变量的作用域。

let与var的另一个不同之处是在同一作用域内不能声明两次。重复的var声明会被忽略,而重复的let声明会抛出SyntaxError。

let的行为非常适合在循环中声明迭代变量。使用var声明的迭代变量会泄漏到循环外部,这种情况应该避免

for (var i = 0; i < 10; ++i) {}
console.log(i); // 10

for (let j = 0; j < 10; ++j) {}
console.log(j); // ReferenceError: j没有定义
复制代码

3 使用const的常量声明

除了let,ES6同时还增加了const关键字。使用const声明的变量必须同时初始化为某个值。一经声明,在其生命周期的任何时候都不能再重新赋予新值。

const a; // SyntaxError:常量声明时没有初始化

const b = 3;
console.log(b); // 3
b = 4; // TypeError:给常量赋值
复制代码

const声明只应用到顶级原语或者对象。换句话说,赋值为对象的const变量不能再被重新赋值为其他引用值,但对象的键则不受限制:

const o1 = {};
//o1 = {}; // TypeError:给常量赋值

const o2 = {};
o2.name = "Jake";
console.log(o2.name); // 'Jake'
o2.name = "Tom";
console.log(o2.name); // 'Tom'
复制代码

如果想让整个对象都不能修改,可以使用Object.freeze(),这样再给属性赋值时虽然不会报错,但会静默失败:

const o3 = Object.freeze({});
o3.name = 'Jake';
console.log(o3.name); // undefined
复制代码

const除了要遵循以上规则,其他方面与let声明是一样的

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享