【笔记】JavaScript指南 > 语法和数据类型
这篇笔记主要摘抄自MDN的JavaScript指南,主要是自己作为知识点梳理用。详细还是请看【JavaScript指南】。
感谢互联网技术的发达,让这些知识变得触手可得,也感谢文档编辑以及翻译人员们。
声明
JavaScript有三种声明: var,let,const。
变量求值
用var或let声明的且未赋初值的变量,值会被设定为undefined。试图访问一个未声明的变量或者访问一个使用let声明的但未初始化的变量会导致一个ReferenceError异常被抛出。
可以使用undefined来判断变量是否已赋值。
var input;
if(input===undefined){...}else{...}
undefined值在布尔类型环境中会被当作false。数值类型环境中undefined值会被转换为NaN。
var a;
a + 2;//NaN
当对一个null变量求值时,空值null在数值类型环境中会被当做0来对待,而布尔类型环境中会被当做false。
var n = null;
typeof(n);//object
console.log(n * 3);//0
变量的作用域
ES6之前的JS没有语句块作用域,语句块中声明的变量将成为语句块所在代码段的局部变量。
if(true) {
var x = 5;
}
console.log(x); //5
//因为x的作用域是声明了x的那个函数(或全局范围),而不是if语句块。
if(true){
let y = 5;
}
console.log(y);//ReferenceError: y is not defined
变量声明提升(Variable hoisting)
可以引用稍后声明的变量而不会引发异常。变量感觉上是被提升到所有函数和语句之前,但提升后变量将返回undefined值。
console.log(x === undefined);//logs "true"
var x = 3;
var myvar = "my value";
(function(){
console.log(myvar);//undefined
var myvar = "local value";
})();
也可写作:
var x;
console.log(x === undefined);//logs "true"
x = 3;
var myvar = "my value";
(function(){
var myvar;
console.log(myvar);//undefined
myvar = "local value";
})()
由于存在变量声明提升,一个函数中左右的var语句应该尽可能地放在接近函数顶部的地方,可以大大提升程序代码的清晰度。
ES6中,let与const不会提升到代码块顶部,而是出现暂时性死区,知道这个变量被声明为止。
console.log(x);// ReferenceError
let x = 3;
函数提升(Function hoisting)
只有函数声明会被提升到顶部,不包括函数表达式。
常量(Constants)
可以用关键字const创建一个只读(read-only)的常量。常量不可以通过赋值改变值,也不可以在脚本运行时重新声明,它必须被初始化为某个值。在同一作用域中,不能使用与变量名或函数名相同的名字来命名常量。如以下两种情况都会报错:
//1
function f() {};
const f = 5;
//2
function f() {
const g = 5;
var g;
}
然而,对象属性是不受保护的,所以可以使用如下语句来执行。
const MY_OBJECT = {"key": "value"};
MY_OBJECT.key = "otherValue";
数据结构和类型
数据类型
JavaScript语言可以识别下边七种不同类型的值:
- 六种原型数据类型:
- Boolean. 布尔值,true和false
- null. 一个表明null值的特殊关键字。JS是大小写敏感的,因此null与Null、NULL或其他变量完全不同
- undefined. 变量未定义时的属性。
- Number. 表示数字
- String. 表示字符串
- Symbol(ES6中新添加的类型). 一种数据类型,它的实例是唯一且不可改变的。
- 以及Object对象
Objects 和 functions 是本语言的其他两个基本要素。你可以将对象视为存放值的命名容器,而将函数视为你的应用程序能够执行的过程(procedures)。
数据类型的转换(Data type conversion)
JS是一种动态类型语言(Dynamically typed language)。这意味着声明变量时可以不必指定数据类型,而数据类型会在脚本执行时根据需要自动转换。
//因此,可以这样来定义变量:
var answer = 42;
//然后还可以给这个变量赋予一个字符串值,并不会报错:
answer = "Thanks for all the fish...";
//在涉及加法运算符(+)的数字和字符串表达式中,JS会把数字值转换为字符串:
x = "The answer is " + 42 // "The answer is 42"
y = 42 + " is the answer" // "42 is the answer"
//在涉及其它运算符(如减号-)时,JS语言并不会把数字变为字符串:
"37" - 7 // 30(数学运算)
"37" + 7 //377(字符串运算)
字符串转换为数字
两种方法:
parseInt()和parseFloat():
parseInt返回整数,丢掉小数部分。使用时最好带上进制参数。
使用单目加法运算符
"1.1" + "1.1" = "1.11.1"
(+"1.1") + (+"1.1") = 2.2 //括号不必须
字面量(Literals)
字面量是常量,其值是固定的,而且在程序脚本运行中不可更改(如false, 3.1415)。在JS中可以使用各种字面量:
- 数组字面量(Array literals)
- 布尔字面量(Boolean literals)
- 浮点数字面量(Floating-point literals)
- 整数(Intergers)
- 对象字面量(Object literals)
- RegExp literals
- 字符串字面量(String literals)
数组字面量(Array literals)
当使用数组字面量创建一个数组时,该数组将会以指定的值作为其元素进行初始化。若在全局脚本里用字面量创建数组,JS语言将会在每次对包含该数组字面值的表达式求值时解释该数组。在函数中使用的数组,将在每次调用函数时都会被创建一次。
数组字面值同时也是数组对象。
不必列举数组字面值中的所有元素:
var fish = ["Lion", , "Angel"];
console.log(fish.length); // 3
//如果在元素列表尾部添加括号,它将被忽略
var animals = ["cat", "dog",];
console.log(animals.length); // 2
写代码时,显示地将缺失的元素声明为undefined,将大大提高你的代码的清晰度和可维护性。
布尔字面量(Boolean literals)
(逻辑字面量)
布尔类型有两种字面量:true和false。
不要混淆作为布尔对象的真和假与布尔类型的原始值true和false。布尔对象时原始布尔数据类型的一个包装器。
浮点数字面量(Floating-point literals)
组成部分:
- 一个十进制整数,可带正负号。
- 小数点
- 小数部分
- 指数部分(e/E)
[(+|-)][digits][.digits][(E|e)[(+|-)]digits]
整数(Intergers)
整可以用十进制、十六进制、八进制以及二进制表示。
- 十进制没有前缀0
- 八进制以0(0o, 0O开头),只包括数字0-7
- 十六进制0x(或0X)开头,可以包含数字(0-9)和字母 a~f 或 A~F
- 二进制以0b(0B开头),只包含0和1
对象字面量(Object literals)
对象字面值是封闭在花括号对({})中的一个对象的零个或多个”属性名-值”对的(元素)列表。你不能在一条语句的开头就使用对象字面值,这将导致错误或产生超出预料的行为, 因为此时左花括号({)会被认为是一个语句块的起始符号。
对象属性名字可以是任意字符串,包括空串。如果对象属性名字不是合法的javascript标识符,它必须用”“包裹。属性的名字不合法,那么便不能用.访问属性值,而是通过类数组标记(“[]”)访问和赋值。
var unusualPropertyNames = {
"": "An empty string",
"!": "Bang!"
}
console.log(unusualPropertyNames.""); // 语法错误: Unexpected string
console.log(unusualPropertyNames[""]); // An empty string
console.log(unusualPropertyNames.!); // 语法错误: Unexpected token !
console.log(unusualPropertyNames["!"]); // Bang!
增强的对象字面量 (Enhanced Object literals)
在ES2015,对象字面值扩展支持在创建时设置原型,简写foo:foo分配,定义方法,加工父函数(super calls),计算属性名(动态)。总之,这些也带来了对象字面值和类声明紧密联系起来,让基于对象的设计得益于一些同样的便利。
var obj = {
// __proto__
__proto__: theProtoObj,
// Shorthand for ‘handler: handler’
handler,
// Methods
toString() {
// Super calls
return "d " + super.toString();
},
// Computed (dynamic) property names
[ 'prop_' + (() => 42)() ]: 42
};
注意!
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
RegExp literals
一个正则表达式是字符被斜线(译注:正斜杠“/”)围成的表达式。
字符串字面量(String literals)
字符串字面量是由双引号(”)对或单引号(’)括起来的零个或多个字符。
你可以在字符串字面值上使用字符串对象的所有方法——JavaScript会自动将字符串字面值转换为一个临时字符串对象,调用该方法,然后废弃掉那个临时的字符串对象。
在ES2015中,还提供了一种模板字符串(template literals),模板字符串提供了一些语法糖来帮你构造字符串。这与Perl、Python还有其他语言中的字符串插值(string interpolation)的特性非常相似。除此之外,你可以在通过模板字符串前添加一个tag来自定义模板字符串的解析过程,这可以用来防止注入攻击,或者用来建立基于字符串的高级数据抽象。
// Basic literal string creation
`In JavaScript '\n' is a line-feed.`
// Multiline strings
`In JavaScript this is
not legal.`
// String interpolation
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
// Construct an HTTP request prefix is used to interpret the replacements and construction
POST`http://foo.org/bar?a=${a}&b=${b}
Content-Type: application/json
X-Credentials: ${credentials}
{ "foo": ${foo},
"bar": ${bar}}`(myOnReadyStateChangeHandler);
除非有特别需要使用字符串对象,否则,你应当始终使用字符串字面值。
在字符串中使用的特殊字符
Symbol | meaning |
---|---|
\0 | Null字节 |
\b | 退格符 |
\f | 换页符 |
\n | 换行符 |
\r | 回车符 |
\t | Tab (制表符) |
\v | 垂直制表符 |
\’ | 单引号 |
\” | 双引号 |
\ | 反斜杠字符(\) |
\XXX | 由从0到377最多三位八进制数XXX表示的 Latin-1 字符。例如,\251是版权符号的八进制序列。 |
\xXX | 由从00和FF的两位十六进制数字XX表示的Latin-1字符。例如,\ xA9是版权符号的十六进制序列。 |
\uXXXX | 由四位十六进制数字XXXX表示的Unicode字符。例如,\ u00A9是版权符号的Unicode序列。见Unicode escape sequences (Unicode 转义字符). |
\u{XXXXX} | Unicode代码点 (code point) 转义字符。例如,\u{2F804} 相当于Unicode转义字符 \uD87E\uDC04的简写。 |
注: 严格模式下,不能使用八进制转义字符
转义字符
对于那些未出现在表2.1中的字符,其所带的前导反斜线’\’将被忽略。但是,这一用法已被废弃,应当避免使用。
通过在引号前加上反斜线’\’,可以在字符串中插入引号,这就是引号转义。例如:
var quote = "He read \"The Cremation of Sam McGee\" by R.W. Service.";
console.log(quote);
代码的运行结果为:
He read "The Cremation of Sam McGee" by R.W. Service.
要在字符串中插入’\’字面值,必须转义反斜线。例如,要把文件路径 c:\temp 赋值给一个字符串,可以采用如下方式:
var home = "c:\\temp";
也可以在换行之前加上反斜线以转义换行(译注:实际上就是一条语句拆成多行书写),这样反斜线和换行都不会出现在字符串的值中。
var str = "this string \
is broken \
across multiple\
lines."
console.log(str); // this string is broken across multiplelines.
Javascript没有“heredoc”语法,但可以用行末的换行符转义和转义的换行来近似实现
var poem =
"Roses are red,\n\
Violets are blue.\n\
Sugar is sweet,\n\
and so is foo."