功能

创建一个object对象自身可枚举属性的键🈯值对数组。如果Object是map或者set,返回其条目。

function Foo() {

  this.a = 1;

  this.b = 2;

}

Foo.prototype.c = 3;
_.toPairs(new Foo);

// => [['a', 1], ['b', 2]] 

源码实现

var createToPairs = require('./_createToPairs'),
    keys = require('./keys');

var toPairs = createToPairs(keys);

从这里来看先理解keys方法和createToPairs方法的实现。

keys就是_.keys方法,功能是创建一个object自身可枚举属性名的数组 (暂时解释,接下来会写一篇keys的文章)

toPairs来看,createToPairs接收一个函数返回一个方法。

func => object => {}

createToPairs

function createToPairs(keysFunc) {
  return function(object) {
    var tag = getTag(object);
    if (tag == mapTag) {
      return mapToArray(object);
    }
    if (tag == setTag) {
      return setToPairs(object);
    }
    return baseToPairs(object, keysFunc(object));
  };
}

module.exports = createToPairs;

keysFunc是用来获取给定对象object的keys的方法。对toPairstoPairsIn的区别就是keysFunc不同。

对于返回的函数

 function(object) {
    var tag = getTag(object);
    if (tag == mapTag) {
      return mapToArray(object);
    }
    if (tag == setTag) {
      return setToPairs(object);
    }
    return baseToPairs(object, keysFunc(object));
  };
}

对其来讲,setmap类型会分别由mapToArraysetToPairs来处理。除了二者的类型都会由baseToPairs处理。

在这之前,可以先了解下getTag的实现。

getTag

关于getTag百度出来一个很好的文章

在es5规范中,调用Object.prototype.totring会采用下面的步骤

  1. 如果 this 的值是 undefined, 返回 "[object Undefined]".
  2. 如果 this 的值是 null, 返回 "[object Null]".
  3. 令 O 为以 this 作为参数调用 ToObject 的结果 .
  4. 令 class 为 O 的 [[Class]] 内部属性的值 .
  5. 返回三个字符串 "[object ", class, and "]" 连起来的字符串

对es5来讲,除了undefinednull会返回[object Undefined]和[object Null]。

对于其它的类型,都会返回一个[Object [[class]]]的字符串。[[Class]]为内部属性的值。

在es6中的,没有了[[class]]这个内部属性,这部分逻辑可以查看深入理解Object.prototype.toString方法来理解。

对稳重的步骤17,需要引用一下令 tag 为 Get(O, @@toStringTag) 的返回值( Get(O, @@toStringTag) 方法,既是在 O 是一个对象,并且具有 @@toStringTag 属性时,返回 O[Symbol.toStringTag] )

let obj = {}

Object.defineProperty(obj, Symbol.toStringTag, {
    get: function() {
        return "newClass"
    }
})

console.log(Object.prototype.toString.call(obj)) 

// => [object newClass]

在es6规范table1中Symbol.toStringTag被解释为 该属性值是一个字符串,创建对象时它是对其的默认描述。通过Object.prototype.toString才能访问这个属性

也就是当调用Object.prototype.toString如果Symbol.toStringTag存在会返回它的属性值。

通过上边的这些认识,我们再去查看baseGetTag就容易理解了。

baseTag

function baseGetTag(value) {
  if (value == null) {
    return value === undefined ? undefinedTag : nullTag;
  }
  return (symToStringTag && symToStringTag in Object(value))
    ? getRawTag(value)
    : objectToString(value);
}

对于是symToStringTag会调用getRawTag方法,其它类型直接调用Object.prototype.toString返回tag
正如在es6规范所描述。

getRawTag

function getRawTag(value) {
  var isOwn = hasOwnProperty.call(value, symToStringTag),
      tag = value[symToStringTag];

  try {
    value[symToStringTag] = undefined;
    var unmasked = true;
  } catch (e) {}

  var result = nativeObjectToString.call(value);
  if (unmasked) {
    if (isOwn) {
      value[symToStringTag] = tag;
    } else {
      delete value[symToStringTag];
    }
  }
  return result;
}

getRawTag方法实际做的就是去除掉symToStringTag对获取tag的影响。先通过value[symToStringTag] = undefined;移除掉该属性。再通过nativeObjectToString.call(value)获取其tag.

if (unmasked) {
    if (isOwn) {
      value[symToStringTag] = tag;
    } else {
      delete value[symToStringTag];
    }
  }

这段代码也很简单,做了一个修正。

总结

toParis依次调用了toParis,getTag,baseTag,getRawTag.

至于Object.prototype.toString的由来可结合代码再自行体会。
参考


最普通的一个
301 声望41 粉丝

永远不要做你擅长的事。