郁闷吧 微信小程序 4188479 63242849 39070147 130690866
还没有任何记录...

山东福彩群英会预测专注于网页素材下载,提供网站模板、网页设计、ps素材、图片素材等 ,服务于【个人站长】【网页设计师 】和【web开发从业者 】的代码素材与设计素材网站。

山东福彩群英会预测提供网页素材下载、网站模板
这一切都是免费的 !
当前位置:山东福彩群英会预测 > 山东福彩群英会预测教程 >

山东福彩群英会预测山东福彩群英会预测

来源:oschina 作者: qiangdada 日期:2017-06-18 人气:
监听山东福彩群英会预测数组变化,从而改变数据是 mvvm框架必备功能 ,下面尝试使用不同的方法来实现js数组变化的监听

监听山东福彩群英会预测数组变化,从而改变数据是 mvvm框架必备功能 ,下面尝试使用不同的方法来实现js数组变化的监听。

山东福彩群英会预测山东福彩群英会预测思路

1、定义变量arrayProto接收Array的prototype
2、定义变量arrayMethods,通过Object.create()方法继承arrayProto
3、重新封装数组中push,pop等常用方法。(这里我们只封装我们需要监听的数组的方法 ,并不做JavaScript原生Array中原型方法的重写的这么一件暴力的事情 )
4、其他js数组变化监听方法​

js山东福彩群英会预测实现方法

这里我们首先需要确定的一件事情就是,我们只需要监听我们需要监听的数据数组的一个变更,而不是针对原生Array的一个重新封装。

其实代码实现起来会比较简短 ,这一部分代码我会直接带着注释贴出来

// 获取Array原型
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
const newArrProto = [];
[
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
].forEach(method => {
  // 原生Array的原型方法
  let original = arrayMethods[method];

  // 将push,pop等方法重新封装并定义在对象newArrProto的属性上
  // 这里需要注意的是封装好的方法是定义在newArrProto的属性上而不是其原型属性
  // newArrProto.__proto__ 没有改变
  newArrProto[method] = function mutator() {
    console.log('监听到数组的变化啦!');

    // 调用对应的原生方法并返回结果

(新数组长度)
    return original.apply(this, arguments);
  }
})

let list = [1, 2];
// 将我们要监听的数组的原型指针指向上面定义的空数组对象

// newArrProto的属性上定义了我们封装好的push,pop等方法
list.__proto__ = newArrProto;
list.push(3);  // 监听到数组的变化啦! 3

// 这里的list2没有被重新定义原型指针,所以这里会正常执行原生Array上的原型方法
let list2 = [1, 2];
list2.push(3);  // 3

目前为止我们已经实现了数组的监听。从上面我们看出 ,当我们将需要监听的数组的原型指针指向 newArrProto对象上的时候(newArrProto的属性上定义了我们封装好的push,pop等方法)。这样做的好处很明显,不会污染到原生 Array上的原型方法  。

其他js数组变化监听方法

1、分析实现的机制

从上面我们看出 ,其实我们做了一件非常简单的事情,首先我们将需要监听的数组的原型指针指向newArrProto,然后它会执行原生 Array中对应的原型方法  ,与此同时执行我们自己重新封装的方法。

那么问题来了 ,这种形式咋这么眼熟呢?这不就是我们见到的最多的继承问题么 ?子类(newArrProto)和父类(Array)做的事情相似 ,却又和父类做的事情不同 。但是直接修改__proto__隐式原型指向总感觉心里怪怪的(因为我们可能看到的多的还是 prototype),心里不(W)舒(T)服(F)。

那么接下来的事情就是尝试用继承 (常见的prototype)来实现数组的变更监听 

2、利用ES6的extends实现

首先这里我们会通过ES6的关键字extends实现继承完成 Array原型方法的重写,咱总得先用另外一种方式来实现一下我们上面实现的功能,证明的确还有其他方法可以做到这件事。OK,废话不多说,直接看代码

class NewArray extends Array {
  constructor(...args) {
    // 调用父类Array的constructor()
    super(...args)
  }
  push (...args) {
    console.log('监听到数组的变化啦!');

    // 调用父类原型push方法
    return super.push(...args)
  }
  // ...
}

let list3 = [1, 2];

let arr = new NewArray(...list3);
console.log(arr)
// (2) [1, 2]

arr.push(3);
// 监听到数组的变化啦!
console.log(arr)
// (3) [1, 2, 3]

3、ES5及以下的方法能实现 js山东福彩群英会预测吗?

