资讯专栏INFORMATION COLUMN

Zepto 源码分析 2 - Polyfill 设计

chuyao / 2467人阅读

摘要:此模块包含的设计思路即为预以匹配降级方案。没有默认编译该模块,以及利用该模块判断后提供平台相关逻辑的主要原因在于其设计原则的代码完成核心的功能。此处,也引出了代码实现的另一个基本原则面向功能标准,先功能覆盖再优雅降级。

在进入 Zepto Core 模块代码之前,本节简略列举 Zepto 及其他开源库中一些 Polyfill 的设计思路与实现技巧。

涉及模块:IE/IOS 3/Detect.

IE 模块 / CSSOM 相关 Polyfill

Zepto 的 IE 模块 src/ie.js 中仅仅包含了一个兼容性降级逻辑,虽简单其实现也值得学习:

(function() {
  try {
    getComputedStyle(undefined);
  } catch (e) {
    var nativeGetComputedStyle = getComputedStyle;
    window.getComputedStyle = function(element, pseudoElement) {
      try {
        return nativeGetComputedStyle(element, pseudoElement);
      } catch (e) {
        return null;
      }
    };
  }
})();

低版本兼容模式(以 IE 7 为例)调用 getComputedStyle 会出现找不到该方法的问题),已经在高版本 IE 获得支持:

The value of the property "getComputedStyle" is null or undefined, not a Function object

顾名思义该方法用于获得元素的动态计算属性,此处在 windows 对象上显式挂载包含 Failover 的 getComputedStyle 方法,使得该方法不存在时的调用代码仍可继续运行,不行成阻塞。更详细的多浏览器兼容方案可以通过阅读 jQuery css API 源码找到。

此模块包含的设计思路即为Failover 预 catch以匹配降级方案

从该问题中可以引申出一个常见问题,CSSOM 的浏览器支持程度远远低于 DOM 的支持程度,W3C 对于 Document Object Model (DOM) Level 2 Style Specification 的声明早已于 2000 年末时刻完成,然而 CSSOM 的官方标准 CSS Object Model (CSSOM) 由于 CSS 3 多管道演进的实现方式影响,仍未推出厂商公认的实际标准,因此对于 CSSOM 的操作设计与跨浏览器兼容性测试,jQuery 仍有极好的参考价值。同时,开源社区中也存在大量的 Polyfill(腻子脚本)用于对低版本浏览器通过 JavaScript 附加逻辑的方式附加较新潮的特性,可以在 Modernizr/Modernizr 类似的代码源中找到。阅读 Polyfill 往往可以获得对 原型链和 JS 面向对象设计思维的更深刻认识,以及更深层次的设计技巧,以如下的一个 IE 8 opacity 属性的 Polyfill 函数为例,完成该函数的技巧已经远远超越了自身实现的功能:

// 正则表达式,匹配满足 alpha 定义规则的字符串
var opacityre = /s*alphas*(s*opacitys*=s*(d+)s*)/;

// 原型链挂载,直接将 opacity 放入 CSSStyleDeclaration 中
defineProperty(window.CSSStyleDeclaration.prototype, "opacity", {

  // getter 函数,自定义 toString 方法
  get: function() {
    var m = this.filter.match(opacityre);
    return m ? (m[1] / 100).toString() : "";
  },
  
  // setter 函数,将 opacity 值写入 alpha(opacity=$value) 的形式,供浏览器使用
  set: function(value) {
    this.zoom = 1;
    var found = false;
    if (value < 1) {
      value = " alpha(opacity=" + Math.round(value * 100) + ")";
    } else {
      value = "";
    }
    this.filter = this.filter.replace(opacityre, function() {
      found = true;
      return value;
    });
    if (!found && value) {
      this.filter += value;
    }
  }
});

此脚本包含的设计思路为利用 Getter/Setter 控制不同上下文中属性的设置与获取,同样的思路即为 Vue.js 数据绑定的设计源泉。

IOS 3 模块 / 语言特性 Polyfill

Zepto 默认编译中未包含的 IOS 3 模块 src/ios3.js 包含了两个函数的兼容实现,实际上属于语言特性 Polyfill,这类 Polyfill 主要用于解决语言发展与实现不同步等问题,并提供一些实现良好的公共方法用于业务开发,最常见的两类例子:

Lodash / Underscore 提供大量实现良好的工具函数

TypeScript 提供类型系统,实际这门语言也可被当做 Polyfill 看,因为 ECMAScript 提案中,已经包含了一个静态类型系统 的建议

IOS 3 模块中的两个 Polyfill 分别为 String / Array 两个包装类原型上挂载了一个常见方法:

    // Line 6
    String.prototype.trim = function() {
      // 将字符串首末的空格剪除
      return this.replace(/^s+|s+$/g, "");
    };

该方法原始定义于 ES 5 标准中的 String.prototype.trim(),此处实现依赖 ES 5 标准中的 White Space 中的描述。该方法实现相对简单,同时也提示了一个设计常识:向公认的 API 靠齐,实现方法核心后提供方法扩展,遵循该原则的包括:

