在Vue源代码中发现5个有趣的JavaScript

阅读著名框架的源代码可以帮助程序员提高其专业技能。这篇文章的作者(我们今天将要翻译的翻译版本)最近分析了vue2.x代码。他在这段代码中发现了一些有趣的JavaScript想法,并决定与所有人分享。



1.确定任何对象的确切类型


大家都知道,在JavaScript中有六种基本数据类型(BooleanNumberStringNullUndefinedSymbol),和一个对象类型- Object您知道如何区分不同对象值的类型吗?对象可以是数组或函数,也可以是值Map或其他东西的集合。为了找到对象的确切类型需要做什么?

寻找一个回答这个问题之前,让我们想想之间的差异Object.prototype.toString.call(arg)String(arg)

这些表达式的用途旨在将传递给它们的参数转换为字符串。但是它们的工作方式不同。

调用时,String(arg)系统将尝试调用arg.toString()arg.valueOf()。结果,arg无论是在原型还是在原型中arg这些方法将被覆盖,调用Object.prototype.toString.call(arg)String(arg)给出不同的结果。

考虑一个例子。

const _toString = Object.prototype.toString
var obj = {}
obj.toString()  // [object Object]
_toString.call(obj) // [object Object]

我们将在浏览器开发人员工具控制台中执行此代码。


在这种情况下,调用obj.toString()Object.prototype.toString.call(obj)会导致相同的结果。

这是另一个例子。

const _toString = Object.prototype.toString
var obj = {}
obj.toString = () => '111'
obj.toString()  // 111
_toString.call(obj) // [object Object]
/hello/.toString() // /hello/
_toString.call(/hello/) // [object RegExp]

让我们在控制台中执行代码。


现在,调用对象的方法.toString()并使用构造会Object.prototype.toString.call(obj)产生不同的结果。

以下是描述ECMAScript标准中方法行为的规则Object.prototype.toString()


ECMAScript标准中Object.prototype.toString()方法的描述

查看文档,我们可以得出结论,当调用Object.prototype.toString()不同的对象时,将返回不同的结果。

在控制台中探索这个想法。


此外,返回的值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"

在控制台中探索此功能。


如您所见,使用上面的函数,您可以找到对象变量的确切类型。

在这里,在Vue存储库中,您可以找到类似功能的代码。

2.缓存函数的结果


假设有一个类似于以下的函数执行冗长的计算:

function computed(str) {    
    console.log('2000s have passed')
    return 'a result'
}

通过创建这样的函数,我们打算缓存返回给它的结果。下次调用此函数时,如前所述传递相同的参数,将不会执行“繁重的”功能代码。相反,将返回缓存的结果,而无需任何额外的时间。怎么做?

例如,您可以为目标函数编写包装函数。可以给这样的函数起一个名字cached该函数接受目标函数作为参数,并返回一个具有缓存功能的新函数。在函数中,cached您可以使用实体Object缓存对目标函数的先前调用的结果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]
  }
}

这是使用上述功能的示例。


→  这是 Vue代码库中可用的类似功能的代码。

3.将格式为hello-world的字符串转换为格式为helloWorld的字符串


当几个程序员在同一个项目上一起工作时,对他们来说,照顾代码的统一样式非常重要。例如,某人可以用格式记录一些复合标识符helloWorld,而某人可以用格式记录hello-world为了给这个区域带来订单,您可以创建一个功能转换查看hello-world线路图线helloWorld

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

这是此示例来自Vue代码的位置。

4.确定运行JavaScript代码的环境


如今,随着浏览器的快速发展,JavaScript代码可以在各种环境中执行。为了更好地使项目适应不同的环境,您需要能够确定程序的执行位置:

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+)/)

这是我找到此代码的地方。

5.内置功能和用户定义功能之间的区别


众所周知,JavaScript具有两种功能。第一种类型是内置的,或者也称为“本机”函数。这些功能由执行代码的环境提供。第二种类型是所谓的“用户功能”,即程序员自己编写的那些功能。您可以区分这些函数,并考虑到将它们转换为字符串时会返回各种结果的事实。

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())
}

→  这是 Vue代码库中具有此功能的位置。

通过探索著名JavaScript项目存储库中的代码,您是否设法找到了一些有趣的东西?


All Articles