Js进阶
JS 进阶
代码示例
1 | (() => { |
catch
代码块接收参数x
。当我们传递参数时,这与之前定义的变量x
不同。这个x
是属于catch
块级作用域的。然后,我们将块级作用域中的变量赋值为
1
,同时也设置了变量y
的值。现在,我们打印块级作用域中的变量x
,值为1
。
catch
块之外的变量x
的值仍为undefined
,y
的值为2
。当我们在catch
块之外执行console.log(x)
时,返回undefined
,y
返回2
。
1 | let person = { name: "Lydia" }; |
首先我们声明了一个拥有
name
属性的对象person
。然后我们又声明了一个变量
members
. 将首个元素赋值为变量person
。当设置两个对象彼此相等时,它们会通过 引用 进行交互。但是当你将引用从一个变量分配至另一个变量时,其实只是执行了一个 复制 操作。(注意一点,他们的引用 并不相同!)接下来我们让
person
等于null
。我们没有修改数组第一个元素的值,而只是修改了变量
person
的值,因为元素(复制而来)的引用与person
不同。members
的第一个元素仍然保持着对原始对象的引用。当我们输出members
数组时,第一个元素会将引用的对象打印出来。
1 | const num = parseInt("7*6", 10) // 7 |
只返回了字符串中第一个字母。设定了 进制 后 (也就是第二个参数,指定需要解析的数字是什么进制:十进制、十六机制、八进制、二进制等等……),
parseInt
检查字符串中的字符是否合法。一旦遇到一个在指定进制中不合法的字符后,立即停止解析并且忽略后面所有的字符。
*
就是不合法的数字字符。所以只解析到"7"
,并将其解析为十进制的7
.num
的值即为7
.
1 | const name = "Lydia"; |
delete
操作符返回一个布尔值:true
指删除成功,否则返回false
. 但是通过var
,const
或let
关键字声明的变量无法用delete
操作符来删除。
name
变量由const
关键字声明,所以删除不成功:返回false
. 而我们设定age
等于21
时,我们实际上添加了一个名为age
的属性给全局对象。对象中的属性是可以删除的,全局对象也是如此,所以delete age
返回true
.
函数柯里化(Curry):函数元(参数)降维技术
1 | const a = (b, c) => b + c |
1 | const curry = function(fn){ // bind(绑定) fn |
1 | [y] = [1, 2, 3, 4, 5]; |
1 | // module.js |
类
是 构造函数
的 语法糖
如果用 构造函数 的方式重写 person 类则是:
1 | // 类 |
1 | const myMap = new Map() |
当通过
set
方法添加一个键值对,一个传递给set
方法的参数将会是键名,第二个参数将会是值。在这个 case 里,键名为 函数() => 'greeting'
,值为'Hello world'
。myMap
现在就是{ () => 'greeting' => 'Hello world!' }
。1 是错的,因为键名不是
'greeting'
而是() => 'greeting'
。 3 是错的,因为我们给get
方法传递了一个新的函数。对象受 引用 影响。函数也是对象,因此两个函数严格上并不等价,尽管他们相同:他们有两个不同的内存引用地址
。
创建一个新的变量 counterTwo
并将 counOne 的 引用地址
赋值给他(Two、One 指向内存同一个地址)
1 | class Counter { |
事件循环机制**event loop
**
1 | const myPromise = Promise.resolve("Promise!"); |
疑难杂症
对象的键被自动转化为字符串,当对象化为字符串时,变成”[object object]”
导致事件的最深嵌套的元素是事件的 target 可以通过event.stopPropagation 来阻止事件冒泡
.apply .call .bind (parameter1, parameter2)
parameter1 传递对象引用
parameter2 所传递对象的参数(apply
是数组,而call
是参数列表,且为一次性传入,bind
可多次动态传入,参数列表形式传入)
bind 返回函数的副本,但带有绑定上下文!它不是立即执行的
apply call 立即执行
7 种内置类型
string
number (bigint)
boolean
null
undefined
symbol
object
function 不是一种类型 属于 object 对象
JavaScript 中的一切都是 基本类型(7)+ 对象
string 是可迭代的 […’Lydia’] = [‘L’, ‘y’, ‘d’, ‘i’, ‘a’]
引入的模块 是只读的
1 | import myCounter from "./counter"; // myCounter 为只读属性 |
引入的模块是 只读 的:你不能修改引入的模块。只有导出他们的模块才能修改其值。
JavaScript中闭包(Closure,上面我们已经提到过)产生的原因,一个函数还没有被销毁(调用没有完全结束),你可以在子环境内使用父环境的变量。
delete 不能删除 const let var 声明的变量 返回 false
defineProperty(object, key, { value: 1 }) 给指定对象添加 key属性 不可枚举
import
命令是编译阶段执行的,在代码运行之前,被导入的模块代码,先运行。区别于 CommonJs
的 require
,require
按需加载,执行顺序取决于 require
所在代码位置
functong * name(params){} : 表示声明了 一个函数生成器Genarator
对象,通常 name 生成器函数,配合yeild
使用,以达到 name 函数内部逻辑 暂停
恢复执行
。 name.next()
得到一个 { value: 值, done: true }
对象。next
方法可以带参数 name.next('param1')
则 param1
将传递给 name 函数的 上一个 yeild
表达式的返回值。注:yeild 只能在生成函数中使用。
Object.freeze(obj)
使得obj对象的属性 无法添加、修改、删除(冻结对象)
尝试打印一个未定义的对象,报错 ReferenceError
引用错误
数组元素:任何值、数学表达式、日期、函数计算
定时器 setTimeout
setInterval
中,this
指向 全局对象 windows
function(a, b = a)
可以将函数参数的默认值 设置为另一个参数,只需另一个参数定义于这个函数参数之前
push
方法返回 数组长度
[1,2,3].push(5) === 4
function(a, b, ...c){}
...c
表示 剩余参数
是一个 数组
只能 作为最后一个参数
否则抛出 语法错误 syntaxError
Javascript 引擎
自动在语句后添加 ;
号
可以将类
设置为等同于其他类/函数 构造函数
symbol
类型是不可 枚举的
Object.keys(obj)
将不可见 symbol
类型的 key
但 Object.getOwnPropertySymbols(obj)
方法访问
箭头函数
若返回 一个值
,则 () =>
不必要写 {}
,若返回 对象
则必须 () => { return { obj } }
或 () => ({ obj })
"string"()
字符串调用(非函数不能调用)报错 TypeError
类型错误
常见 假值
null
undefined
""
0
-0
NaN
false
0n
微任务
: promise.then()
process.nextTick()
MutationOvserver()
宏任务
: setTimeout
setInterval
script
setImmediate
I/O
UI-rendering
await 执行当前代码,将后续代码加入 微任务队列。等价于 先执行new Promise()后,将 promise.then() 加入微任务队列
事件循环数据结构
:微任务队列
、 宏任务队列
。不断循环执行 宏任务队列
a + b
若 a、b 不全为 数字
Js引擎
会将 a、强制转为 字符串
{ name: value } 对象强转字符串为 [ Object object ]
,再进行字符串拼接
对象通过引用传递
(引用内存的位置),当我们检查对象的严格性相等时===
,我们正在比较他的引用
.
点
表示法访问对象属性,Obj.name
,会使用改确切名称在对象上查找属性,若没有name ,则返回 undefined
Obj['name']
,方括号表示法,它会从第一个 [
开始直到找到右方括号 ]
,之后才开始评估 语句,[]
中可以插入表达式,运行时才确认的属性,而.
属性不能访问。
❤️
表情符号是 unicode
,对于相同的 表情符号,他们总是相等的 如❤️ === ❤️
map slice filter
返回一个新数组,find
返回一个元素,reduce
返回一个计算 值
在 javascript 中 原始类型
通过 值
起作用。当 原始类型 如字符串 的值是数组的值时,该字符串的值只是 数组引用值的复制
,改变字符串值时,数组值并不会被改变
let const
与 var
声明的变量都会有 提升,但与var
不同的是,它们不会被初始化 undefined
.在声明之前不能访问它,这个行为成为暂时性死区
,试图访问会抛出ReferenceError
(暂时性死区:在 let 声明之前的执行瞬间)
((x => x)('param'))
是个立即执行函数
相当于向箭头函数 x => x 传递参数 param 并且执行
() =>
箭头函数并没有属于自己的 this
,this
捕获其所在上下文的this,作为自己的值
??=
逻辑空赋值,x ??= value
仅在 x = 空值(undefined 或 null)时,对其赋值 value
get
语法将对象属性绑定到查询该属性时被调用的方法。(当 访问 obj.name
时,就会调用 get name()
方法若有)。当尝试设置属性时,set
语法将对象属性绑定到要调用的函数,它还可以在类中应用。(当 修改属性 obj.name = value
时,就会调用 set name(value)
方法若有)。get、set
方法返回 undefined
!typeof name === "string"
: 先 计算 typeof name
再取反 !
最后再检验 ===
Number.isNaN(value)
检测 value
是否是 数字且等价于NaN
isNaN
检测 value 是不是 不是一个数字
Object.seal(obj)
可以防止新属性被添加、存在属性 被移除。然而、仍然可以对存在属性
进行更改
Object.freeze(obj)
对 对象进行浅冻结
,不能对 obj 的属性 添加、修改、删除。但可以操作 obj 里的对象属性(浅冻结)
ES2015 -> es6
...
ES2020 -> es11
,在 ES2020 中,通过 #
可以给 class
添加私有变量,但在 class 外部我们无法获取该值,尝试获取、则会报错 syntaxError
语法错误
对象默认不是可迭代的,可以通过添加对象迭代器[sysmbol.iterator]
来定义迭代规则,其返回一个generator
函数*[sysmbol.iterator](){}
,[...obj]
无法解构,{...obj}
可以解构
在 class
中constructor
中的属性,不会在原型链上共享
Promise.all
方法可以并行运行promise
,如果其中一个promise失败了,Promise.all
方法会带上reject
的promise
的值_rejects_
函数式编程特性
说了这么久,都是在讲函数,那么究竟什么是函数式编程呢?在网上你可以看到很多定义,但大都离不开这些特性。
- First Class 函数:函数可以被应用,也可以被当作数据。
- Pure 纯函数,无副作用:任意时刻以相同参数调用函数任意次数得到的结果都一样。
- Referential Transparency 引用透明:可以被表达式替代。
- Expression 基于表达式:表达式可以被计算,促进数据流动,状态声明就像是一个暂停,好像数据到这里就会停滞了一下。
- Immutable 不可变性:参数不可被修改、变量不可被修改—宁可牺牲性能,也要产生新的数据(Rust内存模型例外)。
- High Order Function 大量使用高阶函数:变量存储、闭包应用、函数高度可组合。
- Curry 柯里化:对函数进行降维,方便进行组合。
- Composition 函数组合:将多个单函数进行组合,像流水线一样工作。
另外还有一些特性,有的会提到,有的一笔带过,但实际也是一个特性(以Haskell为例)。
- Type Inference 类型推导:如果无法确定数据的类型,那函数怎么去组合?(常见,但非必需)
- Lazy Evaluation 惰性求值:函数天然就是一个执行环境,惰性求值是很自然的选择。
- Side Effect IO:一种类型,用于处理副作用。一个不能执行打印文字、修改文件等操作的程序,是没有意义的,总要有位置处理副作用。(边缘)
数学上,我们定义函数为集合A到集合B的映射。在函数式编程中,我们也是这么认为的。函数就是把数据从某种形态映射到另一种形态。注意理解“映射”,后面我们还会讲到。
浏览器性能优化
渲染流程
渲染进程
html -> DOM树
渲染引擎
css -> css样式树
计算dom节点样式
构建布局树 Dom树 + css样式树
生成图层树 对布局树进行分层
每个图层生成绘制列表 提交给合成线程
每个图层单独绘制
合成图层
渲染性能
减少回流(重排:大小、位置、布局几何信息发生变化)、重绘 (颜色、背景、border)
将回流、重绘的元素作为单独的图层(css3D、canvas、position: fixed、video、css3动画节点)
浏览器以 图层 为单位 进行渲染
元素作为单独图层(
will-change: transform
),使用opacity 或者 transform: transformX(100px)
不会触发 回流、重绘(元素偏移量右 100px 则会交给GPU处理)