lodash在小程序中未正常工作
在微信小程序中引入了lodash库,然后调用了cloneDeep
方法去拷贝一个对象,但是函数却返回了空对象!最后通过调试,发现原因在于小程序并未实现Function.prototype.toString
的方法。在开发者社区上提问,得到了微信官方的确认,确实存在问题。他们给出了一个解决办法,在app.js中加上代码(一定要加在lodash前面):
|
|
具体分析
cloneDeep
会调用baseClone
,而baseClone
会调用getTag
方法去获得拷贝目标的类型,从而判断目标能否拷贝。当他发现拷贝对象是对象时(getTag({value:1})返回’[object Object]’),就会调用对应函数创建新对象。
|
|
getTag
起初就是Object.prototype.toString
。但是lodash为了使得getTag
在各种环境下都能正常工作,有可能会对getTag
函数做一些改造。而是否修改是基于以下条件的:
|
|
这些DataView
、Map
、Promise
、Set
、WeakMap
都是取的原生函数,而不是polyfill的结果。所以在正常情况下,由于小程序并未定义任何这些函数,结果都是undefined
。由于条件不成立,getTag
还是Object.prototype.toString
。getTag({value:1})
的结果是[object Object]
,结果正常。但是不幸的是,在获取这些原生类时,出错了!
在获取原生类时,lodash会调用baseIsNative
方法来确认是不是原生类。而判断是不是原生的原理就是首先对一个标准的原生函数调用Function.prototype.toString
获得源码,之后去掉函数源码的头尾得到[native code]
作为比较的标准,再对需要判断的函数也调用Function.prototype.toString
,掐掉头尾和之前的标准对比,查看是否一致。由于在小程序中,Function.prototype.toString
就是Object.prototype.toString
,lodash得到的比较标准就会是[object Function]
,而需要判断的函数也会得到[object Function]
,lodash错误把所有东西都认为是原生的了!baseIsNative
总是返回true
。
由于baseIsNative
的错误,我们得到了Promise
。所以lodash对getTag
进行了改造。
|
|
改造了就改造了,正常情况下也是能够正常工作的,那又是哪里出问题了?问题就出在toSource上,现在的toSource返回的不再是函数源码了,而是调用Object.prototype.toString的结果。当value是对象时,ctorString得到错误的结果[object Function]
,而各种比较的标准也是通过toSource
得到的,Promise
由于存在,在调用toSource
后得到的也是[object Function]
。最终,getTag({value:1})返回的结果就成了’[object
Promise]’。baseClone一看,这怎么拷贝?给你一个空对象好了。
总结
- 在app.js第一行加上
Function.prototype.toString = Object.getPrototypeOf(function(){})
就能解决lodash引用错误的问题 Function.prototype.toString
未定义,直接继承了Object.prototype.toString
baseIsNative
出错导致getTag
被改造getTag
依赖Function.prototype.toString
,导致结果错误cloneDeep
依赖getTag
判断目标的类型,对象被认为是函数,所以返回空对象