携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第15天,点击查看活动详情
前言
获取原生方法主要通过一个名为getNative的内部方法去获取,该方法内部会对传入的参数进行判断,而getNative方法虽然是内部方法,但是在对外暴露的方法实现中很多都借用了该方法去实现,且实现getNative方法借助到的工具函数在很多方法实现中也常常使用,所以单独一篇章讲解getNative以及其相关方法的实现。
获取全局对象
在lodash内部提供了一个root方法可以获取全局对象。
由于在浏览器环境下存在一个self变量会返回一个指向当前 window 对象的引用,所以当环境存在self类型是对象时并且self存在一个Object的值与环境中的Object相同,则返回该self变量作为环境变量root。
同理,由于node环境存在global变量,所以判断global变量,成立的话便返回。
对于兼容性问题,则调用Function('return this')()返回环境变量。
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
var root = freeGlobal || freeSelf || Function('return this')();
判断当前环境是否有corejs的标记
corejs会在当前环境注入变量标记__core-js_shared__,所以通过判断该变量是否存在即可。
var coreJsData = root['__core-js_shared__'];
var maskSrcKey = (function() {
var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
return uid ? ('Symbol(src)_1.' + uid) : '';
}());
function isMasked(func) {
return !!maskSrcKey && (maskSrcKey in func);
}
获取一个对象的值
当想要获取一个对象的值时,可以使用getValue方法,该方法仅在lodash内部使用,在方法内部处理了错误数据可能造成的报错问题。
function getValue(object, key) {
return object == null ? undefined : object[key];
}
获取函数的源代码
获取函数的源代码可以通过toSource方法处理,该方法仅在lodash内部使用,通过调用Function.prototype.toString.call方法获取函数代码片段,如果为null则返回空字符串。
var funcProto = Function.prototype;
var funcToString = funcProto.toString;
function toSource(func) {
if (func != null) {
try {
return funcToString.call(func);
} catch (e) {}
try {
return (func + '');
} catch (e) {}
}
return '';
}
判断是否是原生方法
这里主要用到了前面讲解到的isObject、isMasked、isFunction判断方法。
判断原生方法的原理是由于调用Function.prototype.toString.call之后,如果是原生方法,会带有[native code]字段。
Function.prototype.toString.call(Object.prototype.hasOwnProperty)
// => 'function hasOwnProperty() { [native code] }'
Function.prototype.toString.call(Object.prototype.hasOwnProperty).replace(/[\^$.*+?()[]{}|]/g,'\$&').replace(/hasOwnProperty|(function).*?(?=\()| for .+?(?=\])/g, '$1.*?') + '$'
// => 'function.*?\(\) \{ \[native code\] \}$'
如果参数不等于对象或者是标记的corejs代码则返回false;如果参数是其他类型,则调用正则匹配结果。
其中对于函数类型会用reIsNative 的匹配规则,而其他类型则用reIsHostCtor的匹配规则。
var reRegExpChar = /[\^$.*+?()[]{}|]/g;
var reIsHostCtor = /^[object .+?Constructor]$/;
var funcProto = Function.prototype,
objectProto = Object.prototype;
var funcToString = funcProto.toString;
var hasOwnProperty = objectProto.hasOwnProperty;
/** 验证是否为本地方法 */
var reIsNative = RegExp('^' +
funcToString.call(hasOwnProperty).replace(reRegExpChar, '\$&')
.replace(/hasOwnProperty|(function).*?(?=\()| for .+?(?=\])/g, '$1.*?') + '$'
);
function baseIsNative(value) {
if (!isObject(value) || isMasked(value)) {
return false;
}
var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
return pattern.test(toSource(value));
}
获取原生方法
getNative方法可以获取原生方法,通过传递一个对象和一个key,如果对象是原生方法则返回相应的值,不是的话则返回undefined。
这里调用了baseIsNative方法进行判断处理。
function getNative(object, key) {
var value = getValue(object, key);
return baseIsNative(value) ? value : undefined;
}
小结
我们通过多个内部方法实现getNative方法,在lodash中大多数方法是存在公用的情况。
实现getNative方法有助于我们在后边实现其他暴露的方法直接调用。