前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • React专栏

    • React组合式开发实战

      • 前端开发的四个时代
      • 企业管理系统的前世今生
      • 可视化页面搭建工具
      • 实战篇 01:开发前准备
      • 实战篇 02:项目脚手架
      • 实战篇 03:页面布局方案
      • 实战篇 04:权限管理机制
      • 实战篇 05:菜单匹配逻辑
      • 实战篇 06:消息通知设计
      • 实战篇 07:多语言支持
      • 继往开来:可视化页面搭建工具
    • React Hooks与Immutable实战

    • React SSR服务端渲染与同构实践

    • IM聊天系统前端开发实践

    • 微前端开发实战

    • React进阶实践

  • Vue专栏

  • 移动端专栏

  • Node专栏

  • 前端工程化专栏

  • 算法专栏

  • Typescript专栏

  • 其他专栏

完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

前面章节中,我们讲了什么是构建、为什么需要构建、然后对比了几种常见的构建工具。在构建中,很重要的一个过程就是通过语法降级来兼容低版本浏览器。在前端领域中,用来为旧浏览器提供其没有的最新原生支持的代码片段,我们将其称之为“polyfill” ,翻译过来就是“垫片”,也就是打补丁的意思。

比如说我们想使用 fetch 发请求,我们在 can i use 网站 上查询到,很多低版本的浏览器是不支持该 API 的,所以我们就需要使用 polyfill 比如 whatwg-fetch 来让这些低版本的浏览器支持该 API。whatwg-fetch 会首先判断浏览器是否原生支持 fetch,如果不支持,则结合 Promise 使用 XMLHttpRequest 的方式来实现 fetch。

img

不得不说,你永远不知道用你产品的用户还在使用多么古老的浏览器,为了少数用户的体验,我们还是要支持低版本浏览器(/□\*),作为一个前端开发工程师,必备的一项技能就是处理兼容性问题,本篇文章就带你一起看下前端 polyfill 方案。

目前,前端 polyfill 的实现主要有以下几种方案:

  • 手动打补丁
  • 根据覆盖率动态打补丁
  • 在线动态打补丁

接下来,我们就来看下这几种方法分别是怎么实现的并且分析下其优缺点。

# 手动打补丁

最方便的解决兼容性问题,首先想到的应该是手动写一个转换函数,将新语法转换为旧语法实现降级。比如 Object.assign(),我们如果要自己写一个 Object.assign() 的话,应该怎么实现呢?

  • 首先需要判断原生 Object 中是否存在该函数,如果不存在的话创建一个 assign 函数,并使用Object.defineProperty 将该函数绑定到 Object 上。
  • 然后需要对传参进行判断,处理异常情况。
  • 之后我们需要将传入的对象转换为 Object 对象,保存并返回。
  • 最后我们循环遍历出上一步返回对象的所有可枚举的自有属性,并复制给新的目标对象。

具体代码如下:

// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
if (typeof Object.assign !== 'function') {
  // Must be writable: true, enumerable: false, configurable: true
  Object.defineProperty(Object, "assign", {
    value: function assign(target, varArgs) { // .length of function is 2
      'use strict';
      if (target === null || target === undefined) {
        throw new TypeError('Cannot convert undefined or null to object');
      }

      var to = Object(target);

      for (var index = 1; index < arguments.length; index++) {
        var nextSource = arguments[index];

        if (nextSource !== null && nextSource !== undefined) {
          for (var nextKey in nextSource) {
            // Avoid bugs when hasOwnProperty is shadowed
            if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
              to[nextKey] = nextSource[nextKey];
            }
          }
        }
      }
      return to;
    },
    writable: true,
    configurable: true
  });
}
@前端进阶之旅: 代码已经复制到剪贴板

上面的过程是不是让你想起来了面试时常见题型"手撕xxx代码",确实如此。如果我们采用手动打补丁的方式,需要模拟浏览器原生语法,不只是将功能实现出来就好,我们还需要处理各种各样的边界情况和异常处理,这对开发者的编程基本功有一定的要求。

但是其优点是,直接简单,并且天然的支持“按需”使用,不会有其他冗余代码,在性能上比较友好,但是缺点就是这不是一种工程化的解决方案,不易管理和维护,且复用性低。

# 根据覆盖率自动打补丁

我们都知道,babel 是将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中的工具链。@babel/preset-env 会根据目标环境来进行编译和打补丁,如果想在最近 3个 浏览器版本和 安卓4.4 版本以及 iOS 9.0 以上版本运行我们的代码,那么我们可以这样配置 babel:

...
   presets: [
     [
       '@babel/preset-env',
       {
         targets: {
           "browsers": [
             "last 3 versions",
             "Android >= 4.4",
             "iOS >= 9.0"
           ],
         }
       },
     ],
   ]
...
fe
基础篇
进阶篇
高频篇
精选篇
手写篇
原理篇
面经篇
自检篇
每日一题
  • 综合
    • 综合题型
    • 其他问题
    • 设计模式
    • 思维导图
    • 学习路线
  • 前端基础
    • HTTP
    • 浏览器
    • 计算机基础
  • 进阶学习
    • NPM工作流
    • Docker
    • Canvas
    • Node学习指南
    • 前端综合文章
  • 其他
    • Handbook
    • 职场话题
    • CSS可视化
小程序题库
公众号动态
博客动态
开发者导航
  • React专栏

    • React组合式开发实战

      • 前端开发的四个时代
      • 企业管理系统的前世今生
      • 可视化页面搭建工具
      • 实战篇 01:开发前准备
      • 实战篇 02:项目脚手架
      • 实战篇 03:页面布局方案
      • 实战篇 04:权限管理机制
      • 实战篇 05:菜单匹配逻辑
      • 实战篇 06:消息通知设计
      • 实战篇 07:多语言支持
      • 继往开来:可视化页面搭建工具
    • React Hooks与Immutable实战

    • React SSR服务端渲染与同构实践

    • IM聊天系统前端开发实践

    • 微前端开发实战

    • React进阶实践

  • Vue专栏

  • 移动端专栏

  • Node专栏

  • 前端工程化专栏

  • 算法专栏

  • Typescript专栏

  • 其他专栏