lodash 源码解读
以下代码都来自于4.17.11-es分支
1. isObjectLike
function isObjectLike(value) {
return value != null && typeof value == 'object';
}
export default isObjectLike;
两行代码,少到令人发指的地步,这样看来只有普通对象{},数组[],还有内置类型的实例(比如 new Date(), new Regex(),new String('geek')),可以是伪对象
2. isObject
/**
* Checks if `value` is the
* [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
*
* @static
* @memberOf _
* @since 0.1.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
* @example
*
* _.isObject({});
* // => true
*
* _.isObject([1, 2, 3]);
* // => true
*
* _.isObject(_.noop);
* // => true
*
* _.isObject(null);
* // => false
*/
function isObject(value) {
var type = typeof value;
return value != null && (type == 'object' || type == 'function');
}
export default isObject;
isObject代码也就三行,比isObjectLike多了个条件,就是函数也被认为是对象,这就是广义上的对象
3. isPlainObject 是否是纯的(平的)对象

import baseGetTag from './_baseGetTag.js';
import getPrototype from './_getPrototype.js';
import isObjectLike from './isObjectLike.js';
/** `Object#toString` result references. */
var objectTag = '[object Object]';
/** Used for built-in method references. */
var funcProto = Function.prototype,
objectProto = Object.prototype;
/** Used to resolve the decompiled source of functions. */
var funcToString = funcProto.toString;
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
/** Used to infer the `Object` constructor. */
var objectCtorString = funcToString.call(Object);
/**
* Checks if `value` is a plain object, that is, an object created by the
* `Object` constructor or one with a `[[Prototype]]` of `null`.
*
* @static
* @memberOf _
* @since 0.8.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
* @example
*
* function Foo() {
* this.a = 1;
* }
*
* _.isPlainObject(new Foo);
* // => false
*
* _.isPlainObject([1, 2, 3]);
* // => false
*
* _.isPlainObject({ 'x': 0, 'y': 0 });
* // => true
*
* _.isPlainObject(Object.create(null));
* // => true
*/
function isPlainObject(value) {
if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
return false;
}
var proto = getPrototype(value);
if (proto === null) {
return true;
}
var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
return typeof Ctor == 'function' && Ctor instanceof Ctor &&
funcToString.call(Ctor) == objectCtorString;
}
export default isPlainObject;
该函数是用来判断一个对象是否是通过Object构造函数new出来的,或者他的原型链__proto__
是null,其中baseGetTag是用来准确判断数据的类型,baseGetTag函数没有直接对外暴露出来,但是很有用
3.1 _baseGetTag 私有函数
import Symbol from './_Symbol.js';
import getRawTag from './_getRawTag.js';
import objectToString from './_objectToString.js';
/** `Object#toString` result references. */
var nullTag = '[object Null]',
undefinedTag = '[object Undefined]';
/** Built-in value references. */
var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
/**
* The base implementation of `getTag` without fallbacks for buggy environments.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the `toStringTag`.
*/
function baseGetTag(value) {
if (value == null) {
return value === undefined ? undefinedTag : nullTag;
}
return (symToStringTag && symToStringTag in Object(value))
? getRawTag(value)
: objectToString(value);
}
export default baseGetTag;
Object(value))
这里有个疑惑,一般这么执行是强制类型转换,但是这里也是强制类型转换吗?
在《你不知道的JavaScript 中》36页找到了答案,
如果想要自行封装基本类型值,可以使用 Object(..) 函数(不带 new 关键字):
var a = "abc";
var b = new String( a );
var c = Object( a );
typeof a; // "string"
typeof b; // "object"
typeof c; // "object"
b instanceof String; // true
c instanceof String; // true
Object.prototype.toString.call( b ); // "[object String]"
Object.prototype.toString.call( c ); // "[object String]"
再次强调,一般不推荐直接使用封装对象(如上例中的 b 和 c),但它们偶尔也会派上
用场。
var s= Symbol("s")
Symbol.toStringTag in Object(s)// true
关于in操作符
prop in object
prop
一个字符串类型或者 symbol 类型的属性名或者数组索引(非symbol类型将会强制转为字符串)。
"" instanceof String // false
居然返回false ,instanceof需要好好理解下
3.2 _objectToString 私有函数,精确获取数据的类型
精确获取数据的类型,比如
Object.prototype.toString.call([]) // "[object Array]"
/** Used for built-in method references. */
var objectProto = Object.prototype;
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString = objectProto.toString;
/**
* Converts `value` to a string using `Object.prototype.toString`.
*
* @private
* @param {*} value The value to convert.
* @returns {string} Returns the converted string.
*/
function objectToString(value) {
return nativeObjectToString.call(value);
}
export default objectToString;
上面声明一堆变量,其实可以简写成一句
function objectToString(value) {
return Object.prototype.toString.call(value);
}
export default objectToString;
3.3 _root
获得全局对象
import freeGlobal from './_freeGlobal.js';
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
export default root;
Function('return this')();
这句话最有意思,Function('return this')
其实就是创建个函数function(){return this}
,然后后面的括号是立即执行该函数,拿到当前宿主全局对象,node的global或者浏览器的window,在红宝书中134页有提到用这种办法拿全局对象,但是写法有点不同罢了,
var global = function(){
return this;
}();
你不知道的JavaScript 中册40页提到的另一种创建函数的方式
var e = new Function( "a", "return a * 2;" );
也就是将Function作为构造函数使用,得到的结果等同于
var f = function(a) { return a * 2; }
function g(a) { return a * 2; }