OK,终于要回到我们常见的带有prototype的继承了,看看它究竟能不能也实现这件事情呢  。这里我们直接上最优雅的继承方式-寄生式组合继承,看看能不能搞定这件事情 。代码如下

/**
 * 寄生式继承	 继承原型
 * 传递参数 subClass 子类
 * 传递参数 superClass 父类
 */
function inheritObject(o){
  //声明一个过渡函数
  function F(){}
  //过渡对象的原型继承父对象
  F.prototype = o;
  return new F();
}
function inheritPrototype(subClass,superClass){
  //复制一份父类的原型副本保存在变量

  var p = inheritObject(superClass.prototype);
  //修正因为重写子类原型导致子类的constructor指向父类
  p.constructor = subClass;
  //设置子类的原型
  subClass.prototype = p;
}

function ArrayOfMine (args) {
  Array.apply(this, args);
}
inheritPrototype(ArrayOfMine, Array);
// 重写父类Array的push,pop等方法
ArrayOfMine.prototype.push = function () {
  console.log('监听到数组的变化啦!');
  return Array.prototype.push.apply(this, arguments);
}
var list4 = [1, 2];
var newList = new ArrayOfMine(list4);
console.log(newList, newList.length, newList instanceof Array, Array.isArray(newList));
newList.push(3);
console.log(newList, newList.length, newList instanceof Array, Array.isArray(newList));

目前我们这么看来,的的确确是利用寄生式组合继承完成了一个类的继承,那么console.log的结果又是如何的呢  ?是不是和我们预想的一样呢,直接看图说话吧
ES5及以下的方法能实现	js山东福彩群英会预测吗?

我擦嘞,这特么什么鬼,教练,我们说好的 ,不是这个结果。这是典型的买家秀和卖家秀吗?

那么我们来追溯一下为什么会是这种情况,我们预想中的情况应该是这样的 

newList => [1, 2]  newList.length => 2  Array.isArray(newList) => true

push执行之后的理想结果

newList => [1, 2, 3]  newList.length => 3  Array.isArray(newList) => true

我们先抛弃Array的apply之后的结果 ,我们先用同样的方式继承我们自定义的父类Father,代码如下

function inheritObject(o){
  function F(){};
  F.prototype = o;
  return new F();
}
function inheritPrototype(subClass,superClass){
  var p = inheritObject(superClass.prototype);
  p.constructor = subClass;
  subClass.prototype = p;
}

function Father() {
  // 这里我们暂且就先假定参数只有一个
  this.args = arguments[0];
  return this.args;
}
Father.prototype.push = function () {
  this.args.push(arguments);
  console.log('我是父类方法');
}
function ArrayOfMine () {
  Father.apply(this, arguments);
}
inheritPrototype(ArrayOfMine, Father);
// 重写父类Array的push,pop等方法
ArrayOfMine.prototype.push = function () {
  console.log('监听到数组的变化啦!');
  return Father.prototype.push.apply(this, arguments);
}
var list4 = [1, 2];
var newList = new ArrayOfMine(list4, 3);
console.log(newList, newList instanceof Father);
newList.push(3);
console.log(newList, newList instanceof Father);

结果如图

结果和我们之前预想的是一样的 ,我们自己定义的类的话  ,这种做法是可以行的通的 ,那么问题就来了,为什么将父类改成 Array就行不通了呢?

为了搞清问题 ,查阅各种资料后。得出以下结论:
因为Array构造函数执行时不会对传进去的 this做任何处理。不止Array,String,Number,Regexp,Object等等JS的内置类都不行 。。这也是著名问题 ES5及以下的JS无法完美继承数组  的来源,不清楚的小伙伴可以Google查查这个问题。那么,为什么不能完美继承呢 ?

1、数组有个响应式的length,一方面它会跟进你填入的元素的下表进行一个增长,另一方面如果你将它改小的话 ,它会直接将中间的元素也删除掉 

var arr1 = [1];
arr1[5] = 1;
console.log(arr1.length === 6);  // true
// 以及
var arr2 = [1,2,3];
arr2.length = 1
console.log(arr2);
// [1] 此时元素2,3被删除了

2、数组内部的 [[class]] 属性,这个属性是我们用Array.isArray(someArray)和Object.prototype.String.call(someArray) 来判定someArray是否是数组的根源 ,而这又是内部引擎的实现 ,用任何JS方法都是无法改变的。而为啥要用这两种方法进行数组的判定,相信大家从前面的代码结果可以看出来,利用instanceof去判定是否为数组 ,结果是有问题的。

