收藏
回答

当使用插件时候,数组不能通过修改原型覆盖数组方法

问题类型 插件 AppID 插件版本号 AppID 微信版本 基础库版本
Bug wx6cec2d42cc7f81e0 0.2.5 wx6cec2d42cc7f81e0 6.5.3 2.7.0

- 当前 Bug 的表现(可附上截图)


当使用插件时候,数组不能通过修改原型覆盖数组方法。造成`mpvue`等基于响应式数组的框架运行不正常


TL;DR 根据下面运行情况,猜测:在微信小程序使用插件时候,数组创建时候,数组的方法会被重新赋值一次,而不是原型继承,造成使用__proto__继承的Vue响应式数组没法按预期执行。

分别在未使用插件和使用插件(App.json中有plugins字段)的情况下执行下面代码

const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)
Object.defineProperty(arrayMethods, 'push', {
  value(...args) {
    console.log('Modified push', args)
  },
  enumerable: false,
    writable: true,
    configurable: true
})
arrayMethods.aaaaaa = 'arrayMethods' // 做个标记
const foo = [];
foo.__proto__ = arrayMethods
foo.push(100) // 未使用插件: Modified push ; 使用插件: 和Array.prototype.push一样

这时候可以打印下foo变量

未使用插件的foo

使用插件的foo

由上可知,使用插件时候,所有数组实例都会直接挂载数组方法(覆盖隐式原型__proto__没用)

另外如果你去打印foo.__proto__ === arrayMethods,值是true,不过隐式原型并没有被覆盖(这不重要哈)

foo.__proto__ === arrayMethods // true

源码(core/observer/index.js#L48-L51)可知Vue在覆盖数组方法时候,会有两种情况

  1. 如果支持隐式原型(即hasProto = '__proto__' in {}为true),则通过覆盖隐式原型

  2. 否则,直接覆盖数组对象方法

无论在什么情况下,小程序hasProto都为true,但又无法通过覆盖隐式原型,把数组方法替换为响应式方法,因此造成响应式数组没法按预期执行


- 预期表现


与未使用插件的小程序表现一致


- 复现路径


- 提供一个最简复现 Demo


相关issue: https://github.com/Meituan-Dianping/mpvue/issues/1554


const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)
Object.defineProperty(arrayMethods, 'push', {
  value(...args) {
    console.log('Modified push', args)
  },
  enumerable: false,
    writable: true,
    configurable: true
})
arrayMethods.aaaaaa = 'arrayMethods' // 做个标记
const foo = [];
foo.__proto__ = arrayMethods
foo.push(100) // 未使用插件: Modified push ; 使用插件: 和Array.prototype.push一样


最后一次编辑于  2019-05-27
回答关注问题邀请回答
收藏

1 个回答

  • 疯狂的小辣椒
    疯狂的小辣椒
    2019-05-27

    你好,麻烦提供能复现问题的代码片段(https://developers.weixin.qq.com/miniprogram/dev/devtools/minicode.html)

    2019-05-27
    有用
    回复
登录 后发表内容