热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

js正则匹配闭合标签_我从Vue源码中学到的一些JS编程技巧

在我们面试的过程中,经常会遇到问源码的环节,因为优秀的框架通常都会包含很多设计理念跟编程实践。这段时间我一直在看Vue2的源码,发现了很多

在我们面试的过程中,经常会遇到问源码的环节,因为优秀的框架通常都会包含很多设计理念跟编程实践。这段时间我一直在看Vue2的源码,发现了很多有意思的实现。虽然现在Vue3都已经发布了,也无法否认Vue2是个优秀的框架这个事实,不影响我们从中学到一些最佳实践。

Vue不感兴趣的同学也可以看看,因为我只是谈论一些我从这个框架的实现上学到的一些Javascript的用法,不涉及Vue的概念。

  1. 获取HTML格式的字符串中非标签文本(vue/src/compiler/parser/entity-decoder.js)

假设我们有这样一个字符串:

var html = 'hello world hello xxx'。我们现在想要提取其中非标签的文本,拿到如下结果:

'hello world hello xxx'。这该怎么办?我们首先想到的肯定是正则表达式,但是这个场景下正则表达式写起来肯定很烦,我们来看看Vue的开发者是怎么处理的:

  • 既然这个字符串是HTML文本格式,我们就可以把它解析成对应的HTML元素。

  • HTML元素的textContent属性可以用来获取HTML元素中的文本内容。

代码如下:

function decoder(html){
  let decoder = document.createElement('div')
  decoder.innerHTML = html
  console.log(decoder.textContent)
  // return decoder.textContent
}

这个代码创建了一个div元素作为容器,然后通过设置innerHTML把字符串转换成对应的HTML元素,最后就可以通过textContent属性来获取文本内容了。

6512bf543b584f5fc726878c6387fba6.png
  1. 确定运行环境(vue/src/core/util/env.js)

随着前端的高速发展,我们已经可以在多个环境中运行Javascript代码,为了针对不同的运行环境作出调整,我们需要知道我们的代码跑在哪个环境下,我们来看看Vue是怎么确定运行时环境的:

const inBrowser = typeof window !== 'undefined'
const inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform
const weexPlatform = inWeex && WXEnvironment.platform.toLowerCase()
const UA = inBrowser && window.navigator.userAgent.toLowerCase()
const isIE = UA && /msie|trident/.test(UA)
const isIE9 = UA && UA.indexOf('msie 9.0') > 0
const isEdge = UA && UA.indexOf('edge/') > 0
const isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android')
const isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios')
const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge
const isPhantomJS = UA && /phantomjs/.test(UA)
const isFF = UA && UA.match(/firefox\/(\d+)/)

如果我们的代码是运行在浏览器中,那我们肯定会拿到一个window对象,所以我们可以通过const inBrowser = typeof window !== 'undefined'这种方式来判断环境。

b536215a32cdaa148f03d1ae599b80a1.png
c9c94fea8b117ac39237539f6a11ed63.png

而且在浏览器中,我们可以通过window对象拿到浏览器的userAgent,

91872fc5b67902c7d3845f4d89757b96.png

不同的浏览器对应的userAgent也不同,像IEuserAgent总是会包含MSIE,而ChromeuserAgent会包含Chrome。类似地安卓系统的浏览器userAgent就会带Android。那我们通过userAgent就可以判断当前用的是什么浏览器,运行在什么操作系统上。上面的代码中已经列举出了对主流的浏览器跟操作系统的判断,注意由于Edge浏览器最新版本也基于Chromium内核,所以它的userAgent也会包含Chrome,所以我们要写const isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge这样的代码来判断当前环境是Chrome
  1. 确定一个函数是不是用户自定义的(vue/src/core/util/env.js)

一般我们使用的就两种函数,环境提供给我们的跟我们用户自己定义的,这两种函数在转换成字符串时表现形式是不同的:

Array.isArray.toString() // "function isArray() { [native code] }"
function fn(){} 
fn.toString() // "function fn(){}"

环境自带函数调用toString方法后总是会返回类似function fnName() { [native code] }格式的字符串,我们可以利用这一点来区分函数类型:

function isNative (Ctor){
  return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
}

  1. 实现只执行一次的函数(vue/src/shared/util.js)

