本文翻译自Mozilla的官方JavaScript教程系列之《Values, variables, and literals》。
原文地址:
https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Values,_variables,_and_literals
这一章主要将讨论JavaScript能够识别并且是组成JavaScript的基本结构单元的各种数据:值、变量、直接量。
值
JavaScript支持以下的各种类型的值:
数值,比如说 42 或者 3.14159
逻辑值,要么 true 要么 false
字符串,比如 “Howdy”
null, 这是一个特殊的关键字表示没有值;null 也是一个原始值,因为JavaScript是大小写敏感的,所以null和Null、NULL或者其他变量是有区别的
undefined,这是一个顶级属性;同样,undefined也是一个原始值
对象和方法是其他两个在JavaScript中的基本元素。你可以认为对象是数据的一个容器,而方法是你应用程序中的一个处理过程。
数据类型转换
JavaScript是一个动态类型的语言,这就意味着当你在申明一个变量的时候你不需要指定他的数据类型,这些数据类型将会在执行过程中根据要求被自动指定。比如说你可要定义一个变量如下:
var answer = 42;
而之后,你又在同一个变量上为他赋一个字符串的值,像这样:
answer = "Thanks for all the fish...";
因为JavaScript是动态编译,这种赋值将不会引发一个异常。
在用“+”符号将数值和字符串连接的表达式中,JavaScript将会把数字转换为字符串来处理。比如,看看下面的表达式:
x = "The answer is " + 42 // returns "The answer is 42" y = 42 + " is the answer" // returns "42 is the answer"
但是如果你用其他的操作符,而不是”+“,JavaScript将不会转换数字为字符串,比如:
"37" - 7 // returns 30 "37" + 7 // returns "377"
字符串转换为数字
有一种情况就是一个值代表的是数字,然而在内存中却以字符串的形式存储,这个时候你就可能需要用到下面的方法去做一个转换。
parseInt() 和 parseFloat()
详情请看: parseInt() 和 parseFloat()。
使用parseInt()将只会返回一个整数,意味着对小数操作将减少他的精度。
加运算符
这儿还有一种方式就是采用“+”符号来转换字符串为数字。
"1.1" + "1.1" = "1.11.1" (+"1.1") + (+"1.1") = 2.2 // 注意:括号加上只是为了让代码更清晰,并不是必须的
变量
一般我们都会使用变量来表示你的数据。变量的名字我们称之为标识符,他必须满足一些规则。
一个JavaScript的标识符必须以字母,下划线(_)、或者美元符号($)开头,其次的部分可以加上数字(0-9)。还有一点,因为JavaScript是大小写敏感的,所以字母就理所当然的包括了从A到Z和从a到z。
从JavaScript 1.5开始,你可以使用ISO 8859-1或者Unicode 编码的字母,比如在标识符中可以使用å 和 ü,你也可以使用像\uXXXX这样的 Unicode编码来转义一些字符。
这里列了几个合法的名字:
Number_hits
, temp99
, 和 _name。
声明变量
你可以声明一个变量通过以下两种方式:
使用关键字"var"。比如,var x = 42,这种方式既可以用于局部和全局变量。
仅仅通过赋值操作。比如,x = 42,这种方式会声明一个全局变量,并且会得到一个JavaScript的一个警告,所以你应该避免使用这种方式。
高级变量
使用"var"来声明一个没有初始值的变量将会被指定为"undefined"。
当尝试去访问一个未声明的变量将会得到一个”ReferenceError”的异常:
var a; console.log("The value of a is " + a); // prints "The value of a is undefined" console.log("The value of b is " + b); // throws ReferenceError exception
你可要通过”undefined“来判定一个变量是否有值。在下面的代码中,变量”input“没有被赋值,而if 条件中将得到true的结果:
var input; if (input === undefined) { doThis(); } else { doThat(); }
当使用一个boolean类型时,undefined 会被认为是false。比如在下面的代码中,因为myArray并没有被定义,所以将执行myFunction方法:
var myArray = new Array();
if (!myArray[0]) myFunction();
当使用一个数字类型时,undefined会被转换为 NaN:
var a;
a + 2 = NaN
当你计算一个null变量时,在数字类型中,null将会作为0来计算,而在逻辑运算boolean中,null会被认为是false。比如:
var n = null; console.log(n * 32); // prints 0
变量作用域
当你在一个方法外定义一个变量是,这个变量的作用域就是全局的,因为在当前的这个文档中,任何地方都可以访问到他。相反的,当你定义一个变量在方法内时,此变量会被认为是局部变量,因为他只能被方法内的代码访问到。
JavaScript里并不存在表达式块的范围,当然,如果一个变量在一个语句块里,他也会被认为是局部变量。下面的代码将会记录5,因为x的声明是在一个方法或者是一个全局的上下文中,而不是在下面if的语句块中(没表达清楚,有点让人疑惑):
if (true) { var x = 5; } console.log(x);
还有一件关于变量不同寻常的事,就是你可以得到一个在之后声明的变量,而又不报异常。这里存在一个概念叫”推断“(原文是hoisting,大概是这个意思吧)。
JavaScript中的变量一直处于一个”推断“状态,或者说是可以传递到一个方法或者表达式的顶端。但是,变量将不会被初始化,因此你会得到一个undefined:
/** * Example 1 */ console.log(x === undefined); // logs "true" var x = 3; /** * Example 2 */ // will return a value of undefined var myvar = "my value"; (function () { console.log(myvar); // undefined var myvar = "local value"; })();
(个人对这个的理解是方法体内myvar的声明把全局myvar给覆盖了,声明首先被检测到,而赋值则在输出的后面,因此会是undefined)正是由于这种”推断“,所有var表达式
的表达式都应该被放到尽可能方法里的顶部。
全局变量
全局变量事实上是一个全局对象的一个属性。在web页面中,这个全局的对象就是window,因此你可要设置和访问一个全局变量通过window.变量名的语法。
因此,你可以访问一个全局变量,这个变量声明在一个window或者frame中,而你可以通过指定的window或者frame的名字来访问他从另一个window或者frame中。比如,如果一个变量叫phoneNumber声明在一个FRAMESET的文档中,你可以从他的一个子frame中通过
parent.phoneNumber
访问到他.
常量
你可以用const关键字来创建只读的常量。声明一个常量的规则和声明变量的规则一样:
const prefix = '212';
一个常量不允许在脚本运行过程为其赋值或者重新声明。
常量的作用域规则和变量的一样,除了常量中,关键字const是必须的,即使是全局常量也必须加上。如果关键字被省略了,那JavaScript将会认为他是一个变量。
你不能让一个常量的名字和方法或者变量的名字一样。比如:
// THIS WILL CAUSE AN ERROR function f() {}; const f = 5; // THIS WILL CAUSE AN ERROR ALSO function f() { const g = 5; var g; //statements }
直接量
注:关于直接量的一些内容我也不是很清楚,先挂一个和他相关的文章在这里,空时候再仔细了解。
下面的区域概括了以下的直接量类型:
数组
一个数组直接量对象由0个或者更多的表达式组成,每一个都表示了一个数组元素,每一个数组元素都是由一对中括号([])包含。当你用一个数组直接量创建一个数组的时候,他会被用指定的值来作为他的元素值,而他的长度则被指定的参数设定。
下面的列子创建了一个包含三个元素的coffees数组和他们三个的一个长度:
var coffees = ["French Roast", "Colombian", "Kona"];
注意:一个数组直接量是对象初始器的一种类型。详情请看使用对象初始器。
如果一个通过直接量来创建的数组放在脚本的最顶层时,每次当他尝试编译这个表达式的时候JavaScript会解释说明这个数组。不仅如此,当每次尝试调用一个包含了一个直接量时,这个直接量会被创建。
数组直接量同样也是数组对象。详情请看数组对象。
在数组直接量中多余的逗号
在一个数组直接量中,你不必指定所有的元素。如果你把两个都好在一行里,这个数组会用undefined来为没有指定值的元素创建。下面的列子创建了一个fish的数组:
var fish = ["Lion", , "Angel"];
这个数组有两个元素有值和一个空元素。
如果在你元素列表的末尾包含了一个逗号,那么这个逗号将会被忽略。在下面的列子中,这个数组的长度是三。这里没有myList[3]。所有在列表中的其他逗号都表示一个新的元素。(注意:在老式的浏览器中,最末尾的这个逗号会引发一个错误,因此多一事不如少一事,还是不要加上吧):
var myList = ['home', , 'school', ];
在下面的列子中,数组的长度是四,myList[0]和myList[2]丢失:
var myList = [, 'home', , 'school'];
在下面的例子中,数组的长度是四,myList[1]和myList[3]丢失。只有最后一个逗号被忽略:
var myList = ['home', , 'school', , ];
正确的理解这些附加的逗号对于理解JavaScript是非常重要的。然而,当我们在编写我们的代码时:使用undefined来表示缺失的元素会增加你代码的可读性和可维护性。
布尔直接量
布尔类型有两个直接量值:true和false。
不要布尔值的原始值true和false与布尔对象的true和false值相互混淆。布尔对象是元数据布尔类型的包装实现。详情请看布尔对象。
数值
数值能够表示十进制、十六进制、和八进制。
- 十进制包含了一些列的不以0开头的数字
- 在八进制中,是以0开头的,并且八进制只能包括从0到7的数字
- 在十六进制中,是以0x(或者0X)开头来表示的。十六进制只能包括从0-9和字母从a-f和A-F
八进制已经被弃用了并且在ECMA-263,也就是标准3中已经被移除掉了。但是为了保证向后兼容性,JavaScript 1.5任然还支持。
这儿有一些数值的例子:
0, 117 and -345 (十进制, base 10)
015, 0001 and -077 (八进制, base 8)
0x1123, 0x00111 and -0xF1A7 (十六进制, "hex" or base 16)
浮点直接量
一个浮点直接量可以由以下的部分组成:
- 一个带符号(”+”或”-“)的整数部分
- 一个小数点
- 一个分数部分 (another decimal number),
- 一个指数
指数部分指的是在一个带符号的整数后面再加上一个”e”(或者”E”)。一个浮点直接量必须有至少一个数字和一个小数点或者是一个指数”e”(或者“E”)
3.1415, -3.1E12, .1e12, and 2E-12 这些都是浮点数的例子。
想更多更简洁的话,下面是他的语法:
[digits][.digits][(E|e)[(+|-)]digits]
比如:
3.14 2345.789 .3333333333333333333
对象直接量
一个对象的直接量是由0个或者多个使用({})包含的属性名和其对应的值对。你不应该在一个表达式的开头使用一个对象直接量。这会引发一个错误或者不可预料的行为,因为”{”是作为一个块的开始。
下面是一个对象直接量的例子。这个car的对象的第一个元素定义了一个属性mycar,第二个元素也就是属性getCar和一个方法function(CarTypes(“Honda”))相关联,但三个元素即属性special,对应一个以存在的变量(Sales)。
var Sales = "Toyota"; function CarTypes(name) { return (name == "Honda") ? name : "Sorry, we don't sell " + name + "."; } var car = { myCar: "Saturn", getCar: CarTypes("Honda"), special: Sales }; console.log(car.myCar); // Saturn console.log(car.getCar); // Honda console.log(car.special); // Toyota
加之,你可要使用一个数字或者一个字符串的直接量来表示一个属性名或者是包含一个对象在其对应的值里面。下面的例子采用这些可选的方式:
var car = { manyCars: { a: "Saab", "b": "Jeep" }, 7: "Mazda" }; console.log(car.manyCars.b); // Jeep console.log(car[7]); // Mazda
请注意:
var foo = { a: "alpha", 2: "two" }; console.log(foo.a); // alpha console.log(foo[2]); // two //console.log(foo.2); // Error: missing ) after argument list //console.log(foo[a]); // Error: a is not defined console.log(foo["a"]); // alpha console.log(foo["2"]); // two
字符串直接量
字符串直接量是由0个或者多个用双引号"或者单引号'包括的字符。一个字符串必须由相同的引号类型来包括。也就是说要么都是双引号,要么都是单引号。下面是一些例子关于字符串直接量的:
"foo"
'bar'
"1234"
"one line \n another line"
"John's cat"
你可以在一个字符串直接量上调用字符串对象的所有方法—JavaScript自动的把一个字符串直接量转换为一个临时字符串对象,然后再调用这个临时对象的方法,最后再丢弃这个临时对象。因此你可以在字符串直接量上使用像String.length的属性:
"John's cat".length
推荐你应该使用字符串直接量,除非你确实需要一个字符串对象。更多关于字符串对象详情
String Object
在字符串中使用特殊字符
在一般的字符集合众,你可能需要包含一些特殊在字符在字符串里,就像下面的例子。
"one line \n another line"
下面的一个表列出了你可要在JavaScript中可以用到的特殊字符:
字符 | 意思 |
\b | 退格 |
\f | 换页 |
\n | 换行 |
\r | 返回 |
\t | 制表符 |
\v | 垂直制表符 |
\' | 单引号 |
\" | 双引号 |
\\ | 反斜杠 |
\XXX | 采用Latin-1编码来指定三个八进制数字从0-377。比如说,\251就是表示版权符号@ |
\xXX | 采用Latin-1编码来指定两个十六进制数字从00到FF。比如说,\A9就是表示版权符号@ |
\uXXXX | 四个采用Unicode编码来的十六进制数。比如说,\u00A9 就是表示版权符号@。请看Unicode 转义序列 . |
下面的是转义字符和Unicode编码相关的就先不翻译了。实在有点吃不消。