📢 大家好,我是小丞同学,最近在刷红宝书,这是一篇学习笔记
📢 愿你我一起在这肆意生活里大放光彩
这是阅读《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循环块内部 使用varfor循环嵌套异步事件最常见的问题
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 类型
布尔类型,trueorfalse,一般用于条件的判断或者节流阀之类的
在 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():返回对象的字符串表示。