# 二.JS 高级

# 1.路由原理

路由的本质是监听 URL 的变化,然后匹配路由规则,显示相应的页面,并且无需刷新页面

  • hash 模式:通过 hashchange 事件来监听 URL 的变化,从而实现页面跳转,而服务端接受到的 URL 永远都没有 hash 后缀
  • history 模式:通过 pushState 和 replaceState 改变 URL;通过 History 模式改变 URL 同样不会引起页面的刷新,只会更新浏览器的历史记录;后退会触发 popState 事件
  • hash 模式只可以更改#后面的内容,history 模式可以通过 API 设置任意的同源 URL
  • history 模式可以通过 API 添加任意类型的数据到历史记录中,hash 模式只能更改哈希值,也就是字符串

# 2.异步加载和延迟加载

  • 1.异步加载的方案: 动态插入 script 标签
  • 2.通过 ajax 去获取 js 代码,然后通过 eval 执行
  • 3.script 标签上添加 defer 或者 async 属性
  • 4.创建并插入 iframe,让它异步执行 js
  • 5.延迟加载:有些 js 代码并不是页面初始化的时候就立刻需要的,而稍后的某些情况才需要的。

# 3.作用域

  • 一套管理引擎如何在当前作用域以及嵌套的子作用域中根据标识符名称(标识符就是变量或者函数名)查找变量的规则;
  • 只有全局作用域和局部作用域(es6 中加入块级作用域),作用域在他创建的时候就存在了
  • 什么是作用域链
    • 由当前环境与上一层环境的一系列变量对象组成,保证当前执行环境里有权访问的变量和函数是有序的,作用域变量只能被向上访问
    • 变量访问到 window 对象即被终止,作用域链向下访问是不被允许的
  • 改变作用方式有
    • 变量访问到 window 对象即被终止,作用域链向下访问时不允许的
      • 1.改变作用域由 with try...中 catch
      • 2.所有格未定义的直接赋值的变量自动声明为全局作用域。
  • 代码执行分为两个阶段:
    • 代码编译阶段:
      • 由编译器完成,将代码翻译成可执行的代码,这个阶段会被确定
    • 代码执行阶段:
      • 由 js 引擎完成,主要执行科执行的代码,这个阶段执行上下文被创建(对象被创建)
    • 执行上下文:
      • 一个看不见的对象,存在若干个属性和变量,它被调用的时候创建的。函数被调用查看 this 指向 object,object 就是上下文(只有被调用的时候创建)
  • 作用域链
    • 当代码在一个环境中执行时,会创建变量对象的一个作用域链
    var name = "Tom"
    function say() {
      alert("hi," + name)
    }
    say() //hi, Tom
    
    1
    2
    3
    4
    5
    • 函数 say()的执行环境为全局环境,所以他的变量对象为 window。当函数执行到 name 时,先查找局部环境,找到则返回局部环境的 name,否则顺着作用域查找,在全局环境中找到 name 返回,这一查找变量的有序过程的依据就是作用域。
    • 作用域链是保证执行环境有权访问的所有变量和函数的有序访问
    • 当代码在一个环境中执行是,会创建变量对象的一个作用域链

# 5.对象的几种创建方式

  • 工厂模式
  • 构造函数模式
  • 原型模式
  • 混合构造函数和原型模式
  • 动态原型模式
  • 寄生构造函数模式
  • 稳妥构造函数模式

# 6.js 异步加载的方式

  • 渲染引擎遇到 script 标签会停下来,等到执行完脚本,继续向下渲染
  • defer 是“渲染完再执行”,async 是“下载完就执行”,defer 如果有多个脚本,会按照在页面中出现的顺序加载,多个 async 脚本不能保证加载顺序
  • 加载 es6 模块的时候设置 type=module,异步加载不会造成阻塞浏览器,页面渲染完再执行,可以同时加上 async 属性,异步执行脚本(利用顶层的 this 等于 undefined 这个语法点,可以侦测当前代码是否在 ES6 模块之中)

# 7.函数

高阶函数

  • 函数作为参数传递,抽离出一部分容易变化的业务逻辑,把这部分业务逻辑放在函数参数中。这样一来可以分离业务代码中变化与不变的部分

  • 函数作为返回值传递

函数参数传递

按共享传递

var person = { a: 111 }
function change(obj) {
  obj = new Object()
  obj.a = 222
  return obj
}
1
2
3
4
5
6

函数柯里化

  • 概念:
    • 一个函数接受函数 A 作为参数,运行后返回一个新的函数,并且可以处理 A 中的参数(只接受一个参数的函数)
  • 意义:
    • 将函数完全变成了接受一个参数,返回一个参数的固定形式,便于讨论和优化

# 8.TypeScript 的优点

  • 编译时的强类型,变成了强类型语言,还是编译成 js,编译的时候可以检验
  • 更好的模块化
  • 更好的实现面向对象的编程,类、接口、模块

# 9.js 的阻塞特性

  • 所有浏览器在下载 js 的时候,会阻一切其他活动,比如其他资源的下载,内容的程序等等;直到 js 下载、解析、执行完毕后才开始继续并下载其他资源并呈现内容。为了提高用户体验,新一代浏览器都支持并行下载 js,但是 js 下载任然会阻塞其他资源的下载(图片,css)
  • css 阻塞:因为浏览器会维持 thml 中的 css 和 js 的顺序,样式表必须在嵌入的 js 执行前先加载、解析完。而嵌入的 js 会阻塞后面的资源加载,所以就会出现上面的 css 阻塞下载的情况

# 10.移动端 300ms 延迟

  • 由来:300 毫秒延迟解决的是双击缩放
    • 双击缩放,手指在屏幕快速点击两次,safari 浏览器就会将网页缩放原始比列
    • 由于用户可以双击缩放或者是滚动操作,当用户点击屏幕一次之后,浏览器并不会判断用户确实要打开这个链接,还是想要进行双击操作
    • 因此,safair 浏览器就会等待 300ms,来判断用户是否在次点击屏幕
  • 解决方案
    • 1.禁止缩放,设置 meta 标签 user-scalable=no
    • 2.fastclick.js
      • 原理:FastClick 的实现原理是在检查到 touchend 事件的时候,会通过 dom 自定义事件立即发出 click 事件,并把浏览器在 300ms 之后真正 click 事件阻止掉
      • fastclick.js 还可以解决穿透问题

# 11.DOM 操作

(1)创建新节点

createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
1
2
3

(2)添加、移除、替换、插入

appendChild()
removeChild()
replaceChild()
insertBefore() //在已有的子节点前插入一个新的子节点
1
2
3
4

(3)查找

getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
getElementById() //通过元素Id,唯一性
1
2
3

# 12.为什么 0.1+0.2!=0.3

上次更新: 2023/1/7 下午3:34:52