Zepto 实现原理

理解 Zepto 的架构设计和 $ 函数的实现方式

问题

Zepto 是一个轻量级的 JavaScript 库,API 与 jQuery 兼容。它的实现原理是什么?

解答

整体架构

Zepto 的核心是 $ 函数,它返回一个包含 DOM 元素的类数组对象,并通过原型链提供各种操作方法。

// 简化版 Zepto 实现
var Zepto = (function() {
  var $, zepto = {};
  
  // Zepto 对象构造函数
  function Z(dom, selector) {
    var len = dom ? dom.length : 0;
    for (var i = 0; i < len; i++) {
      this[i] = dom[i];
    }
    this.length = len;
    this.selector = selector || '';
  }
  
  // 初始化方法
  zepto.Z = function(dom, selector) {
    return new Z(dom, selector);
  };
  
  // 判断是否为 Zepto 对象
  zepto.isZ = function(object) {
    return object instanceof Z;
  };
  
  // 核心:将选择器转换为 DOM 数组
  zepto.qsa = function(element, selector) {
    return Array.prototype.slice.call(
      element.querySelectorAll(selector)
    );
  };
  
  // 初始化入口
  zepto.init = function(selector, context) {
    var dom;
    
    // 空选择器,返回空 Zepto 对象
    if (!selector) {
      return zepto.Z();
    }
    
    // 字符串选择器
    if (typeof selector === 'string') {
      selector = selector.trim();
      
      // HTML 字符串,创建 DOM 元素
      if (selector[0] === '<') {
        dom = zepto.fragment(selector);
      } else {
        // CSS 选择器,查询 DOM
        dom = zepto.qsa(context || document, selector);
      }
    }
    // DOM 元素
    else if (selector.nodeType) {
      dom = [selector];
    }
    // 数组或类数组
    else if (Array.isArray(selector)) {
      dom = selector;
    }
    // Zepto 对象,直接返回
    else if (zepto.isZ(selector)) {
      return selector;
    }
    // 函数,DOM ready 后执行
    else if (typeof selector === 'function') {
      return $(document).ready(selector);
    }
    
    return zepto.Z(dom, selector);
  };
  
  // $ 函数
  $ = function(selector, context) {
    return zepto.init(selector, context);
  };
  
  // 原型方法挂载点
  $.fn = {
    constructor: zepto.Z,
    length: 0,
    
    // 遍历方法
    each: function(callback) {
      Array.prototype.every.call(this, function(el, idx) {
        return callback.call(el, idx, el) !== false;
      });
      return this;
    },
    
    // 查找子元素
    find: function(selector) {
      var result = [];
      this.each(function() {
        var nodes = zepto.qsa(this, selector);
        result = result.concat(Array.prototype.slice.call(nodes));
      });
      return zepto.Z(result, selector);
    },
    
    // 添加 class
    addClass: function(name) {
      return this.each(function() {
        this.classList.add(name);
      });
    },
    
    // 设置/获取 CSS
    css: function(property, value) {
      if (value === undefined) {
        return this[0] && this[0].style[property];
      }
      return this.each(function() {
        this.style[property] = value;
      });
    },
    
    // 事件绑定
    on: function(event, callback) {
      return this.each(function() {
        this.addEventListener(event, callback, false);
      });
    }
  };
  
  // 关键:将 $.fn 设为 Z 的原型
  zepto.Z.prototype = Z.prototype = $.fn;
  
  return $;
})();

// 暴露到全局
window.Zepto = Zepto;
window.$ = Zepto;

使用示例

// 选择元素
$('.item').addClass('active');

// 链式调用
$('#box')
  .css('color', 'red')
  .on('click', function() {
    console.log('clicked');
  });

// DOM ready
$(function() {
  console.log('DOM 加载完成');
});

// 创建元素
$('<div class="new">新元素</div>').appendTo('body');

原型链结构

$('.item') 返回的对象

Z 实例 { 0: element, 1: element, length: 2 }
    ↓ __proto__
$.fn (包含 each, find, css, on 等方法)
    ↓ __proto__
Object.prototype

关键点

  • 类数组对象:Zepto 对象本质是包含 DOM 元素的类数组,有 length 属性和数字索引
  • $ 函数多态:根据参数类型(字符串、DOM、函数、数组)执行不同逻辑
  • 原型链设计$.fn 作为所有 Zepto 对象的原型,方法定义在此处实现共享
  • 链式调用:方法返回 this(Zepto 对象本身)实现链式操作
  • 轻量化:相比 jQuery,Zepto 去掉了 IE 兼容代码,体积更小,适合移动端