阅读著名框架的源代码可以帮助程序员提高其专业技能。这篇文章的作者(我们今天将要翻译的翻译版本)最近分析了vue2.x代码。他在这段代码中发现了一些有趣的JavaScript想法,并决定与所有人分享。
1.确定任何对象的确切类型
大家都知道,在JavaScript中有六种基本数据类型(Boolean
,Number
,String
,Null
,Undefined
,Symbol
),和一个对象类型- 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()
_toString.call(obj)
我们将在浏览器开发人员工具控制台中执行此代码。在这种情况下,调用obj.toString()
和Object.prototype.toString.call(obj)
会导致相同的结果。这是另一个例子。const _toString = Object.prototype.toString
var obj = {}
obj.toString = () => '111'
obj.toString()
_toString.call(obj)
/hello/.toString()
_toString.call(/hello/)
让我们在控制台中执行代码。现在,调用对象的方法.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)
toRawType(/sdfsd/)
在控制台中探索此功能。如您所见,使用上面的函数,您可以找到对象变量的确切类型。→ 在这里,在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')
→ 这是此示例来自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 fn(){}
fn.toString()
我们将在控制台中试用此代码。本toString()
机函数方法始终返回以下形式的构造:function fnName() { [native code] }
知道了这一点,您可以编写一个函数,以区分本地函数和用户定义函数:function isNative (Ctor){
return typeof Ctor === 'function' && /native code/.test(Ctor.toString())
}
→ 这是 Vue代码库中具有此功能的位置。通过探索著名JavaScript项目存储库中的代码,您是否设法找到了一些有趣的东西?