JavaScript高级程序设计读书笔记--语言基础
文章目录
- 1.语法
- 1.1 标识符
- 1.2 语句
- 2.关键字与保留字
- 3.变量
- 3.1 var 关键字
- 1. var 声明作用域
- 2. var 声明提升
- 3.2 let 声明
- 1.暂时性死区
- 2. 全局声明
- 3. 条件声明
- 4. for 循环中的 let 声明
- 3.3 const 声明
- 1. const 声明修改变量
- 2. 迭代变量
- 3.4 声明风格及最佳实践
- 4. 数据类型
- 4.1 typeof 操作符
- 4.2 Undefined 类型
- 4.3 Null 类型
- 4.4 Boolean 类型
- 4.5 Number 类型
- 1. 浮点值
- 2. 值的范围
- 3. NaN
- 4. 数值转换
- (1)Number()
- (2)parseInt()
- (3)parseFloat()
- 4.6 String 类型
- 1. 字符串的特点
- 2. 转换为字符串
- 3. 模板字面量(ECMAScript 6 新增)
- 4. 字符串插值
- 4.7 Symbol 类型
- 4.8 Object 类型
1.语法
1.1 标识符
标识符,就是变量、函数、属性或函数参数的名称。标识符按照ECMAScript惯例,采用驼峰命名法,由一或多个下列字符组成:
- 第一个字符必须是一个字母、下划线(_)或美元符号($);
- 剩下的其他字符可以是字母、下划线、美元符号或数字。
1.2 语句
ECMAScript 中的语句以分号结尾。省略分号就意味着由解析器确定语句在哪结尾。加分号有助于防止因为省略造成的问题,也便于开发者通过删除空行来压缩代码(如果没有结尾的分号,只删除空行,则会导致语法错误),同时加分号也有助于在某些情况下提升性能。
2.关键字与保留字
关键字不能用作标识符或属性名。
3.变量
ECMAScript 变量是松散类型的,意思是变量可以用于保存任何类型的数据。每个变量都是一个用于保存任意值的命名占位符。有 3 个关键字可以声明变量:var、const 和 let。其中const 和 let 只支持 ECMAScript 6。
3.1 var 关键字
var message = "hi";
这行代码定义了一个名为 message 的变量,并为其赋值。这里,message 被定义为一个保存字符串值 hi 的变量。
1. var 声明作用域
var声明作用于全局或函数内,声明在函数内的作用于该函数内,声明于函数外的作用于全局。使用 var 操作符定义的变量会成为包含它的函数的局部变量。比如,使用 var在一个函数内部定义一个变量,就意味着该变量将在函数退出时被销毁:
function test() { var message = "hi"; // 局部变量
}
test();
console.log(message); // 出错!
在函数内定义变量时省略 var 操作符,可以创建一个全局变量,但不推荐这么做。在局部作用域中定义的全局变量很难维护:
function test() { message = "hi"; // 全局变量
}
test();
console.log(message); // "hi"
如果需要定义多个变量,可以在一条语句中用逗号分隔每个变量。
var message = "hi", found = false, age = 29;
2. var 声明提升
使用var关键字声明的变量会自动提升到函数作用域顶部:
function foo() { console.log(age); var age = 26;
}
foo(); // undefined
以上代码等价于:
function foo() { var age; console.log(age); age = 26;
}
foo(); // undefined
3.2 let 声明
let 声明的范围是块作用域,而 var 声明的范围是函数作用域(函数作用域是指在在函数内部声明的只能在这个函数内部访问的变量,块作用域是函数作用域的子集)。let 不允许同一个块作用域中出现冗余声明。这样会导致报错:
let age;
let age; // SyntaxError;标识符 age 已经声明过了
1.暂时性死区
由于 let 声明的变量不会在作用域中被提升,即:let(const)声明的变量不能在声明位置前使用。在"预处理"时,所有的声明被“注册”,var声明的变量会分配一个初始值(undefined),而let不会,只有执行到声明语句时,let声明的变量才会被初始化,而未初始化的变量不能使用。从let变量作用域顶部到声明位置被称作“暂存死区”。
2. 全局声明
使用 let 在全局作用域中声明的变量不会成为 window 对象的属性(var 声明的变量则会)。
var name = 'Matt';
console.log(window.name); // 'Matt'
let age = 26;
console.log(window.age); // undefined
需要注意的是:let 声明是在全局作用域中发生的,所以仍要确保页面不会重复声明同一个变量。
3. 条件声明
在使用 var 声明变量时,由于声明会被提升,JavaScript 引擎会自动将多余的声明在作用域顶部合并为一个声明。因为 let 的作用域是块,所以不可能检查前面是否已经使用 let 声明过同名变量,同时也就不可能在没有声明的情况下声明它。如下:
<script> var name = 'Nicholas'; let age = 26;
</script>
<script> // 假设脚本不确定页面中是否已经声明了同名变量// 那它可以假设还没有声明过var name = 'Matt'; // 这里没问题,因为可以被作为一个提升声明来处理// 不需要检查之前是否声明过同名变量let age = 36; // 如果 age 之前声明过,这里会报错
</script>
4. for 循环中的 let 声明
在 let 出现之前,for 循环定义的迭代变量会渗透到循环体外部:
for (var i = 0; i < 5; ++i) { // 循环逻辑
}
console.log(i); // 5
改成使用 let 之后,这个问题就消失了,因为迭代变量的作用域仅限于 for 循环块内部:
for (let i = 0; i < 5; ++i) { // 循环逻辑
}
console.log(i); // ReferenceError: i 没有定义
3.3 const 声明
const 的行为与 let 基本相同,唯一一个重要的区别是用它声明变量时必须同时初始化变量,且尝试修改 const 声明的变量会导致运行时错误。const 也不允许重复声明,const 声明的作用域也是块。
1. const 声明修改变量
const 声明的限制只适用于它指向的变量的引用。换句话说,如果 const 变量引用的是一个对象,那么修改这个对象内部的属性是完全OK的。
const person = {};
person.name = 'Matt'; // ok
2. 迭代变量
不可以通过const来声明迭代变量,因为迭代变量会自增,如下:
for (const i = 0; i < 10; ++i) {} // Uncaught TypeError: Assignment to constant variable.(给常量赋值)
但是可以使用用 const 声明一个不会被修改的 for 循环变量,即每
次迭代只是创建一个新变量:
查看控制台输出:
3.4 声明风格及最佳实践
不使用 var,const 优先,let 次之
4. 数据类型
ECMAScript 有 6 种简单数据类型(也称为原始类型):Undefined、Null、Boolean、Number、String 和 Symbol(ECMAScript 6 新增),和一种复杂数据类型: Object(对象)。Object 是一种无序名值对的集合。
4.1 typeof 操作符
typeof操作符可以用来确定任意变量的数据类型。对一个值使用 typeof 操作符会返回下列字符串之一:
- "undefined"表示值未定义;
- "boolean"表示值为布尔值;
- "string"表示值为字符串;
- "number"表示值为数值;
- "object"表示值为对象(而不是函数)或 null;
- "function"表示值为函数;
- "symbol"表示值为符号。
下面是使用 typeof 操作符的例子:
let message = "some string";
console.log(typeof message); // "string"
console.log(typeof(message)); // "string"
console.log(typeof 95); // "number"
4.2 Undefined 类型
Undefined 类型只有一个值,就是特殊值 undefined。当使用 var 或 let 声明了变量但没有初始化时,就相当于给变量赋予了 undefined 值:
let message;
console.log(message == undefined); // true
4.3 Null 类型
Null 类型同样只有一个值,即特殊值 null。逻辑上讲,null 值表示一个空对象指针,这也是给typeof 传一个 null 会返回"object"的原因:
let car = null;
console.log(typeof car); // "object"
在定义将来要保存对象值的变量时,建议使用 null 来初始化,不要使用其他值。
4.4 Boolean 类型
Boolean(布尔值)类型是 ECMAScript 中使用最频繁的类型之一,有两个字面值:true 和 false。
这两个布尔值不同于数值,因此 true 不等于 1,false 不等于 0。下面是给变量赋布尔值的例子:
let found = true;
let lost = false;
注意,布尔值字面量 true 和 false 是区分大小写的,因此 True 和 False(及其他大小混写形式)是有效的标识符,但不是布尔值。虽然布尔值只有两个,但所有其他 ECMAScript 类型的值都有相应布尔值的等价形式。要将一个其他类型的值转换为布尔值,可以调用特定的 Boolean()转型函数:
let message = "Hello world!";
let messageAsBoolean = Boolean(message);
像 if 等流控制语句会自动执行其他类型值到布尔值的转换,如下:
let message = "Hello world!";
if (message) { console.log("Value is true");
}
在这个例子中,console.log 会输出字符串"Value is true",因为字符串 message 会被自动转换为等价的布尔值 true。下表总结了不同类型与布尔值之间的转换规则:
4.5 Number 类型
Number 类型使用 IEEE 754 格式表示整数和浮点值(在某些语言中也叫双精度值)。不同的数值类型相应地也有不同的数值字面量格式。
1. 浮点值
要定义浮点值,数值中必须包含小数点,而且小数点后面必须至少有一个数字。虽然小数点前面不是必须有整数,但推荐加上。下面是几个例子:
let floatNum1 = 1.1;
let floatNum3 = .1; // 有效,但不推荐
因为存储浮点值使用的内存空间是存储整数值的两倍,所以 ECMAScript 总是想方设法把值转换为整数。在小数点后面没有数字的情况下,数值就会变成整数。如下例所示:
let floatNum1 = 1.; // 小数点后面没有数字,当成整数 1 处理
let floatNum2 = 10.0; // 小数点后面是零,当成整数 10 处理
对于非常大或非常小的数值,浮点值可以用科学记数法来表示。ECMAScript 中科学记数法的格式要求是一个数值(整数或浮点数)后跟一个大写或小写的字母 e,再加上一个要乘的 10 的多少次幂。默认情况下,ECMAScript 会将小数点后至少包含 6 个零的浮点值转换为科学记数法。比如:
let floatNum1 = 3.125e7; // 等于 31250000
let floatNum2 = 3e-7; // 等于 0.000 000 3
浮点值的精确度最高可达 17 位小数,但在算术计算中远不如整数精确。例如,0.1 加 0.2 得到的不是 0.3,而是 0.300 000 000 000 000 04。由于这种微小的舍入错误,导致很难测试特定的浮点值。比如下面的例子:
if (a + b == 0.3) { // 别这么干! console.log("You got 0.3.");
}
2. 值的范围
ECMAScript 可以表示的最小数值保存在 Number.MIN_VALUE 中,这个值在多数浏览器中是 5e-324;可以表示的最大数值保存在Number.MAX_VALUE 中,这个值在多数浏览器中是 1.797 693 134 862 315 7e+308。如果某个计算得到的数值结果超出了 JavaScript 可以表示的范围,那么这个数值会被自动转换为一个特殊的 Infinity(无穷)值。要确定一个值是不是有限大(即介于 JavaScript 能表示的最小值和最大值之间),可以使用 isFinite()函数,如下所示:
let result = Number.MAX_VALUE + Number.MAX_VALUE;
console.log(isFinite(result)); // false
3. NaN
NaN,意思是“不是数值”(Not a Number),用于表示本来要返回数值的操作失败了(而不是抛出错误)。在ECMAScript 中,0、+0 或-0 相除会返回 NaN:
console.log(0/0); // NaN
console.log(-0/+0); // NaN
如果分子是非 0 值,分母是有符号 0 或无符号 0,则会返回 Infinity 或-Infinity:
console.log(5/0); // Infinity
console.log(5/-0); // -Infinity
首先,任何涉及 NaN 的操作始终返回 NaN(如 NaN/10),在连续多步计算时这可能是个问题。其次,NaN 不等于包括 NaN 在内的任何值。例如,下面的比较操作会返回 false:
console.log(NaN == NaN); // false
为此,ECMAScript 提供了isNaN()函数。该函数接收一个参数,可以是任意数据类型,然后判断
这个参数是否“不是数值”。把一个值传给 isNaN()后,该函数会尝试把它转换为数值。某些非数值的
值可以直接转换成数值,如字符串"10"或布尔值。任何不能转换为数值的值都会导致这个函数返回
true。举例如下:
console.log(isNaN(NaN)); // true
console.log(isNaN(10)); // false,10 是数值
console.log(isNaN("10")); // false,可以转换为数值 10
console.log(isNaN("blue")); // true,不可以转换为数值
console.log(isNaN(true)); // false,可以转换为数值 1
4. 数值转换
三 个函数可以将非数值转换为数值:Number()、parseInt()和 parseFloat()。Number()是转型函数,可用于任何数据类型。后两个函数主要用于将字符串转换为数值。对于同样的参数,这 3 个函数执行的操作也不同。
(1)Number()
Number()函数基于如下规则执行转换。
- 布尔值,true 转换为 1,false 转换为 0。
- 数值,直接返回。
- null,返回 0。
- undefined,返回 NaN。
- 字符串,应用以下规则:
1.如果字符串包含数值字符,包括数值字符前面带加、减号的情况,则转换为一个十进制数值。
因此,Number(“1”)返回 1,Number(“123”)返回 123,Number(“011”)返回 11(忽略前面的零)。
2. 如果字符串包含有效的浮点值格式如"1.1",则会转换为相应的浮点值(同样,忽略前面的零)。
3. 如果字符串包含有效的十六进制格式如"0xf",则会转换为与该十六进制值对应的十进制整数值。
4.如果是空字符串(不包含字符),则返回 0。
5.如果字符串包含除上述情况之外的其他字符,则返回 NaN。
- 对象,调用 valueOf()方法,并按照上述规则转换返回的值。如果转换结果是 NaN,则调用
toString()方法,再按照转换字符串的规则转换。下面是几个具体的例子:
let num1 = Number("Hello world!"); // NaN
let num2 = Number(""); // 0
let num3 = Number("000011"); // 11
let num4 = Number(true); // 1
(2)parseInt()
在需要得到整数时可以优先使用 parseInt()函数。parseInt()函数更专注于字符串是否包含数值模式。在使用parseInt()对字符串进行转换时,字符串最前面的空格会被忽略,从第一个非空格字符开始转换。如果第一个字符不是数值字符、加号或减号,parseInt()立即返回 NaN。空字符串也会返回 NaN(这一点跟 Number()不一样,它返回 0)。如果第一个字符是数值字符、加号或减号,则继续依次检测每个字符,直到字符串末尾,或碰到非数值字符。比如,"1234blue"会被转换为 1234,因为"blue"会被完全忽略。类似地,"22.5"会被转换为 22,因为小数点不是有效的整数字符。假设字符串中的第一个字符是数值字符,parseInt()函数也能识别不同的整数格式(十进制、八进制、十六进制)。换句话说,如果字符串以"0x"开头,就会被解释为十六进制整数。如果字符串以"0"开头,且紧跟着数值字符,在非严格模式下会被某些实现解释为八进制整数。
下面几个转换示例有助于理解上述规则:
let num1 = parseInt("1234blue"); // 1234
let num2 = parseInt(""); // NaN
let num3 = parseInt("0xA"); // 10,解释为十六进制整数
let num4 = parseInt(22.5); // 22
let num5 = parseInt("70"); // 70,解释为十进制值
let num6 = parseInt("0xf"); // 15,解释为十六进制整数
不同的数值格式很容易混淆,因此 parseInt()也接收第二个参数,用于指定底数(进制数)。如
果知道要解析的值是十六进制,那么可以传入 16 作为第二个参数,以便正确解析:
let num = parseInt("0xAF", 16); // 175
//同上
let num1 = parseInt("AF", 16); // 175
因为不传底数参数相当于让 parseInt()自己决定如何解析,所以为避免解析出错,建议始终传给
它第二个参数。
(3)parseFloat()
parseFloat()函数从位置 0 开始检测每个字符。解析到字符串末尾或者解析到一个无效的浮点数值字符为止。第一次出现的小数点是有效的,但第二次出现的小数点无效,此时字符串的剩余字符都会被忽略。因此,"22.34.5"将转换成 22.34。parseFloat()始终忽略字符串开头的零,且只解析十进制值,因此不能指定底数。最后,如果字符串表示整数(没有小数点或者小
数点后面只有一个零),则 parseFloat()返回整数。下面是几个示例:
let num1 = parseFloat("1234blue"); // 1234,按整数解析
let num2 = parseFloat("0xA"); // 0
let num3 = parseFloat("22.5"); // 22.5
let num4 = parseFloat("22.34.5"); // 22.34
let num5 = parseFloat("0908.5"); // 908.5
let num6 = parseFloat("3.125e7"); // 31250000
4.6 String 类型
String(字符串)数据类型表示零或多个 16 位 Unicode 字符序列。字符串可以使用双引号(")、单引号(')或反引号(`)标示。
1. 字符串的特点
ECMAScript 中的字符串是不可变的(immutable),意思是一旦创建,它们的值就不能变了。要修改某个变量中的字符串值,必须先销毁原始的字符串,然后将包含新值的另一个字符串保存到该变量,如下所示:
let lang = "Java";
lang = lang + "Script";
这里,变量 lang 一开始包含字符串"Java"。紧接着,lang 被重新定义为包含"Java"和"Script"的组合,也就是"JavaScript"。整个过程首先会分配一个足够容纳 10 个字符的空间,然后填充上"Java"和"Script"。最后销毁原始的字符串"Java"和字符串"Script",因为这两个字符串都没有用了。
2. 转换为字符串
有两种方式把一个值转换为字符串。
(1)toString()方法:这个方法返回当前值的字符串等价物。比如:
let age = 11;
let ageAsString = age.toString(); // 字符串"11"
toString()方法可用于数值、布尔值、对象和字符串值。null 和 undefined 值没有 toString()方法。该方法可以通过传入底数参数(和parseInt相似)来决定转换为几进制的数值。
(2)string()方法
当不确定一个值是否为 null 或 undefined,则使用String()转型函数。String()函数遵循如下规则。
如果值有 toString()方法,则调用该方法(不传参数)并返回结果。
如果值是 null,返回"null"。
如果值是 undefined,返回"undefined"。
下面看几个例子:
let value1 = 10;
let value2 = true;
let value3 = null;
let value4;
console.log(String(value1)); // "10"
console.log(String(value2)); // "true"
console.log(String(value3)); // "null"
console.log(String(value4)); // "undefined"
3. 模板字面量(ECMAScript 6 新增)
模板字面量不是字符串,而是一种特殊的 JavaScript 句法表达式,只不过求值后得到的是字符串。与使用单引号或双引号不同,模板字面量保留换行字符,可以跨行定义字符串:
let myMultiLineString = 'first line\nsecond line';
let myMultiLineTemplateLiteral = `first line
second line`;
console.log(myMultiLineString);
console.log(myMultiLineTemplateLiteral);
console.log(myMultiLineString === myMultiLinetemplateLiteral); // true
二者输出结果一致,均为:
// first line
// second line
// first line
// second line
更多示例:
// 这个模板字面量以一个换行符开头
let secondTemplateLiteral = `
first line
second line`;
console.log(secondTemplateLiteral[0] === '\n'); // true
4. 字符串插值
字符串插值通过在 $ { } 中使用一个 JavaScript 表达式实现:
let value = 5;
let exponent = 'second';
// 以前,字符串插值是这样实现的:
let interpolatedString = value + ' to the ' + exponent + ' power is ' + (value * value);
// 现在,可以用模板字面量这样实现:
let interpolatedTemplateLiteral = `${ value } to the ${ exponent } power is ${ value * value }`;
console.log(interpolatedString); // 5 to the second power is 25
console.log(interpolatedTemplateLiteral); // 5 to the second power is 25
所有插入的值都会使用 toString()强制转型为字符串,而且任何 JavaScript 表达式都可以用于插值。
4.7 Symbol 类型
Symbol(符号)是 ECMAScript 6 新增的数据类型。符号是原始值,且符号实例是唯一、不可变的。
符号的用途是确保对象属性使用唯一标识符,不会发生属性冲突的危险。
4.8 Object 类型
ECMAScript 中的对象其实就是一组数据和功能的集合。对象通过 new 操作符后跟对象类型的名称
来创建。开发者可以通过创建 Object 类型的实例来创建自己的对象,然后再给对象添加属性和方法:
let o = new Object();
JavaScript高级程序设计读书笔记--语言基础相关推荐
- JavaScript高级程序设计读书笔记(一)
第一章 总结: JavaScript是一种专为与网页交互设计的脚本语言. 由三个不同的部分组成: ECMAScript, 由ECMA-262定义,提供核心语言功能: DOM(文件对象模型),提供访问和 ...
- JavaScript高级程序设计-读书笔记(6)
第20章 JSON JSON是一个轻量级的数据格式,可以简化表示复杂数据结构的工作量 JSON的语法可以表示一下三种类型的值 l 简单值:使用与JavaScript相同的语法,可以在JS ...
- javascript高级程序设计读书笔记2
<!DOCTYPE HTML>//这个网页的文档类型,这个是html5的写法 Bootstrap使用的某些HTML元素和CSS属性需要文档类型为HTML5 doctype.因此这一文档类型 ...
- Javascript高级程序设计--读书笔记--第八章BOM
BOM(browser object model 浏览器对象模型) BOM的核心对象是window,它表示浏览器的一个实例.在浏览器钟,window对象有双重角色,它既是通过javascript 访问 ...
- javascript高级程序设计读书笔记----引用类型
Array类型. ECMAScript数组的每一项可以保存任何类型的数据. 数组大小是可以动态调整的. 创建数组第一种基本方式方式: 使用Array构造函数 var colors = new Arra ...
- JavaScript高级程序设计读书笔记(第5章引用类型之Array类型)
为什么80%的码农都做不了架构师?>>> 1.数组长度 //lenth会自动更新 var arr=["black","red","g ...
- JavaScript高级程序设计读书笔记(第8章BOM之location对象查询字符串参数)
为什么80%的码农都做不了架构师?>>> location对象查询字符串参数 //location.search返回从问号到URL末尾的所有内容function getQuerySt ...
- JavaScript高级程序设计读书笔记(第6章面向对象的程序设计之创建对象)
2019独角兽企业重金招聘Python工程师标准>>> 面向对象语言都有"类"的概念,而通过类可以创建任意多个具有相同属性和方法的对象. JS中没有"类 ...
- javascript高级程序设计读书笔记1
浮点数虽然精度很高,但在实际计算中的精度可能不如整数.比如0.1+0.2并不等于0.3,而是0.3000000000000004,所以把浮点数的计算结果当做判断条件会产生失误,这是基于IEEE754数 ...
- JavaScript高级程序设计学习笔记(三)
分享一下第五章(引用类型)的笔记,内容比较多,我拆成了两部分,今天这部分是关于Object.Array.Date和RegExp类型的. 以下的笔记是书上一些我以前学习的时候,没有太重视的js基础知识, ...
最新文章
- Java对象XML序列化框架-Simple2.0
- 互联网的双刃剑效应与视频监控的信息安全
- STM32 基础系列教程 28 - USB_DFU
- PMCAFF微课堂|猎豹清理大师亿万用户量产品背后的紫牛方法论,傅盛不会说的秘密...
- C语言程序设计 函数递归调用示例
- 解决三星手机EditText背景色的问题
- 初步的 MPI消息传递函数
- TortoiseSVN的安装和使用
- SSIS工具的ETL过程,全量ETL和增量ETL过程教程
- C# 数组拷贝 byte数组拷贝,char数组拷贝
- javascript 代码段整理
- 软件需求分析用例图 实例简述
- GPU架构演进十年,从费米到安培
- Netty实现群聊系统
- 大学追忆录(天空晴朗的梦)
- 微积分基础之图形面积(体积)计算
- Linux Kubuntu 良心输入法
- 服务器系统https打不开网页,记录一次解决网站突然无法打开处理HTTP被封的问题...
- chrome浏览器怎么把整个网页截图保存
- java tld文件配置_Java Web应用因tld文件损坏出现的错误