《JavaScript高级程序设计(第四版)》学习笔记第3章
Posted 小丞同学
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《JavaScript高级程序设计(第四版)》学习笔记第3章相关的知识,希望对你有一定的参考价值。
《javascript高级程序设计(第四版)》学习笔记(二)第3章
- 📢 大家好,我是小丞同学,最近在刷红宝书,这是一篇学习笔记
- 📢 愿你我一起在这肆意生活里大放光彩
- 这是阅读《JavaScript高级程序设计(第四版)》的第二天,本书已阅读 56/865
第三章:语言基础
3.1 语法
个人感觉 ECMAScript 的语法挺简单的,学过 C 之类都能很容易的上手
3.1.1 区分大小写
ECMAScript 中一切都区分大小写
例如:test
和Test
是两个不同的变量
注意:typeof
是关键字,不能做函数名,而Typeof
可以
3.1.2 标识符
- 第一个字符必须是一个字母,下划线
_
或一个美元符号$
- 其他字符可以是字母,
_
,$
,数字。 - 标识符需要用驼峰大小写格式。
关键字、保留字、true、false 和 null 不能作为标识符。
3.1.3 注释
单行注释采用//
多行注释采用/* */
3.1.4 严格模式
在严格模式下一些不安全的操作会抛出错误
开启严格模式的方法
全局开启在文件开头添加"use strict";
语句
单独一个函数开启,写在函数体上分
function doSomething() {
"use strict";
// 函数体
}
3.1.5 语句
这一点相对于我学过的 C 语言就特别的友好
单条语句末尾可以不添加分号
let sum = a + b
let sum = a + b; //均可
3.2 关键字与保留字
有特殊用途的关键字,比如if
、break
之类的
一些还未正式使用,但是在未来会使用的叫保留字,例如enum
关键字和保留字都不能作为标识符或属性名
3.3 变量
在 JS 中定义变量是很方便的,不需要考虑变量保存数据的类型,每个变量只不过是一
个用于保存任意值的命名占位符。
最开始采用 var
、在 ES6 后更多的采用let
、const
关键字,它们的不同在后面会写到
3.3.1 var 关键字
采用var
操作符定义变量
var message = 'hi';
message = 100
上面的代码合理
1. var 声明作用域
这部分内容很重要,虽然以后用var
的机会很少,但是在一些题中,这常常会是烦人的考点
在上面的代码中,相差之处在于message
变量是否通过var
被声明
原因在于,通过
var
定义的变量作为局部变量存在于函数当中,而右图中,未声明message
直接使用,会被创建成一个全局变量,因此能够打印出来
注意:当未声明的变量直接使用时,会被声明到全局
2. var 声明提升
对于 var
而已,最恶心的地方就是变量提升
例如下列代码
function foo() {
console.log(age);
var age = 26;
}
foo() // undefined
初学时,可能会很疑惑,为什么没报错呢,这就是变量提升的魅力
在函数执行的前一刻,会将所有的变量声明提到最前面
注意:仅仅是声明噢
上面的代码就可以转化成
function foo() {
var age;
console.log(age);
age = 26;
}
foo(); // undefined
因此输出undefined
还有很多有关 var 的问题记得后面闭包啥的部分应该有
3.3.2 let 关键字
let 声明的范围是块级作用域,而 var 声明的范围是函数作用域
可以简单理解为let
声明的变量只在最近的一对{}
内有效
if (true) {
let age = 26;
console.log(age); // 26
}
console.log(age); // ReferenceError: age 没有定义
//书上的例子
age
变量的生存区仅在于if
的括号内,因此外部无法访问
注意:
- 在一个块级作用域中,不允许一个变量被多次声明
- 在不同的块级作用域内,同一个变量名可以随意使用
1. 暂时性死区
与 var 的重要区别之一,在于 let 没有变量提升
console.log(age); // ReferenceError:age 没有定义
let age = 26;
在解析时,会发现后面有age
的声明,只不过在前面无法使用,在let
声明前的执行瞬间被称为“暂时性死区”,并抛出语法错误
2. 全局声明
特别注意
let
在全局作用域中声明的变量不会成为window·
中的对象
3. for循环中的 let 声明
for (let i = 0; i < 5; ++i) {
// 循环逻辑
}
console.log(i); // ReferenceError: i 没有定义
相对于 var
而言,使用let
后,迭代变量i
的作用域仅限于for
循环块内部
使用var
for循环嵌套异步事件最常见的问题
for (var i = 0; i < 5; ++i) {
setTimeout(() => console.log(i), 0)
}
// 你可能以为会输出 0、1、2、3、4
// 实际上会输出 5、5、5、5、5
原因:for 循环中的事件是异步事件,会在for
循环结束时才输出,而这时的变量i
已经是5
了
3.3.3 const 声明
const 用于定义不变的量
const age = 26;
age = 16; // TypeError
很显然报错了,因为age
变量是const
定义的
而对于引用数据类型又不同,const
声明的限制只适用于它指向的变量的引用。例如对象,我们可以改变它的值,以及不引起地址改变的操作
3.3.4 代码风格
不使用var
,多使用let
,不变的值使用const
大多数的值都是不变的,要多用用噢!
3.4 数据类型
ECMAScript 的数据类型很灵活,一种数据类型可以当作多种数据类型来使用
3.4.1 typeof 操作符
-
"undefined"表示值未定义;
-
"boolean"表示值为布尔值;
-
"string"表示值为字符串;
-
"number"表示值为数值;
-
"object"表示值为对象(而不是函数)或 null;
-
"function"表示值为函数;
-
"symbol"表示值为符号。
注意:typeof null
返回object
,因为 null
被认为是一个空对象
3.4.2 undefined 类型
当变量为初始化时,相当于给变量赋予了 undefined 值
let message;
console.log(message == undefined); // true
利用 typeof 来检测为声明的变量时,不会报错,会得到 undefined
3.4.3 Null 类型
Null 类型只有一个值 null,逻辑上,null值表示一个空指针对象
在定义将来要保存对象值的变量时,建议使用 null 来初始化,不要使用其他值
关于 null
和 undefined
,undefined
值是由 null
值派生而来的。因此
null
等于undefined
但是不全等于(===)undefined
3.4.4 Boolean 类型
布尔类型,true
orfalse
,一般用于条件的判断或者节流阀之类的
在 Boolean 类型来说,类型转换是非常重要的
3.4.5 Number 类型
表示整数和浮点数值。
关于八进制,第一个数值是0
,如果数字的值超出一定范围,则会忽略前缀0
let oNum1= 070 //有效 70八进制,十进制56
let oNum2 = 079 // 无效 79
1. 浮点值
浮点数值:该数值中必须包含一个小数点,并且小数点后面必须至少有一位数字
let floatnum1 = 1.1;
let floatnum2 = 1.; //小数点后面没有数字——解析为1
let floatnum3 = .1 ;//解析为0.1,不推荐这种写法
let floatnum4 = 10.0;//整数——解析为10
tips:浮点值的精确度最高是17位,但是由于计算机组成原理,0.1 + 0.2
的结果不会是0.3
,因此不要比较某个特定的值
2. 值的范围
在多数浏览器中,最小数值是 5e-324
,最大数值是 1.797 693 134 862 315 7e+308
,当超出这个范围时,会转化为infinity
或者-inifinity
3. NaN
意思是“不是数值”(Not a Number),NaN 不是报错!!
用 0 除以任何数都会返回 NaN。分子是非 0 ,分母是 0 ,则会是 infinity
注意:任何涉及 NaN 的操作都会返回 NaN,例如(NaN / 10)
但是离谱的是, NaN 不等于包括 NaN 在内的任何值
console.log(NaN == NaN); // false
isNaN()
:确定一个值是否为NaN;
当isNaN()
接收一个值后,第一步会将这个值转换为数值,任何不能被转换为数值的值都会返回true
console.log(isNaN("10")); // false,可以转换为数值 10
console.log(isNaN("blue")); // true,不可以转换为数值
4. 数值转化
有 3 个函数可以将非数值转换为数值:
Number()
;parseInt()
;parseFloat()
Number()
是转型函数,可用于任何数据类型。
- undefined 转为 NaN
- null 转为 0
- 对于字符串的转换比较复杂
- 有数值就是数值本身,八进制,十六进制注意转为十进制
- 空字符串("")转为 0
- 对象先调用
valueOf()
方法,如果为NaN再调用toString
转换
parseInt()
函数更专注于字符串是否包含数值模式
非常重要 如果第一个字符是数值字符、加号或减号,则继续依次检测每个字符,直到字符串末尾,或碰到非数值字符
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,解释为十六进制整数
这个函数特殊的一点在于可以接收2个参数,第二个参数表示第一个参数是多少进制
let num1 = parseInt("AF", 16); // 175
let num2 = parseInt("AF"); // NaN
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
记得之前看过一到面试题
请问parseInt()
,parseFloat()
,Number()
的区别?(其实不是这道的,但是找不到了)
答:
parseInt()
字符串转换成整型,parseFloat()
字符串转换成浮点型,Number()
字符串转换成数字型Number()
看的是整体,只要字符串内的内容不是合法的数字,则结果为NaN
;否则,就会正常转换为数字类型。parseInt()
和parseFloat()
的转换规则比较接近如果第一个字符是非数字,那么,结果为NaN
,如果第一个字符是数字:parseInt()
:如果遇到小数点或者其它非数字字符或结尾,那么就把前面的内容正常转换为数字parseFloat()
:如果遇到第二个小数点或者其它非数字字符或结尾,那么就把前面的内容正常转换为数字
3.4.6 String 类型
三种表示方法,双引号,单引号以及反引号,但是不能混用
1. 字符字面量
用来打印一些特殊字符
太简单,记一记
2. 字符串的特点
从我的理解来看,修改字符串实际上是一个重构的过程,首先给原值和需要连接的值分配足够的空间,然后填充。再销毁原值
3. 转化为字符串
第一种方法也是最常用最通用的方法toString
多数情况下,toString()不接收任何参数,当操作的值为数值时,传入的参数表示转化为的数值对应的进制
let num = 10;
console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
对于String
方法我的理解是,对于toString
方法的补充,当不确定是否为 null 或 undefined 时,可以采用String
方法,
如果值为为null 则返回null
,为undefined
返回undefined
,如果该值可以使用toString
方法则返回值相同
4. 模板字面量
ES6中非常好用的一个玩意,可以替代创建元素的复杂操作,直接通过模板字面量来创建
let pagehtml = `
<div>
<a href="#">
<span>Jake</span>
</a>
</div>`;
直接将上述文本插入 html 即可
5. 字符串插值
普通字符串插值
let interpolatedString =
value + ' to the ' + exponent + ' power is ' + (value * value);
模板字面量插值
let interpolatedTemplateLiteral =
`${ value } to the ${ exponent } power is ${ value * value }`;
通过${}
来插值
所有插入的值都会使用
toString()
强制转型为字符串
6. 模板字面量标签函数
这个是第一次见,通过下面的例子来理解吧
<script>
let name = "ljc";
let age = 19;
// 标签函数strings(第一个参数)为以${}分割的数组,后面的参数对应${}的值
function myTag(strings, name, age) {
console.log(strings);
//["", "my name is ,age is ", ""]
console.log(name);
//ljc,对应表达式${name}的结果
console.log(age);
//19
return "successful";
}
const res = myTag `${name}my name is ,age is ${age}`
console.log(res);
</script>
首先函数的调用在第14行,strings接收以${}
分隔的成的数组,例如${a}asdfa${b}s
,可以分隔为数组["", 'asdfa', "", s]
7. 原始字符串
可以使用默认的 String.raw
标签函数:
// Unicode 示例
// \\u00A9 是版权符号
console.log(`\\u00A9`); // ©
console.log(String.raw`\\u00A9`); // \\u00A9
好奇怪,但是不知道哪里奇怪
3.4.7 Symbol 类型
ES6 新增的数据类型。表示唯一的值
1. 符号的基本用法
通过Symbol
函数初始化
let sym = Symbol();
console.log(typeof sym); // symbol
调用 Symbol 函数时,可以传入对符号的描述,但是这个不会影响字符串本身
这种定义方法是唯一的方法
2. 使用全局符号注册表
(卑微跳过)等二刷 ES6 的时候再重新写
3.4.8 Object 类型
在 ECMAScript 中,Object 类型是所有它的实例的基础,即 Object 类型所具有的任何属性和方法都是存在更具体的对象中。
constructor
:保存着用于创建当前对象的函数。hasOwnProperty
:用于检查给定的属性在当前对象实例中是否存在。参数的属性名必须以字符串形式指定。isPrototypeOf
:用于检查传入的对象是否是当前对象的原型。propertyIsEnumerable
:用于检查给定的属性是否能够使用for-in语句累枚举。参数的属性名必须以字符串形式指定。toLocaleString()
:返回对象的字符串,该字符串与执行环境的地区对应。toString()
:返回对象的字符串表示。valueOf()
:返回对象的string、number、boolean表示。通常与toString()
方法的返回值相同。
以上是关于《JavaScript高级程序设计(第四版)》学习笔记第3章的主要内容,如果未能解决你的问题,请参考以下文章
《JavaScript高级程序设计(第四版)》学习笔记第4章
《JavaScript高级程序设计(第四版)》学习笔记第4章
《JavaScript高级程序设计(第四版)》学习笔记第5章
《JavaScript高级程序设计(第四版)》学习笔记第5章