读zepto核心源码学习JS笔记(4)--内部方法

根据第一篇整体框架,可以知道$()方法返回的Z函数的实例化;而Z的原型又指向$.fn;所以经过$()处理过的对象,都可以使用$.fn中的方法;
这一篇就记录一下读$.fn的笔记;

zepto.Z.prototype = Z.prototype = $.fn

一 内部函数

1. zepto.match

  //判断一个元素是否匹配给定的选择器
zepto.matches = function(element, selector) {
    //如果selector,element没值或者element是普通节点
    if (!selector || !element || element.nodeType !== 1) return false
    var matchesSelector = element.matches || element.webkitMatchesSelector ||
                          element.mozMatchesSelector || element.oMatchesSelector ||
                          element.matchesSelector
    if (matchesSelector) return matchesSelector.call(element, selector)
    // fall back to performing a selector:
    var match, parent = element.parentNode, temp = !parent
    if (temp) (parent = tempParent).appendChild(element)
    match = ~zepto.qsa(parent, selector).indexOf(element)
    temp && tempParent.removeChild(element)
    return match
 }
  • 如果浏览器支持matchesSelector方法,则用此方法进行判断
QQ截图20170610142612.png
QQ截图20170610171446.png
  • 如果浏览器不支持matchesSelector,则定义matchparent变量,其中parentelement的父元素,如果没有父元素,则创建一个div容器当作其父元素

    tempParent = document.createElement('div'),

    match = ~zepto.qsa(parent, selector).indexOf(element)

    qsa()函数之前已经说明,若element不存在zepto.qsa(parent, selector).中,则返回-1,~-1即为0,即match最终的值为false

    element存在,则返回非零的值,转换为布尔值为true

二 $.fn

constructor

constructor: zepto.Z,

  • 这就涉及到原型和构造函数的知识.之后会当作一个专题来记录;这里只做简单介绍;
var person = function(name){
this.name = name;
}
var siva = new Person('Siva');
siva .__proto__ == person.prototype //true
person.prototype.constructor == person //true

由于zepto.Z.prototype = $.fn ;因此$.fn的构造函数即为zepto.Z

forEach

forEach: emptyArray.forEach,

  • 之前已经说过,emptyArray为定义的一个空数组,所以这里的forEach即为Array.prototype.forEach,可以理解为数组自带的forEach方法;

reduce,push,sort,splice,indexOf

reduce: emptyArray.reduce,
push: emptyArray.push,
sort: emptyArray.sort,
splice: emptyArray.splice,
indexOf: emptyArray.indexOf,
  • 道理同上

get

get: function(idx){
//如果不传参,将Z对象转为数组, slice.call()在第三篇已经提到过;数组自有的slice;
//如果传参小于0,就将传的参数转换为idx加上传入对象的长度;即为倒数返回;
//例如传入的值为-1;则选取最后一个元素
  return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]
},

在分析这句话之前,我们先看看get的用法;

QQ截图20170610142612.png
QQ截图20170610142642.png

toArray

//将Z对象集合转换成数组
toArray: function(){ return this.get() },
  • 不传参调用get()

concat

concat: function(){
  var i, value, args = []
  for (i = 0; i < arguments.length; i++) {
    value = arguments[i]
    //如果其中传入的参数为Z对象,则将其转为数组;并将值传给arg
    args[i] = zepto.isZ(value) ? value.toArray() : value
  }
  //apply方法将this强制绑定到调用concat的对象身上
  //如果调用concat的是Z对象,则将其转换成数组
  return concat.apply(zepto.isZ(this) ? this.toArray() : this, args)
},
  • 添加元素到一个Zepto对象集合形成一个新数组。如果参数是一个数组,那么这个数组中的元素将会合并到Zepto对象集合中。

  • arguments为传入的参数组合;

  • 这个方法并没有像上面的reduce,push,sort,splice,等直接复制Array.prototype的属性,是因为调用此事件的对象并不一定为数组,如果调用的对象为$();则是类数组对象,而不是真正的数组,如果直接调用数组的concat,则会将$();当作数组的一个item合并起来,所以此方法需要重新封装