因为数组其响应式的 length属性以及内部的 [[class]]属性我们无法再JS层面实现,这就导致我们无法去用任何一个对象来 “模仿”一个数组,而我们想要创建一个 ArrayOfMine继承Array的话又必须直接用Array的构造函数 ,而上面我提到了  Array构造函数执行时是不会对传进去的 this做任何处理,也就是说这样你根本就不能继承他 。而利用__proto__隐式原型的指针变更却能实现,因为他是一个非标准的属性 (已在ES6语言规范中标准化),详请请点击链接 __proto__

所以要实现最上面我们实现的功能 ,我们还是需要用到__proto__属性。变更后代码如下

function inheritObject(o){
  function F(){}
  F.prototype = o;
  return new F();
}
function inheritPrototype(subClass,superClass){
  var p = inheritObject(superClass.prototype);
  p.constructor = subClass;
  subClass.prototype = p;
}

function ArrayOfMine () {
  var args = arguments
    , len = args.length
    , i = 0
    , args$1 = [];   // 保存所有arguments
  for (; i < len; i++) {
    // 判断参数是否为数组
,如果是则直接concat
    if (Array.isArray(args[i])) {
      args$1 = args$1.concat(args[i]);
    }
    // 如果不是数组,则直接push到
    else {
      args$1.push(args[i])
    }
  }
  // 接收Array.apply的返回值,刚接收的时候arr是一个Array
  var arr = Array.apply(null, args$1);
  // 将arr的__proto__属性指向 ArrayOfMine的 prototype
  arr.__proto__ = ArrayOfMine.prototype;
  return arr;
}
inheritPrototype(ArrayOfMine, Array);
// 重写父类Array的push,pop等方法
ArrayOfMine.prototype.push = function () {
  console.log('监听到数组的变化啦!');
  return Array.prototype.push.apply(this, arguments);
}
var list4 = [1, 2];
var newList = new ArrayOfMine(list4, 3);
console.log(newList, newList.length, newList instanceof Array, Array.isArray(newList));
newList.push(4);
console.log(newList, newList.length, newList instanceof Array, Array.isArray(newList));

结果如图

自此,我所知道几种实现数组监听的方法便得于实现了。

js数组变化监听总结

总结以上几点方案,完整的数组监听代码如下

// Define Property  山东福彩群英会预测 http://www.vehicleheating.com/
function def (obj, key, val, enumerable) {
  Object.defineProperty(obj, key, {
    value: val,
    enumerable: !!enumerable,
    configurable: true,
    writable: true
  })
}
// observe array
let arrayProto = Array.prototype;
let arrayMethods = Object.create(arrayProto);
[
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
].forEach(method => {
  // 原始数组操作方法

  let original = arrayMethods[method];
  def(arrayMethods, method, function () {
    let arguments$1 = arguments;
    let i = arguments.length;
    let args = new Array(i);

    while (i--) {
      args[i] = arguments$1[i]
    }
    // 执行数组方法
    let result = original.apply(this, args);
    // 因 arrayMethods 是为了作为 Observer 中的 value 的原型或者直接作为属性,所以此处的 this 一般就是指向 Observer 中的 value
    // 当然,还需要修改 Observer,使得其中的 value 有一个指向
 Observer 自身的属性	,__ob__,以此将两者关联起来
    let ob = this.__ob__;
    // 存放新增数组元素
    let inserted;
    // 为add 进arry中的元素进行observe
    switch (method) {
      case 'push':
        inserted = args;
        break;
      case 'unshift':
        inserted = args;
        break;
      case 'splice':
        // 第三个参数开始才是新增元素
        inserted = args.slice(2);
        break;
    }
    if (inserted) {
      ob.observeArray(inserted);
    }
    // 通知数组变化

    ob.dep.notify();
    // 返回新数组长度
    return result;
  })

})

原文:https://my.oschina.net/qiangdada/blog/911252#comment-list
github:https://github.com/xuqiang521/overwrite/tree/master/my-mvvm

本文链接:山东福彩群英会预测山东福彩群英会预测http://www.vehicleheating.com/山东福彩群英会预测/山东福彩群英会预测jtszbh_1258.html

山东福彩群英会预测山东福彩群英会预测由山东福彩群英会预测收集整理,您可以自由传播,请主动带上本文链接 

山东福彩群英会预测就是免费分享,觉得有用就多来支持一下,没有能帮到您 ,懒人也只能表示遗憾 ,希望有一天能帮到您。

(责任编辑:山东福彩群英会预测)