vue源码中值得学习的方法

2023-10-30


作者:chinamasters   https://segmentfault.com/a/1190000025157159

最近在深入研究vue源码,把学习过程中,看到的一些好玩的的函数方法收集起来做分享,希望对大家对深入学习js有所帮助。如果大家都能一眼看懂这些函数,说明技术还是不错的哦。

1. 数据类型判断

Object.prototype.toString.call()返回的数据格式为 [object Object]类型,然后用slice截取第8位到倒一位,得到结果为 Object

var _toString = Object.prototype.toString;
function toRawType (value) {
  return _toString.call(value).slice(8, -1)
}

运行结果测试

toRawType({}) //  Object 
toRawType([])  // Array    
toRawType(true) // Boolean
toRawType(undefined) // Undefined
toRawType(null) // Null
toRawType(function(){}) // Function

2. 利用闭包构造map缓存数据

vue中判断我们写的组件名是不是html内置标签的时候,如果用数组类遍历那么将要循环很多次获取结果,如果把数组转为对象,把标签名设置为对象的key,那么不用依次遍历查找,只需要查找一次就能获取结果,提高了查找效率。

function makeMap (str, expectsLowerCase) {
    // 构建闭包集合map
    var map = Object.create(null);
    var list = str.split(',');
    for (var i = 0; i < list.length; i++) {
      map[list[i]] = true;
    }
    return expectsLowerCase
      ? function (val) { return map[val.toLowerCase()]; }
      : function (val) { return map[val]; }
}
// 利用闭包,每次判断是否是内置标签只需调用isHTMLTag
var isHTMLTag = makeMap('html,body,base,head,link,meta,style,title')
console.log('res', isHTMLTag('body')) // true

3. 二维数组扁平化

vue中_createElement格式化传入的children的时候用到了simpleNormalizeChildren函数,原来是为了拍平数组,使二维数组扁平化,类似lodash中的flatten方法。

// 先看lodash中的flatten
_.flatten([1, [2, [3, [4]], 5]])
// 得到结果为  [1, 2, [3, [4]], 5]

// vue中
function simpleNormalizeChildren (children) {
  for (var i = 0; i < children.length; i++) {
    if (Array.isArray(children[i])) {
      return Array.prototype.concat.apply([], children)
    }
  }
  return children
}

// es6中 等价于
function simpleNormalizeChildren (children) {
   return [].concat(...children)
}

4. 方法拦截

vue中利用Object.defineProperty收集依赖,从而触发更新视图,但是数组却无法监测到数据的变化,但是为什么数组在使用push pop等方法的时候可以触发页面更新呢,那是因为vue内部拦截了这些方法。

 // 重写push等方法,然后再把原型指回原方法
  var ARRAY_METHOD = [ 'push', 'pop', 'shift', 'unshift', 'reverse',  'sort', 'splice' ];
  var array_methods = Object.create(Array.prototype);
  ARRAY_METHOD.forEach(method => {
    array_methods[method] = function () {
      // 拦截方法
      console.log('调用的是拦截的 ' + method + ' 方法,进行依赖收集');
      return Array.prototype[method].apply(this, arguments);
    }
  });

运行结果测试

var arr = [1,2,3]
arr.__proto__ = array_methods // 改变arr的原型
arr.unshift(6) // 打印结果: 调用的是拦截的 unshift 方法,进行依赖收集

5. 继承的实现

vue中调用Vue.extend实例化组件,Vue.extend就是VueComponent构造函数,而VueComponent利用Object.create继承Vue,所以在平常开发中VueVue.extend区别不是很大。这边主要学习用es5原生方法实现继承的,当然了,es6中 class类直接用extends继承。

  // 继承方法 
  function inheritPrototype(Son, Father) {
    var prototype = Object.create(Father.prototype)
    prototype.constructor = Son
    // 把Father.prototype赋值给 Son.prototype
    Son.prototype = prototype
  }
  function Father(name) {
    this.name = name
    this.arr = [1,2,3]
  }
  Father.prototype.getName = function() {
    console.log(this.name)
  }
  function Son(name, age) {
    Father.call(this, name)
    this.age = age
  }
  inheritPrototype(Son, Father)
  Son.prototype.getAge = function() {
    console.log(this.age)
  }