很多时候我们需要一个函数只被执行一次,就算它被调用多次,也只有第一次调用时会被执行,所以我们可以写出如下代码:

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

这样后续再执行时我们会直接跳过,这里是使用高阶函数来实现的,感兴趣的可以看看我之前的文章Javascript高级技巧。我们来测试一下这个方法:

29fed328c208c5100aef9a3fab5675bd.png

可以看到test方法只被执行了一次。

  1. 缓存函数执行结果(vue/src/shared/util.js)

这个我也在之前的博客中提到过的,有时候函数执行比较耗时,我们想缓存执行的结果。这样当后续被调用时,如果参数相同,我们可以跳过计算直接返回结果。我们需要的就是实现一个cached函数,这个函数接受实际被调用的函数作为参数,然后返回一个包装的函数。在这个cached函数里,我们可以用一个对象或者Map来缓存结果。

function cached(fn){
  const cache = Object.create(null);
  return function cachedFn (str) {
    if ( !cache[str] ) {
        let result = fn(str);
        cache[str] = result;
    }
    return cache[str]
  }
}

fcdf33544e956bcf0eb32173c256367e.png
  1. 转换命名风格(vue/src/shared/util.js)

我们每个人使用的编程风格可能都不一样,有人喜欢驼峰写法,有人喜欢小横杠连接符,为了解决这个问题,我们可以写一个函数去做统一的转换。(比如把a-b-c转换成aBC)

const camelizeRE = /-(\w)/g
const camelize = cached((str) => {
  return str.replace(camelizeRE, (_, c) => c ? c.toUpperCase() : '')
})
camelize('a-b-c')
// "aBC"

  1. 确定对象的类型(vue/src/shared/util.js)

在Javascript中,有六种基本类型(Boolean, Number, String, Null, Undefined, Symbol)跟一个对象类型,但其实对象类型是可以细分到许多类型的,一个对象可以是数组,也可以是函数等等。我们有没有办法获得它确切的类型呢?

我们可以利用Object.prototype.toString把一个对象转换成一个字符串,如果是我们用{}创建的对象,这个方法总是返回[object Object]

0b620556db527ea432190f008feab27a.png

而对于数组,正则表达式等环境自带的对象类型,它们会返回不同的结果。

110424464259d8d4172bd08e565f1c07.png

基于这个特性我们可以判断一个对象是不是我们用{}创建的对象了:

function isPlainObject (obj){
  return Object.prototype.toString.call(obj) === '[object Object]'
}

而且我们注意到,Object.prototype.toString()的返回值总是以[object tag]的形式出现,如果我们只想要这个tag,我们可以把其他东西剔除掉,这边比较简单用正则或者String.prototype.slice()都可以。

function toRawType (value) {
    const _toString = Object.prototype.toString
    return _toString.call(value).slice(8, -1)
}
toRawType(null) // "Null"
toRawType(/sdfsd/) //"RegExp"

这样我们就可以拿到一个变量的类型了。

  1. 把值转换成字符串(vue/src/shared/util.js)

我们经常需要把一个值转换成字符串,在Javascript里面,我们有两种方式来得到字符串:

  • String()

  • JSON.stringify()

不过这两种方式的实现机制是不同的:

60a4d4600585c212b8a9620693f11115.png

我们看到,他们是基于完全不同的规则去转换字符串的,String(arg)会尝试调用arg.toString()或者arg.valueOf(),那么那我们该用哪个比较好?

  • 对于nullundefined,我们希望把它转成空字符串

  • 当转换一个数组或者我们创建的对象时,我们会使用JSON.stringify

  • 如果对象的toString方法被重写了,那我们会偏向使用String()

  • 其它情况下,一般都用String()

    为了匹配上面的需求,Vue开发者是这么实现的:

    function isPlainObject (obj){
    return Object.prototype.toString.call(obj) === '[object Object]'
    }
    function toString (val) {
    if(val === null || val === undefined) return ''
    if (Array.isArray(val)) return JSON.stringify(val)
    if (isPlainObject(val) && val.toString === Object.prototype.toString)
      return JSON.stringify(val)
    return String(val)
    }

    又是收获满满的一天,通过阅读优秀框架的代码实现可以快速地提高我们对语言的运用,加强我们对于一些特性的理解,总结出一些编程实践,我们的编程能力也在无形中得到质的飞跃,非常建议大家深入学习一门语言时就去阅读用那个语言实现的优秀代码。对于Javascript而言我们光讨论了Vue的这三个源码文件就学到这么多东西,还有比这更开心的事吗?希望本文也能给大家带来一些帮助,happy coding~



