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.toStringbaseIsNative出错导致getTag被改造getTag依赖Function.prototype.toString,导致结果错误cloneDeep依赖getTag判断目标的类型,对象被认为是函数,所以返回空对象