运行结果测试

var son1 = new Son("AAA", 23)
son1.getName()            //AAA
son1.getAge()             //23
son1.arr.push(4)          
console.log(son1.arr)     //1,2,3,4

var son2 = new Son("BBB", 24)
son2.getName()            //BBB
son2.getAge()             //24
console.log(son2.arr)     //1,2,3

6. 执行一次

once 方法相对比较简单,直接利用闭包实现就好了

function once (fn) {
  var called = false;
  return function () {
    if (!called) {
      called = true;
      fn.apply(this, arguments);
    }
  }
}

7. 浅拷贝

简单的深拷贝我们可以用 JSON.stringify() 来实现,不过vue源码中的looseEqual 浅拷贝写的也很有意思,先类型判断再递归调用,总体也不难,学一下思路。

function looseEqual (a, b) {
  if (a === b) { return true }
  var isObjectA = isObject(a);
  var isObjectB = isObject(b);
  if (isObjectA && isObjectB) {
    try {
      var isArrayA = Array.isArray(a);
      var isArrayB = Array.isArray(b);
      if (isArrayA && isArrayB) {
        return a.length === b.length && a.every(function (e, i) {
          return looseEqual(e, b[i])
        })
      } else if (!isArrayA && !isArrayB) {
        var keysA = Object.keys(a);
        var keysB = Object.keys(b);
        return keysA.length === keysB.length && keysA.every(function (key) {
          return looseEqual(a[key], b[key])
        })
      } else {
        /* istanbul ignore next */
        return false
      }
    } catch (e) {
      /* istanbul ignore next */
      return false
    }
  } else if (!isObjectA && !isObjectB) {
    return String(a) === String(b)
  } else {
    return false
  }
}
function isObject (obj) {
  return obj !== null && typeof obj === 'object'
}

就先分享这些函数,其他函数,后面继续补充,如有不对欢迎指正,谢谢!


最后

  • 欢迎加我微信(winty230),拉你进技术群,长期交流学习...

  • 欢迎关注「前端Q」,认真学前端,做个专业的技术人...

点个在看支持我吧

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue源码中值得学习的方法 的相关文章

