New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何在 JavaScript 中声明变量 #15

Open
rccoder opened this Issue Sep 15, 2016 · 3 comments

Comments

Projects
None yet
3 participants
@rccoder
Copy link
Owner

rccoder commented Sep 15, 2016

  • 2016-9-17 10:46 补充说明 const 关于引用值修改问题

我们在学习 JavaScript 的过程中最基础的一项就是如何使用变量。变量是存储所有可能类型(比如:number, string, array 等)值的容器。每个变量都会有一个被称之为变量名的名字,这个名字会在后面的代码中使用(比如:读出这个变量的值)。

在这篇文章中,你将会了解到如何去使用变量以及不同变量声明方式的区别。

声明、初始化、赋值之间的区别

声明: 变量将会已一个包含相应作用域范围(比如: 在一个函数里面)的名字进行注册。

初始化: 当你声明一个变量的时候会自动的进行初始化,也就是说由 JavaScript 解释引擎为变量分配了一块内存。

赋值: 把一个指定的值指派(赋)给一个变量。

声明的类型

注意: 在 JavaScript 第一个版本 released 的的时候 var 这个关键词就是可以使用的。在 ES6(ES 2015)以及之后的版本中出现了 letconst 关键词

var

语法:

var x; // 声明变量、初始化
x = "Hello World"; // 赋值

// 用一行代码写
var y = "Hello World";

这种方式的变量声明和赋值是非常流行的,直到 ES 2015 出现之后这种方式才有了可替代的方法。在封闭的函数作用域中用 var 的方式声明变量是可以的,但是如果不是在封闭的函数作用域中,声明的变量就是全局的。(换句话中,用 var 声明没有块级作用域的概念)

例子:

function sayHello(){
  var hello = "Hello World";
  return hello;
}
console.log(hello);

这将会抛出一个错误ReferenceError: hello is not defined,变量hello只有在函数sayHello中是可用的。但是下面的这个例子将会正常工作,以变量全局声明的方式运行。

var hello = "Hello World";
function sayHello(){
  return hello;
}
console.log(hello);

let

语法:

let x; // 声明与初始化
x = "Hello World"; // 赋值

// 用一行代码写
let y = "Hello World";

在新的 JavaScript 中出现了 var 的后裔。 let 的作用域不仅在函数中封闭,也在块语句中封闭。块语句就是包含在 {} 中的所有语句(比如: 一个判断或一个循环)。let 的优点就是让变量在一个较小的范围内使用,这样就可以让错误产生的可能性减小。

例子:

var name = "Peter";
if(name === "Peter"){
  let hello = "Hello Peter";
} else {
  let hello = "Hi";
}
console.log(hello);

这将会抛出一个错误:ReferenceError: hello is not defined,变量 hello 只有在块级作用域中是可用的(这个例子中的 if 判断中),但是下面的例子将正常工作。

var name = "Peter";
if(name === "Peter"){
  let hello = "Hello Peter";
  console.log(hello);
} else {
  let hello = "Hi";
  console.log(hello);
}

const

语法:

const x = "Hello World";

技术角度上讲 constant 不是一个变量。constant 的特殊就在于你只能在声明的时候进行初始化(赋值给他),在以后的过程中是无法给他赋新值的。constant 也是限制于块级作用域中(和 let 一样)

constant 应该用于那些在程序运行的时候值一定不能改变的量,当你想重写他的值得时候,应用将抛出一个错误。

注解:

如果 const 的变量是一个引用类型的,比如 Object 或者 Array,会发现这个变量还是可以修改的。但是这并不违反上文所说的内容。

引用类型可以理解为申明了一块地址,然后指针指向一块内容。像 Object 或者 Array 这样的引用类型,我们在修改值得时候并不会改动他的指针地址,变得只是指向的内容里面的东西。

例子:

const a = {};
a['b'] = 1;

const b = [];
b.push(1)

意料之外的全局变量创建

你可能会创建一个全局的变量(比如: 在函数的外面),但是即使你在函数的里面,如果你在声明变量的时候忘记了写 varlet 或者 const,创建的变量也将会是全局的。

例子:

function sayHello(){
  hello = "Hello World";
  return hello;
}
sayHello();
console.log(hello);

上面的例子将会输出 Hello World,这是因为在函数中变量 hello 声明的时候 hello = 前面没有任何的变量声明描述。

要避免这种意料之外的全局变量声明你可以在 JavaScript 中开启 严格模式。

变量提升和时间死区(Temporal Dead Zone)

varlet/const 之间的另外一个重要区别就是 变量提升。变量的声明一直会被提升到当前作用域的顶部,这也就是说:

console.log(hello);
var hello;
hello = "I'm a variable";

等价于

var hello;
console.log(hello);
hello = "I'm a variable";

这种方式的表现方式就是在两个例子中都会输出 undefined。如果不是 var hello, 变量的声明将不会提升到作用域的顶部,并且将抛出一个 ReferenceError 的错误

这种现象叫做hoist,在 var 中有,同样在 let/const 中也有。

就和上面所提及到的一样,在声明代码之前使用后面用 var 声明的变量会返回一个 undefined,这个值是默认的在初始化的时候赋进去的。

但是如果是在声明之前使用后面会用 let/const 声明的变量会抛出一个错误。这个因为变量在声明代码之前是不可用的(没有被初始化)。进入作用域和使用作用域的值得这段时期就叫做时间死区(Temporal Dead Zone)

注解:
时间死区(Temporal Dead Zone): 在进入一个scope之后,let/const也会有一个hoist,这个过程和var 一样,区别是 var 在hoist之后,被初始化为了 undefined,但是let/const没有初始化,直到真正声明它的地方。

结论

无论在什么情况下,为了减少出现不必要的错误你应该使用 letconst。如果你一定要使用 var,最好在作用域的顶部使用,以防止产生不可预料的错误(大多和变量提升相关)

原文: Quick Tip: How to Declare Variables in Javascript

参考资料:


版权声明

  • 请尊重辛勤劳动
  • 禁止不署名完全转载,可单独通过下面的捐赠付版权费
  • 建议署名并进行摘要性质转载

捐赠

写文不易,赠我一杯咖啡增强一下感情可好?

alipay

@rccoder rccoder added the JavaScript label Sep 15, 2016

@codezyc

This comment has been minimized.

Copy link

codezyc commented Sep 16, 2016

👍

@xiyuanyuan

This comment has been minimized.

Copy link

xiyuanyuan commented Sep 16, 2016

👏 可以再进一步讲一下function的声明定义吗

@rccoder

This comment has been minimized.

Copy link
Owner

rccoder commented Sep 17, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment