JS基础-你都了解吗?

127 阅读7分钟

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 - 未捕获的范围错误