Preact 与 React

Zepto 与 jQuery

Lodash 与 Underscore 等

trim() 函数较为简单明确,而 reduce() 方法的实现与 ES 5 中的 Array.prototype.reduce(callbackfn[,initialValue]) 定义的算法完全相同,更能体现这一原则,此段不进行注释,进入 ES 5 规范中该函数定义即可对照理解该 Polyfill 的实现方法。

  // Line 11
  if (Array.prototype.reduce === undefined)
    Array.prototype.reduce = function(fun) {
      // 略
    };
Detect 模块 / User Agent 识别

Detect 模块用于识别浏览器平台类型,默认也不处于编译列表中,其代码 src/detect.js 组织结构如下:

// Line 5
;(function($){

  // 平台侦测逻辑
  function detect(ua, platform){
  }

  // 传入 Zepto 及平台环境变量
  detect.call($, navigator.userAgent, navigator.platform)
  // make available to unit tests
  $.__detect = detect

// 将全局变量 Zepto 带入,化为参数 "$"
})(Zepto)

平台侦测逻辑 function detect(ua, platform) 内部为一组大的字符串判断逻辑,形成这样杂乱无章的平台判断逻辑,正是因为一代一代的浏览器大战。 User-Agent 字符串被定义为包含了当前浏览器(规范名称 User Agent)信息的 HTTP 头部标识,用于使服务器可以根据平台完成浏览器检测并下发不同的原始代码用于渲染。由于浏览器伪装等各种原因,UA 实际并不可信,因此对于它的侦测相当困难,常见 UA 可以从 List of User Agents 页面内查询到。

Zepto 没有默认编译该模块,以及利用该模块判断后提供平台相关逻辑的主要原因在于其设计原则:20% 的代码完成 jQuery 核心 80% 的功能。此处,也引出了代码实现的另一个基本原则:面向功能/API 标准,先功能覆盖再优雅降级。以提供一个常见的 Browser Compatibility Matrix 为例,根据实现规格测试前端产出在不同平台的可用性,再提供降级方案或 Polyfill 以满足更多的用户需求。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108707.html

相关文章

  • Zepto 源码分析 1 - 进入 Zepto

    摘要:选择的理由是一个用于现代浏览器的与大体兼容的库。环境搭建分析环境的搭建仅需要一个常规页面和原始代码一个常规页面打开的首页即可,在开发人员工具中即可使用原始代码本篇分析的代码参照,进入该代码分支中即可。 选择 Zepto 的理由 Zepto is a minimalist JavaScript library for modern browsers with a largely jQue...

    Aklman 评论0 收藏0
  • zepto源码分析-代码结构

    摘要:本来想学习一下的源码,但由于的源码有多行,设计相当复杂,所以决定从开始,分析一个成熟的框架的代码结构及执行步骤。同时发表在我的博客源码分析代码结构 本来想学习一下jQuery的源码,但由于jQuery的源码有10000多行,设计相当复杂,所以决定从zepto开始,分析一个成熟的框架的代码结构及执行步骤。 网上也有很多zepto的源码分析,有的给源码添加注释,有的谈与jQuery的不同,...

    sherlock221 评论0 收藏0
  • Zepto 源码分析 3 - qsa 实现与工具函数设计

    摘要:承接第一篇末尾内容,本部分开始进入主模块,分析其设计思路与实现技巧下文代码均进行过重格式化,但代码版本同第一部分内容且入口函数不变的选择器先从第一个与原型链构造不直接相关的工具函数说起,观察的设计思路。 承接第一篇末尾内容,本部分开始进入 zepto 主模块,分析其设计思路与实现技巧(下文代码均进行过重格式化,但代码 Commit 版本同第一部分内容且入口函数不变): Zepto 的选...

    ctriptech 评论0 收藏0
  • zepto.js 源码剖析

    摘要:正则首先看一下其中的正则表达的正则表达式要包含在中间。后面可以跟来表示是否进行全局匹配或者不区分大小写匹配。从句首开始匹配是一个,匹配一个空白字符,包括。 正则 首先看一下其中的正则表达: fragmentRE = /^s*]*>/, singleTagRE = /^(?:|)$/, tagExpanderRE = /]*)/>/ig, rootNodeRE = /^(?:body|h...

    winterdawn 评论0 收藏0
  • Zepto源码之代码结构

    摘要:源码结构整体结构如果在编辑器中将的源码折叠起来,看到的就跟上面的代码一样。参考源码分析代码结构对象思想与源码分析设计和源码分析源码中关于的问题最后,所有文章都会同步发送到微信公众号上,欢迎关注欢迎提意见 虽然最近工作中没有怎么用 zepto ,但是据说 zepto 的源码比较简单,而且网上的资料也比较多,所以我就挑了 zepto 下手,希望能为以后阅读其他框架的源码打下基础吧。 源码版...

    warkiz 评论0 收藏0

发表评论

0条评论

chuyao

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<