推荐阅读
  • vue使用
    关键词: ... [详细]
  • Html5-Canvas实现简易的抽奖转盘效果
    本文介绍了如何使用Html5和Canvas标签来实现简易的抽奖转盘效果,同时使用了jQueryRotate.js旋转插件。文章中给出了主要的html和css代码,并展示了实现的基本效果。 ... [详细]
  • 【shell】网络处理:判断IP是否在网段、两个ip是否同网段、IP地址范围、网段包含关系
    本文介绍了使用shell脚本判断IP是否在同一网段、判断IP地址是否在某个范围内、计算IP地址范围、判断网段之间的包含关系的方法和原理。通过对IP和掩码进行与计算,可以判断两个IP是否在同一网段。同时,还提供了一段用于验证IP地址的正则表达式和判断特殊IP地址的方法。 ... [详细]
  • 单页面应用 VS 多页面应用的区别和适用场景
    本文主要介绍了单页面应用(SPA)和多页面应用(MPA)的区别和适用场景。单页面应用只有一个主页面,所有内容都包含在主页面中,页面切换快但需要做相关的调优;多页面应用有多个独立的页面,每个页面都要加载相关资源,页面切换慢但适用于对SEO要求较高的应用。文章还提到了两者在资源加载、过渡动画、路由模式和数据传递方面的差异。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 成功安装Sabayon Linux在thinkpad X60上的经验分享
    本文分享了作者在国庆期间在thinkpad X60上成功安装Sabayon Linux的经验。通过修改CHOST和执行emerge命令,作者顺利完成了安装过程。Sabayon Linux是一个基于Gentoo Linux的发行版,可以将电脑快速转变为一个功能强大的系统。除了作为一个live DVD使用外,Sabayon Linux还可以被安装在硬盘上,方便用户使用。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 网址:https:vue.docschina.orgv2guideforms.html表单input绑定基础用法可以通过使用v-model指令,在 ... [详细]
  • VueCLI多页分目录打包的步骤记录
    本文介绍了使用VueCLI进行多页分目录打包的步骤,包括页面目录结构、安装依赖、获取Vue CLI需要的多页对象等内容。同时还提供了自定义不同模块页面标题的方法。 ... [详细]
  • 如何在HTML中获取鼠标的当前位置
    本文介绍了在HTML中获取鼠标当前位置的三种方法,分别是相对于屏幕的位置、相对于窗口的位置以及考虑了页面滚动因素的位置。通过这些方法可以准确获取鼠标的坐标信息。 ... [详细]
  • JavaScript和HTML之间的交互是经由过程事宜完成的。事宜:文档或浏览器窗口中发作的一些特定的交互霎时。能够运用侦听器(或处置惩罚递次来预订事宜),以便事宜发作时实行相应的 ... [详细]
  • macOS Big Sur全新设计大版本更新,10+个值得关注的新功能
    本文介绍了Apple发布的新一代操作系统macOS Big Sur,该系统采用全新的界面设计,包括图标、应用界面、程序坞和菜单栏等方面的变化。新系统还增加了通知中心、桌面小组件、强化的Safari浏览器以及隐私保护等多项功能。文章指出,macOS Big Sur的设计与iPadOS越来越接近,结合了去年iPadOS对鼠标的完善等功能。 ... [详细]
  • 本文介绍了一种图片处理应用,通过固定容器来实现缩略图的功能。该方法可以实现等比例缩略、扩容填充和裁剪等操作。详细的实现步骤和代码示例在正文中给出。 ... [详细]
  • 本文讨论了使用HTML5+JS开发App所需的框架和工具推荐,希望能提供真实案例作为参考。重点考虑框架和工具的文档齐全性以及是否支持二维码扫描、摇一摇等功能。同时提到了H5+框架的适用性。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有