最近刚做完一个全栈项目,反思时,发现JS基础薄弱,痛定思痛,故决定回顾JS,查漏补缺,温故知新
JS的运行机制:
1.当浏览器(内核/引擎)渲染和解析JS代码的时候,会为JS代码提供一个可运行的环境,即”全局作用域(global/window scope)”
2.代码自上而下执行(执行前存在变量提升阶段)
Js的垃圾回收机制
个人觉得最主要的概念就是可达性,这么理解真是太简单粗暴了,里面的优化算法还是相当优秀的
- 可达性: 即当前的所有变量与参数是否可以从全局对象从延神过去,如果不行则会回收该变量或参数.
基本数据类型与引用数据类型的赋值差异(执行差异)
-
基本数据类型(值类型),为按值操作,即当每创建一个新值,都会为该值开辟一个新空间,存储在当前作用域下(栈内存)
值类型: 数字
Number
, 字符串String
, 布尔Boolean
,null
,undefined
数字 Number : NaN(not a number),指该值为一个数字类型,但非为有效数字,且与任何值都不相等 isNaN,检测一个值是否非有效数字,会先使用Number()将值转换为数字再进行检测
栈内存: 本身即是JS运行环境
-
复杂数据类型(引用类型), 由于存储数据类型可能复杂,存储后的内容通过地址(16进制)引用进行修改,额外开辟新的空间(堆内存),而不会存储在当前作用域.
引用类型: 对象
Object
(数字, 日期….), 函数Function
, ( 在ES6中加入了唯一值 Symbol )堆内存: 用于存放引用数据类型,如: 对象内存放键值对,函数体内存放代码字符串
数据类型
基本数据类型 | ||||
---|---|---|---|---|
数字Number |
整数 | 浮点数 | Infinity | -Infinity |
数字Bigint |
大于 (2^53-1) | 小于-(2^53-1) | ||
字符串 String |
||||
布尔Boolean |
||||
null |
自成类型 | |||
undefined |
自成类型 | |||
symbol |
唯一值 |
复杂数据类型 |
---|
Object |
Tip: 通过tyepof 去判断null类型会得到Object,但这是Javascript本身的问题,去输出函数如
alert
会得到function类型,但是在Javascript并不存在function类型
数字类型
1.小数计算,应该避免相等性检查.这与计算机存储数字的方式有关,即二进制无法精确的存储0.1这种小数.
2.使用小数时,要记住小数会有精度问题.
3. isFinite()
用于判断一个变量是否为有效数字(非infinity,-infinity,NaN)
// 记一个复杂度较低的算法, 带到日后刷起 leetcode, 我相信这是我对算法兴趣的开端 function getMaxSubSum(arr) { let maxSum = 0; let partialSum = 0; for ( let item of arr) { partialSum += item maxSum = Math.max(maxSum, partialSum) if(partialSum < 0) partialSum = 0; } return maxSum; } alert( getMaxSubSum([-1, 2, 3, -9]) ); // 5
字符串类型
1.字符串可通过[]
和 charAt()
获取字符串的固定字符,区别在于如果[]
获取不到字符,返回undefined,而charAt()
返回一个空字符串.
2.for..of
可以遍历字符串.
3.slice(start, [end])
用于字符串的截取.
4.localeCompare()
根据当前的语言规则来判断两个字符串的大小.
Symbol
1. Symbol类型是唯一值,字面量中使用是给键添加一个[]
如 [id] : 123;
2. Symbol 能够起到唯一标识的作用且创建的属性会被隐藏,即在循环时,该属性将不会被访问到,或者该库内的脚本,被第三方应用的时候,该属性也不会被访问到,不会引起冲突.
3. Symbol类型的创建方式
let id = Symbol("id"); // 对该变量的描述
4. 全局注册表
通过 Symbol.for()
进行查询,如果变量不存在,则创建.
let id = Symbol.for("id"); // 查询or创建一个description为 id 的Symbol let id2 = Symbol.for("id"); // id是存在,即此行为查询. alert( id === id2 ) // true
通过 Symbol.keyFor()
可以通过变量名查找Symbol.
let link = Symbol.for("name"); // 查询or创建一个description为 id 的Symbol alert(Symbo.keyFor(link)) // name
注意: Symbol(“id”)与Symbol.for(“id”)是有区别的,前者是局部上的一个唯一值,而后者是全局范围内的.
系统 Symbol
这个内容尚未接触,待补充.
基本数据类型操作中要注意的地方
1.运算符中,只要 + 的运算会将 元(参数) 转换为字符串类型(String
),其余则全部转换为数字类型(Number
)
2.有意思的是,单元运算中,+ 类似于Number()
方法,可以将参数转换为数字
+='' // 0 += undefined // NaN += null // 0 += " \t \n" // 0
复杂数据类型(Object)
方括号
1.用于对多字段属性名的命名.
2.计算属性简单来说,就是从对象外部去获取属性名.
let fruit = prompt("Which fruit to buy?", "apple"); let bag = { [fruit]: 5, // 属性名是从 fruit 变量中得到的 }; alert( bag.apple ); // 5 如果 fruit="apple"
3.通过外部动态输入的值访问变量
let user = { name: "John", age: 30 }; let key = prompt("What do you want to know about the user?", "name"); // 访问变量 alert( user[key] ); // John(如果输入 "name")
for(..in..)
记录自己遗漏的点.
- 如果对象的属性存在,for循环才会执行.
可选链 “?.”
1.可选链 “?.” 用于防止访问的值不存在的时候报错,但是实际上用了可选链,返回的值仍是undefined,对用户来说还是不友好,但可以自己处理错误.
2.可选链的结构:
let user = { name = "Link", } // ↓↓这里 alert( user?.name )
可见可选链是为问号所在节点提供可选,但对name
是不起作用的,也就是说如果name属性不存在,代码仍会报错
3.可选链使用规则
注意一下 这里纯属个人推测理解
1) 可选链要求被判断属性的对象必须被声明,但可以为空
let user = {}; alert(user?.address) // 代码不会报错 //----------------------------- let user = {}; alert(user.address?.street) // 同样不会报错,但是address属性,并没有被定义 //----------------------------- alert(user?.address) // 代码报错