1. 类型 7个基本类型3个对象类型 - 10
- a.基本(值)类型: string number boolean undefined null symbol bigint
- b.对象(引用)类型: object array function(特殊对象-存代码块) 无对象的引用,为垃圾对象,自动回收
2. 类型判断
a.typeof(类型) 类型的字符串表达(小写) - typeof 1
'string' 'number' 'boolean' 'undefined' 'object'(错误) 'symbol' 'bigint'
'object' 'object' 'function'
b.instanceof(实例) 判断实例,可以(new的构造函数) 不能判断基本类型 - {} instanceof
Object Array|Object Function|Object
instanceof 也会判断原型链
String Number Array Object Function等等构造函数原型链上都是Object 都为true
可以判断new String('') new Number(1) 的内容。它们typeof 为'object' 不再是基本类型
c.constructor(构造函数)
String Number Boolean x x Symbol BigInt
Object Array Function
c. === (undefined null)
?undefined和null的区别 - 已声明未赋值、已声明已赋值为null(垃圾回收)
?基本类型可以被new - 变为Number{1}
?instanceof能否判断基本类型 - 不
?准确判断对象类型 - .constructor
3. 变量 内存 数据
a.变量是内存的标识
b.内存是存储数据的临时空间
栈(变量、基本类型) 堆(对象)
?内存存的是什么 - 数据和地址
?函数的参数是什么传递 - 值传递(基本值|地址值) 值传递(基本值)、引用传递(地址值)
4. 变量提升
a.只有var function存在变量提升 - 先变量提升,后函数提升 - 先提升后赋值
b.var提升后是undefiend function提升后可正常指向
c.当全局var 和块作用域下的var同时存在,只查找当前作用域下的var
?var a = 1
function fn(){
console.log(a) // - undefined
var a = 2
}
? var fn = function(){} 为var提升,undefined 不能执行
? var a = 1 function a(){} a() - 报错,先var a,再function a,再a=1,1()报错。var a = 1分2步,=1在后面
5. 对象
a.封装管理多个数据
b.属性 方法 (属性和方法的合集)
c.['only-key'] .key
6. 函数
a.可执行的代码块 特殊对象
b.函数声明 表达式声明
c.test() .test() new test() test.call()
d.回调函数
e.匿名自调用函数 (不污染全局) (模块化的基础)
7. this
a.函数本质上都是通过(某个对象调用) 没有指定就是window globalThis
b.4种this指向:window object 实例 (call apply bind)
8. 原型链 实例-构造函数-原型
a.非null undefined的所有类型的原型链最终都指向Object的原型 包含了许多js的通用方法
''.proto(String).proto(Object)
(1).proto(Number).proto(Object)
(true).proto(Boolean).proto(Object)
b.通用方法 constructor() toString() valueOf()
c.显式原型prototype
所有构造函数都有prototype 指向其原型对象 {constructor,proto}
所有原型对象的constructor 指向其构造函数
(function 或者 new Function) 在创建函数的时候,就创建其原型对象,并赋值给prototype
''.constructor.prototype === ''.proto
''.constructor === ''.proto.constructor
d.隐式原型__proto__
所有实例都有__proto__ 不建议修改与引用
实例的__proto__和构造函数的prototype 都指向其原型
(new) 在创建实例的时候 将构造函数的prototype赋值给实例的 proto
e.方法定义在原型上、属性定义在构造函数上
f.原型链:通过[Prototype]属性链接形成一个链条
原型链继承:将A原型对象的[Prototype]链接B原型对象
function New(fn){
const obj = Object.create(fn.prototype) // 创建且继承原型链
const [,...rest] = arguments
const obj2 = fn.apply(obj,rest) // this指向创建的obj
return obj2?.constructor === Object ? obj2 : obj
g.实例只能引用原型属性,不能修改
?创建实例a后,更改A.prototype = {}; 再创建实例b
- b的__proto__更改了,a的__props__没有更改。因为new时创建新对象,只链接当前prototype。__proto__不会改
9. 执行上下文(预处理)
a.全局(堆 真实 window)
var - undefined - window属性
function - 赋值 - window属性
this - window
b.函数(栈 虚拟 函数上下文对象)
执行时创建函数上下文 - 预处理 - 执行完销毁
形参 arguments var function
this - 执行对象
执行完销毁上下文
c.执行上下文栈(后进先出)(始终有window,在栈底)
10. 作用域 作用域链
a.静态作用域链,编写代码时就确定。
上下文-顺序执行-销毁
b.隔离变量,不同作用域下的变量没有冲突
c.全局作用域 函数作用域 块作用域
d.和执行上下文的区别:
上下文(动态)从属于作用域(静态)
e.动态作用域链-可以理解为上下文,
引用关系与嵌套关系无关,于执行顺序有关。执行时动态创建不同函数、块的引用关系。(返回函数,不能静态分析)
销毁了父作用域不能影响子函数,所以要再创建个对象。
要把子函数内引用(refer)的父作用域的变量打包里来,给子函数打包带走
设计个独特的属性,比如 [[Scopes]] ,用这个来放函数打包带走的(栈结构)
销毁父作用域后,把用到的变量包起来,打包给子函数,放到一个属性上。这就是闭包的机制。
11. 闭包
a.子函数引用父函数内的变量,父函数执行时,产生闭包
b.闭包存在于 函数执行上下文 中的子函数里
c.父执行完销毁函数上下文,但被引用的内部属性会打包放在[[Scopes]],没被垃圾回收,活在内存。
d.作用:反作用域链 外作用域访问内作用域里的变量
e.set get 属性封装
f.闭包只保存外部引用
g.闭包是返回函数的时候扫描函数内的标识符引用,把用到的本作用域的变量打成 Closure 包,放到 [[Scopes]] 里。
h.闭包是在函数创建的时候,让函数打包带走的根据函数内的外部引用来过滤作用域链剩下的链。
它是在函数创建的时候生成的作用域链的子集,是打包的外部环境。
evel 因为没法分析内容,所以直接调用会把整个作用域打包(所以尽量不要用 eval,容易在闭包保存过多的无用变量)
而不直接调用则没有闭包
i.js 是静态作用域的设计,闭包是为了解决子函数晚于父函数销毁的问题,我们会在父函数销毁时,
把子函数引用到的变量打成 Closure 包放到函数的 [[Scopes]] 上,让它计算父函数销毁了也随时随地能访问外部环境。
? 为啥debugger调试的时候不能看一些变量的信息
- 可是是在回调函数内查看,回调函数是在另一个函数内执行,创建时打包带走该环境内的东西。
只打包必要的环境(不浪费内存),没有被引用,就不打包。就不能查看。
?eval('console.log(1+1)')(字符串变成可执行代码)为什么性能差
- eval不能静态分析,只能动态。所以都打包为闭包。影响性能
12. 事件循环
a.js代码的执行顺序,游览器或者node解决js单线程运行时不阻塞的一致机制,异步的原理
b.先执行Script脚本,清空微任务队列,开始下一轮事件循环,继续先执行宏任务,再清空微任务队列
c.宏任务 /Script/setTimeout/setInterval/setImmediate/io/uiRendering
d.微任务 /process.nextTick()类似node版的setTimeout/Promise
e.优先级 宏任务>微任务
setTimeout = setImmediate 一个队列
process.nextTick > Promise
(每一个宏任务执行完毕都必须将当前的微任务队列清空)
第一个script标签(宏1)-Promise(微)-异步任务-event表-注册事件-放入微事件队列-主线程执行
第一个宏任务执行完毕-setTimeout(宏2)-异步任务-event表-注册事件-放入宏事件队列-主线程执行
f.js引擎monitoring process进程会持续检查主线程是否为空
?setTimeout(()=>test(),1000) 会1s后执行吗 - 不会,1s后放入event队列,等待主线程空闲后执行 ? setTimeout 和 Promise 谁先执行 - Promise,微任务队列清空后,才执行下一个宏任务 13. 继承 a. class extends b. 组合继承 function Father(){} function Children(){ Father.call(this); // 添加父类属性 } Children.prototype = {...Father.prototype} // 连接到父类原型对象 Children.prototype.constructor = Father; // 子类原型对象上的的构造方法指向自己 14. 常见error a. Uncaught SyntaxError: Unexpected end of input - 未捕获的语法错误 b. Uncaught TypeError: f3 is not a function - 未捕获的类型错误 c. Uncaught RangeError: The number 0.1 cannot be a BigInt because it is not an integer - 未捕获的范围错误