slice

slice: function(){
//同上,将this强制绑定到调用的对象身上;
  return $(slice.apply(this, arguments))
},

ready

ready: function(callback){
//判断dom是否ready,如果已经ready,直接执行函数
  if (readyRE.test(document.readyState) && document.body) callback($)
  //否则注册监听器;
  else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false)
  return this
},
  • readyRE = /complete|loaded|interactive/,

  • document.readyState返回当前文档的状态,该属性返回四个值;分别为:

    • uninitialized - 还未开始载入
    • loading - 载入中
    • interactive - 已加载,文档与用户可以开始交互 ---仅DOM加载完成,不包括样式表,图片,flash,触发DOMContentLoaded事件
    • complete - 载入完成 ---页面上所有的DOM,样式表,脚本,图片,flash都已经加载完成了,开始触发load事件

size

size: function() {
  return this.length
},
  • 返回所选集合的length属性的值;

each

each: function(callback){
  emptyArray.every.call(this, function(el, idx){
    return callback.call(el, idx, el) !== false
  })
  //可以使用链式操作
  return this
},
  • 方法内部调用了every,当callback的值返回false的时候就会中止循环;

eq

eq: function(idx){
  return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1)
},
  • 当idx为-1的时候.取最后一个;

first

first: function(){
  var el = this[0]
  return el && !isObject(el) ? el : $(el)
},
  • this[0] 取集合中的第一个值;
  • return el && !isObject(el) ? el : $(el) 如果集合中第一个数据为对象的话返回本身,否则转换成zepto对象

last

last: function(){
  var el = this[this.length - 1]
  return el && !isObject(el) ? el : $(el)
},
  • 同上

add

add: function(selector,context){
  return $(uniq(this.concat($(selector,context))))
},
uniq = function(array){ 
    return filter.call(array, 
    function(item, idx){ return array.indexOf(item) == idx })
}
  • 添加元素到当前匹配的元素集合中

  • uniq中的filter在之前已经定义;filter = emptyArray.filter,即为Array.prototype.filter

    • Array.prototype.filter的用法
      var words = ["spray", "limit", "elite", "exuberant", "destruction", "present"];
      var longWords = words.filter(function(word){
        return word.length > 6;
      })
      // Filtered array longWords is ["exuberant", "destruction", "present"]
      
  • uniq的作用是给数组去重,如果数组中的数据在数组中的位置不等于索引值,说明这个数据在数组中出现过两次以上,我们再利用filter函数,只取出位置和索引值相同的那个;

map

map: function(fn){
  return $($.map(this, function(el, i){ return fn.call(el, i, el) }))
},

remove

remove: function(){
  return this.each(function(){
    if (this.parentNode != null)
      this.parentNode.removeChild(this)
  })
},
  • 从其父节点中删除当前集合中的元素,有效的从dom中移除。

is

is: function(selector){
  return this.length > 0 && zepto.matches(this[0], selector)
},
  • 判断当前元素集合中的第一个元素是否符css选择器。
  • match在开头已经写过了;

not

not: function(selector){
  var nodes=[]
  //当selector为函数时,但是safari下的typeof odeList也是function,
  //所以这里需要再加一个判断selector.call !== undefined
  if (isFunction(selector) && selector.call !== undefined)
    this.each(function(idx){
    //当selector.call(this,idx)返回结果为false,记录;
      if (!selector.call(this,idx)) nodes.push(this)
    })
  else {
  //当selector为字符串的时候,筛选满足selector的记录;
    var excludes = typeof selector == 'string' ? this.filter(selector) :
    //当selector为类数组,将其变为数组,否则,执行$()
      (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector)
    this.forEach(function(el){
    //筛选出不在excludes中的数据
      if (excludes.indexOf(el) < 0) nodes.push(el)
    })
  }
  //以上得到的是数组,将其转换成zepto对象;
  return $(nodes)
},
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容