随机推荐

  • selenium 淘宝爬虫(需要扫码登录一下)

    from selenium import webdriver import time import re def gethtml url 定义函数获取html源代码 由于淘宝是动态网页无法用requests库获取所以使用selenium模拟
  • Signature expired

    django 中使用itsdangerous加密时会出现 Signature expired 签名过期的问题 解决办法 expires in设置时间稍微长一点 然后重启pycharm 重新打开项目 比如设置expires in 3600 单
  • AI+林业重塑未来,科技力量守护森林生态宝

    引言 在科技日新月异的时代 人工智能 AI 作为一项崭新的技术 正在革新着我们社会的方方面面 素有 地球之肺 美誉的森林作为人类生存发展中不可或缺的一部分 其管理与保护也开始融入AI技术 催生出了AI 林业这一新兴领域 在AI 林业的浪潮中
  • RT_thread(二)线程的操作

    文章目录 重点 一 线程是什么 二 线程的工作机制 1 线程控制块 2 线程API 1 思维图 2 创建静态线程 3启动线程 4 静态线程脱离 5 创建动态线程 6 动态线程删除 7 使线程让出处理器资源 8 使线程休眠几个节拍 9 线程节
  • Log4j日志记录

    Log4j主要由Loggers 日志记录器 Appenders 输出器 和Layout 日志格式化器 组成 其中Loggers控制日志的输出级别与日志是否输出 Appenders指定日志的输出方式 输出到控制台 文件等 Loyout控制日志
  • 计算机网络03之三种可靠传输机制

    1 停止 等待协议 为什么要有停止 等待协议 答 除了比特出现差错 底层信道还会出现丢包问题 而且为了流量控制 停止 等待协议的原理 答 停止 等待 就是每发完一个分组就停止发送 等待接收端确认 在收到确认后才发送下一个分组 停止 等待协议
  • 网页基本常用标签

    一 标签 元素 1 表示网页的开始 2 网页的头部 3
  • Docker Hub

    Docker Hub是docker的中心仓库 Docker Hub里存储了公共的 Docker 镜像 并且提供服务来帮助你构建和管理你的 Docker 环境 Docker Hub和docker及其组件一起工作 Docker Hub会帮助你和
  • 石头扫地机器人离线了怎么办_关于激光头故障,石头扫地机器人无限次复活记!...

    关于激光头故障 石头扫地机器人无限次复活记 2019 08 17 19 15 41 61点赞 174收藏 82评论 小编注 此篇文章来自即可瓜分10万金币 周边好礼达标就有 邀新任务奖励无上限 点击查看活动详情 创作立场声明 本文记录的是个
  • 【Shell牛客刷题系列】SHELL17 将字段逆序输出文件的每行:巩固awk命令与学习反向列示文件内容的tac命令

    该系列是基于牛客Shell题库 针对具体题目进行查漏补缺 学习相应的命令 刷题链接 牛客题霸 Shell篇 该系列文章都放到专栏下 专栏链接为 专栏 Linux 欢迎关注专栏 本文知识预告 首先学习了反向列示文件内容的命令 tac 这个命令
  • cocos2dx lua 读取json数据

    这里读取的数据是从excel转成json格式的数据 local sData cc FileUtils getInstance getStringFromFile filename local var json decode sData if
  • 基于STM32F103ZET6的RX8025SA时钟电路设计

    1 现在网上大多例程都是关于RX8025T的 带温度补偿的时钟芯片手册 RX8025SA与RX8025T的区别 RX8025T内置高稳定性32 768kHz的DTCXO 数字温度补偿晶体振荡器 可保证在全温度范围内的精度保持在 5ppm R
  • #program once 和 #ifndef

    program once 和 ifndef 在写小demo的时候 注意到vs中会自动生成 program once 看别人写的代码的时候见到比较多的反而是 ifndef define endif 从字面上看两种方式会产生相同的效果 避免同一
  • C语言--__attribute__((aligned(n)))

    include
  • 用户态和内核态的转换

    用户态切换到内核态的3种方式 a 系统调用 这是用户态进程主动要求切换到内核态的一种方式 用户态进程通过系统调用申请使用操作系统提供的服务程序完成工作 比如前例中fork 实际上就是执行了一个创建新进程的系统调用 而系统调用的机制其核心还是
  • 网络打印机因IP地址变动导致脱机的解决方法

    PC版本win10 某一天因为种种原因导致网络打印机的IP变动了 那么我们在自己PC机上添加的打印机就无法使用了 来看作者是怎么解决的 假设目标IP由192 168 1 16改为192 168 2 195 打开我的打印机和扫面仪菜单
  • CSDN站外文章记录收藏

    序号 c opencv相关 1 OpenCV模板匹配算法详解 2 无参考图像质量评价算法Blind Image Quality Evaluation Using Perception Based Features 3 mtf calcula
  • SQLite 使用(针对Android)

    文章目录 1 SQLite 介绍 2 SQLite可视化工具 安装 3 SQLite的增删改查 3 1 SqliteOpenHelper 创建 库或表 3 2 SqliteOpenHelper 实现 增删改查 1 SQLite 介绍 SQL
  • HEVC编码结构:Slice和Tile

    1 Slice片段层 一幅图像可以被划分为一个或多个片或称为条带 Slice 每个片的数据编码都是独立的 如下图 一幅图像被划分为N个Slice Slice成条带形 在编码时 每一个Slice中的CTU按光栅扫描顺序进行编码 Slice头信
  • vue源码中值得学习的方法

    作者 chinamasters https segmentfault com a 1190000025157159 最近在深入研究vue源码 把学习过程中 看到的一些好玩的的函数方法收集起来做分享 希望对大家对深入学习js有所帮助 如果大家