开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,点击查看活动详情
《JavaScript高级程序设计》 第三章语言基础,阅读的一些笔记摘录
语法
区分大小写
JS 中一切都是区分的大小写的,无论是函数名、变量、操作符等都是区分大小写的。
换句说就是 test和Test是两个变量
标识符
所谓标识符就是变量、函数、属性和函数参数名称,标识符可以由一个或者多个下列字符号组成
- 第一个字符必须是字母 、下划线 或者 $ 符号
- 剩下的字符可以是 字母、下划线、$ 或者数字
- 书写方式以驼峰形式书写,即第一个单词的首字母小写,后面的每一个单词的首字母大写
// 合法
var nameFirst = '' // 驼峰形式
var _nameFirst1 = ''
var $nameFirst2 = ''
// 不合法
var 123bane = ''
注释
- 单行注释
- 多行注释
// 单行注释
/*
多行注释
多行注释
*/
严格模式
关键字和保留字
- 关键字和保留字在 JS 中是有特殊用途的,比如:判断语句用到
if,循环语句forwhile等
| abstract | else | instanceof | super |
|---|---|---|---|
| boolean | enum | int | switch |
| break | export | interface | synchronized |
| byte | extends | let | this |
| case | false | long | throw |
| catch | final | native | throws |
| char | finally | new | transient |
| class | float | null | true |
| const | for | package | try |
| continue | function | private | typeof |
| debugger | goto | protected | var |
| default | if | public | void |
| delete | implements | return | volatile |
| do | import | short | while |
| double | in | static | with |
变量
var
用 var 来声明变量,var 是一个关键字,后面跟上变量名称,例如:var message。var 声明有以下特点
- var 声明范围是函数作用域
- 在全局作用域下声明变量,变量会成为全局对象
window的属性 - var 声明的变量会被提升到函数作用域的顶部
- var 可以重复定义同一个变量
- 定义的变量可以重复的赋值
- 声明的变量未赋值,会默认赋值
undefined
// 当前全局作用域 window
var name = '张三'
console.log(window.name) // '张三'
function fn(){
console.log(age); // undefined
var age = 10
var age = 11
age = 12
age = 15
console.log(age) // 15
}
fn()
// 变量提升的转换
function fn(){
var age;
console.log(age);
age = 10
age = 11
age = 12
age = 15
console.log(age)
}
let
let 是 ES6 中新增的声明变量关键字,有以下特点
- let 声明范围是块级作用域
- 块级作用域是函数作用的子集,所以对 var 声明变量的限制同样也适用于 let
- 全局作用域下声明变量,变量不会成为全局对象
window的属性 - 不能重复声明同一个变量
- 定义的变量可以重复赋值
- 声明变量未赋值,会默认赋值
undefined - 声明变量不会提升
- 暂时性死区,变量声明之前是无法使用的,使用会抛出错误,只能在声明变量语句后使用变量
const
const 和 let 一样都是 ES6 中新增的声明变量关键字,有以下特点
数据类型
Undefined
Undefined 类型只有一个值,就是特殊值 undefined。
- 当声明一个变量但未对变量初始化的时候,变量会被默认赋值
undefined。 typeof一个未声明的变量也是返回 undefined , 所以建议声明变量的时候初始化变量,这样就能知道检测出 undefined 是一个未声明变量,而不是一个声明了但未初始化的变量。- 是一个假值
- 是由
null派生出来的值, null == undefined 值是相等的
Null
Null 类型同样只有一个值,即特殊值 null。
- 表示空对象指针
- 一个假值
- 用途与 undefined 不一样,变量要保存对象,但是当时又没有那个对象保存,就会赋值
null - typeof null === 'object',检测返回是一个对象。(不同的对象在 JS 底层都表示为二进制,JS 二进制的前三位是表示类型的,object 类型的前三位是000,null 的底层二级制表示都是000,所以会被认为是对象)
Boolean
Boolean类型有两个布尔值 true 和 false。布尔值字面量 true 和 false 是区分大小写的,因此 True 和 False(及其他大小混写形式) 是有效的标识符,但不是布尔值。将其他类型的数据转换成布尔值,可以调用 Boolean() 函数。
转换成布尔值
| 数据类型 | 转换为 true 的值 | 转换为 false 的值 |
|---|---|---|
| Boolean | true | false |
| String | 非空字符串 | 空字符串 |
| Number | 非零数值(包括无穷) | 0、NaN |
| Object | 任意对象 | null |
| Undefined | (无,不存在) | undefined |
Number
Number 类型是使用 IEEE 754 格式的整数和浮动数(双精度型)。通过 64 位表示数字。
图片说明:
- 第0位:表示符号,0 表示正,1 表示负 (s)
- 第1位到11位:表示存储指数部分 (e)
- 第12位到63位:表示存储小数部分 (m)
- 整数
- 十进制,基本数值字面量格式
- 八进制,以
0o开头,然后是八进制数 ( 0 ~ 7) - 十六进制, 以
0x开头的 (区分大小写),然后是十六进制数字(09 以 及 AF)。十六进制数字中的字母大小写均可。
- 浮点数
- 带小数点的数字
- 存储是整数的两倍,JS 会尽可能的将浮点数转换成整数处理,比如:1.0 会当做 1 处理
- 科学记数法,3.125e7 相当于 31250000, 0.0000000003 相当于 3e-8
- 值得范围
- Number.MIN_VALUE
- Number.MAX_VALUE
- Infinity
- -Infinity
- isFinite() // 检测是否是无穷值
- NaN
- 不是一个数值,表示在返回一个数值的时候失败了
- NaN 等于任何数 ,包括自己 NaN === NaN // false
- isNaN, Number.isNaN 检测 NaN,isNaN 有个bug,比如:isNaN('abc') 返回得true,'abc'是一个字符串不是NaN,isNaN只是判断传入得值是不是一个数值,所以要重新改造下;
function isNaNMethod (val){
return typeof val === 'number' && isNaN(val)
}
转换为数值
- Number() 函数,将任何数据类型转换成数值
- 布尔值,true 转换为1, false 转换为 0
- 数值直接返回
- null 返回 0
- undefined 返回 NaN
- 字符串
- 包含数值字符,字符前面带加号、减号,转换为一个十进制数值,忽略前置 0 ,例如:Number('011') =>11
- 包含有效的浮点数格式,返回相应的浮点数值,忽略前置 0
- 包含有效的十六进制字符串格式,将十六进制字符串转换为十进制整数值
- 除以上字符串外,都返回 NaN
- 对象,会先调用 valueOf 方法,并且按照上述规则转换返回值,如果值是 NaN,则再会调用 toString() 方法,并按照上述规则转换返回值
- parseInt() 函数,将字符串转换成整数
- 忽略前置空格,从第一个非空字符串开始转换
- 第一个字符不是数值、加号或减号,则返回 NaN
- 空字符串返回 NaN
- 第一个字符是数值、加号或减号,则依次检测每一个字符,一直到字符串末尾,或碰到非字符串为止,例如: parseInt('123aaaa') => 123, parseInt('22.4') => 22, 小数点不是有效的整数字符
- 第一个参数传入的值若不是字符串,会调用 toString() 方法返回字符串
- 还可以传入第二个参数,指定要转换的进制数 (2 ~ 36)
如果提供了十六进制参数,那么字符串前面的"0x"可以省掉:
let num1 = parseInt("AF", 16); // 175
let num2 = parseInt("AF"); // NaN
let num1 = parseInt("10", 2); // 2,按二进制解析
let num2 = parseInt("10", 8); // 8,按八进制解析
let num3 = parseInt("10", 10); // 10,按十进制解析
let num4 = parseInt("10", 16); // 16,按十六进制解析
- parseFloat() 函数,将字符串转换成浮点数值
- 转换方式和 parseInt 类似
- 第一个小数点有效,第二个无效
- 忽略开头的零
- 只解析十进制值,所以十六进制的字符串始终返回 0
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
String
- 表示零或多个 16 位 Unicode 字符
- 可以用一对单引号,一对双引号,一对反引号包围
let name = 'zhangsan'
let name = "zhangsan"
let name = `zhangsan`
- 字符串字面量
- \n 换行
- \t 制表
- \b 退格
- \r 回车
- \f 换页
- \ 反斜杠
- ' 单引号
- " 双引号
- ` 反引号
- 字符串模板
转换成字符串
- toString()
- 除 null 和 undefined 外都有 toString() 方法, 其实就是继承了Object的方法
- 对数值的调用,还可以传入参数,指定返回进制数的字符串
let num = 10;
console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
console.log(num.toString(8)); // "12"
console.log(num.toString(10)); // "10"
console.log(num.toString(16)); // "a"
- String()
Object
- 对象是一组数据和方法的集合
- 字面量可用通过花括号创建,也可以用 new Object() 创建对象
var obj = {}
var obj = new Object()
- 属性和方法
- constructor:创建对象得构造函数
- hasOwnProperty(propertyName): 判断当前对象上(非原型)是否存在该属性
- isPrototypeOf(object): 判断当前对象是否是另一个对象得原型
- propertyEnumerable(propertyName): 判断给定得属性是否可以使用
- toLocaleString() : 返回对象的字符串表示,字符串反映当前的本地执行环境
- toString(): 返回对象的字符串表示
- valueOf(): 返回对象的原始值
Symbol
Symbol 类型是 ES6 新增的符号,是原始值,并且符号的实例是唯一,不可以变得。符号的用途主要就是确保对象属性使用唯一标识符,避免属性冲突。
- Symbol(): 基础用法
- Symbol.for(): 全局注册,
第一次使用字符调用的时候,会先检查全局注册表中是否存在该符号,不存在就新建一个添加到全局注册表中,若存在则就返回符号实例 - Symbol.keyFor(): 查询全局注册
- Symbol.asyncIterator:
一个方法,该方法返回对象默认的 AsyncIterator。由 for-await-of 使用
class Emitter {
constructor(max){
this.max = max
this.asyncIdx = 0
}
async *[Symbol.asyncIterator](){
while(this.asyncIdx < this.max){
yield new Promise((resolve)=>resolve(this.asyncIdx++))
}
}
}
async function asyncCount (){
let emitter = new Emitter(5)
for await (const x of emitter ) {
console.log(x)
}
}
asyncCount()
// 0
// 1
// 2
// 3
// 4
- Symbol.hasInstance:
一个方法,该方法决定一个构造器对象是否认可一个对象是它的实例, 由 instanceof 使用(instanceof 原理就是检测构造函数的prototype属性 是否在对象的原型链上出现)
function Foo() {}
let f = new Foo();
console.log(Foo[Symbol.hasInstance](f)); // true
class Bar {}
let b = new Bar();
console.log(Bar[Symbol.hasInstance](b)); // true
class Bar {}
class Baz extends Bar {
static [Symbol.hasInstance]() {
return false;
}
}
let b = new Baz();
// Baz 是由 Bar 继承而来,所以对象 b 的原型链上是由 Bar 的,
console.log(Bar[Symbol.hasInstance](b)); // true
console.log(b instanceof Bar); // true
console.log(Baz[Symbol.hasInstance](b)); // false
console.log(b instanceof Baz); // false
- Symbol.isConcatSpreadable:
一个布尔值,如果是true,一位置对象应该用 Array.prototype.concat 将数组打平 - Symbol.iterator: 一个方法,该方法返回对象的迭代器。由 for-of 使用。
class Emitter {
constructor(max) {
this.max = max;
this.idx = 0;
}
*[Symbol.iterator](){
while(this.idx < this.max){
yield new Promise((resolve)=> resolve(this.idx++))
}
}
}
function fnCount(){
let emitter = new Emitter(5)
for (const x of emitter){
console.log(x)
}
}
fnCount()
// 0
// 1
// 2
// 3
// 4
- Symbol.match:
一个正则表达式的方法,该方法是用正则表达式去匹配字符。由 String.prototype.match 使用 - Symbol.search:
一个正则表达式的方法,该方法是返回字符串中匹配正则表达式的索引 - Symbol.replace:
一个正则表达式方法,该方法是替换一个字符串中匹配的子串 - Symbol.split:
一个正则表达式的方法,该方法在匹配正则表达式的索引位置拆分字符串 - Symbol.toPrimitive:
一个方法,该方法是将对象转换成相应的原始值 - Symbol.toStringTag:
一个字符串,该字符串用于创建对象的默认字符串 - Symbol.unscopables: 一个对象,该对象所有的以及继承的属性,都会从关联的对象的 with 环境绑定中排除。
let o = { foo: 'bar' };
with (o) {
console.log(foo); // bar
}
// 设置了 true, 就不能在 with 使用属性了
o[Symbol.unscopables] = {
foo: true
};
with (o) {
console.log(foo); // ReferenceError
}