lodash

lodash 源码解读

2019-05-09  本文已影响0人  别过经年

以下代码都来自于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 是否是纯的(平的)对象

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类型将会强制转为字符串)。

mdn in

"" 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; }
上一篇 下一篇

猜你喜欢

热点阅读