uni-app instanceof Array 在某种情况下出错
uni-app instanceof Array 在某种情况下出错
开发环境 | 版本号 | 项目创建方式 |
---|---|---|
Windows | win10 | HBuilderX |
操作步骤:
预期结果:
实际结果:
bug描述:
对数组进行判断,在某些情况下出现不准确的现象; 如下图1: 对象res是通过ajax返回来的object中的一个属性,其本身也应该是数组。但是通过获取构造函数“constructor”后于Array比较的出 false的结论。 定义对象 a 为一个数组,遍历res后,变元素push给a,同样方式判断a,它就是一个数组。
但是 打印 res.constructor 和 a.constructor 都的出结果是“function Array() { [native code] }”,但是res.constructor === Array 结果为false,而a.constructor === Array 则为 true;
图2: 图2是res的结构,以及来源。“res”来源于拦截器中"data"对象中的"data"属性
这就涉及到了内存地址不同导致的比较结果不同了。
uni对象和你本地定义的变量存在于不同的地方
首先两个数组对象直接打印的contructor当然是为Function Array.这是毋庸置疑的。
然而:强等于===比较的一般是内存的地址,本地和服务器的数组对象的constructor都各有自己的内存地址
你在res里面获取到数组示例,实际上是一个新的实例(经过序列化与反序列化处理之后),
因为res是在uni.request()方法那里构造出来的
所以res的constructor的内存地址指向的是uni的同一环境下的内存地址(假设为0000fff
而arr则是你本地另外一个内存环境内存地址(假设为0000fee
总结:这两个对象的constructor的内存地址是不同的。
const arr = [1];
console.log(arr.constructor === Array);// 0000fff === 0000fff 两个相等
console.log(arr.constructor);//function Array √
//res为服务器获取过来的数组对象
console.log(res.constructor === Array);// 0000fee === 0000fff 两个不相等
console.log(res.constructor);//function Array √
也就是说 res只有在服务器本地执行res.constructor===Array输出才为true
在 uni-app
中,instanceof Array
在某些情况下可能会出错,尤其是在跨页面或跨组件传递数据时。这是因为 uni-app
的页面和组件之间的数据传递是通过序列化和反序列化进行的,这可能会导致对象的原型链丢失,从而导致 instanceof
检查失败。
常见问题场景
-
跨页面传递数组:当你从一个页面传递一个数组到另一个页面时,
uni-app
会将数组序列化为 JSON 字符串,然后在目标页面反序列化。反序列化后的数组可能不再继承自Array
的原型链,因此instanceof Array
会返回false
。 -
跨组件传递数组:类似地,当你在父组件和子组件之间传递数组时,
uni-app
也可能会对数组进行序列化和反序列化,导致instanceof Array
检查失败。
解决方案
-
使用
Array.isArray
:Array.isArray
是一个更可靠的方法来检查一个对象是否是数组,因为它不依赖于原型链。if (Array.isArray(myArray)) { console.log('This is an array'); } else { console.log('This is not an array'); }
-
避免跨页面/组件传递复杂对象:如果可能,尽量避免在页面或组件之间传递复杂的对象。可以通过
Vuex
或全局变量来共享数据,这样可以避免序列化和反序列化的问题。 -
手动恢复原型链:如果你确实需要跨页面或组件传递数组,并且需要保持原型链,可以在目标页面或组件中手动恢复原型链。
myArray.__proto__ = Array.prototype;
但这种方法并不推荐,因为它可能会引入其他问题。
示例代码
// 页面A
let myArray = [1, 2, 3];
uni.navigateTo({
url: '/pages/pageB?data=' + JSON.stringify(myArray)
});
// 页面B
onLoad(options) {
let myArray = JSON.parse(options.data);
if (Array.isArray(myArray)) {
console.log('This is an array');
} else {
console.log('This is not an array');
}
}