美文网首页我爱编程
jQuery的实质, 自己写一个jQuery

jQuery的实质, 自己写一个jQuery

作者: Apolo_Du | 来源:发表于2018-01-07 04:00 被阅读102次

    jQuery 的实质:

    • 在了解了python的装饰器之后, 发现jQuery的本质就是一个装饰器, 只是它接受了不同的参数.
      • python装饰器接受一个函数, 在装饰器内部用一个函数(wrapper)将其包装, 并返回处理后的结果.
      • jQuery接受一个css选择器或dom对象作为参数, 返回一个包装后的对象(jQuery对象).

    自定义DOM API

    • 实现一个获取兄弟元素的API
      • 通过定义 length属性, 让函数返回值可迭代, 成为一个类数组对象.
     function getSiblings(node){
        var allChildren = node.parentNode.children
        var array = {length:0}
        for (let i =0; i<allChildren.length; i++){
        if(allChildren[i] !== item3){
          array[array.length] = allChildren[i]
          array.length += 1
        }
      }
    return array
    }
    
    • 实现一个可批量增加/删除 类的API
      我们可以使用点记法 obj.attr 或者 obj[attr] 来调用一个对象的成员
    function addClass(node, classes){
      for(let key in classes){
          var value = classes[key]
          var methodName = value?'add':'remove'
          node.classList[methodName](key)      
        }
    }
    
    • 实现一个命名空间
      • JS中并不提供原生的命名空间支持
      • 我们可以创建一个简单对象字面量来打包所有的相关函数和变量。
        • 这个简单对象字面量模拟了命名空间的作用。
        • 避免覆盖全局变量
        • 为我们自定的API提供了一个统一的入口
    window.myDom ={}
    myDom.addClass = addClass
    myDom.getSiblings = getSiblings
    
    • 让一个dom对象具有我们定义的API

      • 方法1:
        • 扩展 Node 接口, 在 Node.prototype上加函数.
        • 这个方法是不好的
    • 方法2:

      • 使用一个wrapper函数来包装这个对象并返回它, jQuery就是用这种的方式实现的
        • 接收一个dom对象, 返回一个新的jQuery对象.
        • jQuery 还能够区分传入的是字符串或是node节点
    window.Node2 = function(nodeOrSelector) {
      let node
      if (typeof nodeOrSelector === 'string') {
        node = document.querySelector(nodeOrSelector)
      } else {
        node = nodeOrSelector
      }
      return {
        getSiblings: function() {
          var allChildren = node.parentNode.children
          var array = {
            length: 0
          }
          for (let i = 0; i < allChildren.length; i++) {
            if (allChildren[i] !== item3) {
              array[array.length] = allChildren[i]
              array.length += 1
            }
          }
          return array
        },
        addClass: function(classes) {
          for (let key in classes) {
            var value = classes[key]
            var methodName = value ? 'add' : 'remove'
            node.classList[methodName](key)
          }
        }
      }
    }
    
    • 实现一个jQuery选择器
      • 我们要实现类似jQuery的功能, 每次都要能够获得一个jQuery对象这样的类数组对象.
        • 如果参数是一个字符串, 我们就通过 querySelectorAll 获取一个类数组对象
          • 迭代获得的对象, 将它的每一个元素放到新的对象中.
          • 要保证自定义的类数组对象有index下标和length属性. 这样它才是可迭代的
      • 如果参数是一个节点, 我们同样它放到一个具有 index 和 length的自定义类数组对象中.
    window.jQuery = function(nodeOrSelector) {
      let nodes = {}
      if (typeof nodeOrSelector === 'string') {
        let temp = document.querySelectorAll(nodeOrSelector)
          //我们不要nodeList, 要一个自定的类数组元素
        for (let i = 0; i < temp.length; i++) {
          nodes[i] = temp[i]
        }
        nodes.length = temp.length
      } else if (nodeOrSelector instanceof Node) {
        nodes = {
          0: nodeOrSelector,
          length: 1
        }
      }
    
    • 对选择器对象设置 getText 和 setText 方法
      • getText方法要返回一个可迭代对象.
        • 其中每个元素存储一个选择器元素的 textContent值
      • setText 方法要对选择器进行统一设置
        • 对选择器的内一个元素的 textContent 进行设置.
      nodes.getText = function() {
        let text = []
        for (let i = 0; i < nodes.length; i++) {
          text.push(nodes[i].textContent)
        }
        return text
      }
    
      nodes.setText = function(text) {
        for (let i = 0; i < nodes.length; i++) {
          nodes[i].textContent = text
        }
        return nodes
      }
    
    • jQuery 中的 getText 和 setText 方法
      • 在jQuery中, 两种方法被合并了, 通过判断是否有传参数, 来执行不同的代码语句
     nodes.text = function(text) {
        if (text === undefined) {
          let text = []
          for (let i = 0; i < nodes.length; i++) {
            text.push(nodes[i].textContent)
          }
          return text
        } else {
          for (let i = 0; i < nodes.length; i++) {
            nodes[i].textContent = text
          }
          return nodes
        }
      }
    
    • 这其实类似python中的 @property 和 @attr.setter, 为getter方法和setter方法 提供了一个统一的接口

      • @property装饰器
    • nodes.text 函数和闭包

      • nodes.text 函数内部没有声明 nodes变量, 而是引用了函数外部的变量, nodes.text 函数和 nodes变量就构成了一个闭包.
    • 自定义jQuery的完整代码:

    window.jQuery = function(nodeOrSelector) {
      let nodes = {}
      if (typeof nodeOrSelector === 'string') {
        let temp = document.querySelectorAll(nodeOrSelector)
          //我们不要nodeList, 要一个自定的类数组元素
        for (let i = 0; i < temp.length; i++) {
          nodes[i] = temp[i]
        }
        nodes.length = temp.length
      } else if (nodeOrSelector instanceof Node) {
        nodes = {
          0: nodeOrSelector,
          length: 1
        }
      }
    
      nodes.addClass = function(classes) {
        for (let key in classes) {
          var value = classes[key]
          var methodName = value ? 'add' : 'remove'
          for (let i = 0; i < nodes.length; i++) {
            nodes[i].classList[methodName](key)
          }
        }
      }
    
      nodes.text = function(text) {
        if (text === undefined) {
          let text = []
          for (let i = 0; i < nodes.length; i++) {
            text.push(nodes[i].textContent)
          }
          return text
        } else {
          for (let i = 0; i < nodes.length; i++) {
            nodes[i].textContent = text
          }
          return nodes
        }
      }
      return nodes
    }
    

    相关文章

      网友评论

        本文标题:jQuery的实质, 自己写一个jQuery

        本文链接:https://www.haomeiwen.com/subject/nszunxtx.html