• javascript监听数组变化



    /**
    * js中的new()到底做了些什么?
    * 1,创建一个新对象
    * 2,将构造函数里面的作用域赋值给新对象(因为this指向了新对象)
    * 3,执行构造函数里面代码
    * 4,返回新对象
    */
    function Base() {
    this.name = 'xiaoming';

    }
    var obj = new Base();
    /**
    * 解释上面的
    */
    var obj = {};
    obj._proto_ = Base.prototype;
    Base.call(obj);

    /**
    * constructor:每个实例对象所拥有的属性,的值返回创建此对象的函数数组的引用,
    * instanceof:用来检测这个实例是不是有这类创建的(new出来的)
    */

    function A() { };
    var a = new A();
    alert(a instanceof A);// true

    // 用来检测当前对象的_proto_属性是否指向了创建它的对象的prototype所指向的那块内存
    function A() { };
    var a = new A();
    a.__proto__ = {};
    alert(a instanceof A);// false

    /**
    * Object.creat(proto [, propertiesObject ])
    * 有二个属性,第一个属性继承了原型的属性,第二个参数是对象属性的描述
    */

    // 获取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 () {
    console.log('监听到数组的变化啦!');

    // 调用对应的原生方法并返回结果(新数组长度)
    return original.apply(this, arguments);
    }
    });

    let list = [1, 2];
    // 将我们要监听的数组的原型指针指向上面定义的空数组对象
    // newArrProto的属性上定义了我们封装好的push,pop等方法
    list.__proto__ = newArrProto;
    list.push(3); // 监听到数组的变化啦! 3
    /**
    * 使用es6的模式继承 监听变化
    */
    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]
    /**
    * 寄生式继承
    */
    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));
    // ArrayOfMine {} 0 true false
    newList.push(3);
    console.log(newList, newList.length, newList instanceof Array, Array.isArray(newList));
    // ArrayOfMine [3]0: 3length: 1__proto__: Array 1 true false
    /**
    * 为什么将父类改成Array就行不通了呢?因为Array构造函数执行时不会对传进去的this做任何处理。
    *
    */
    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);

    /**
    * 最终监听数组的总结
    */

    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;
    })

    })
    pasting
    http://www.51xuediannao.com/javascript/javascriptjtszbh_1258.html
  • 相关阅读:
    java-以月为单位,得到一年中某一个月份的范围
    计算两个时间段相差几个月(包含相差的哪些月份)
    单个进程最大线程数
    Dell PowerEdge R720内存安装原则
    Java [parms/options] range -b 100 -c 10 -i 100 -t 300 -s 180
    PhysicalDrive
    classpath和环境变量设置
    MySQL正则表达式
    MySQL模式匹配(LIKE VS REGEXP)
    ubuntu为什么没有/etc/inittab文件? 深究ubuntu的启动流程分析
  • 原文地址:https://www.cnblogs.com/yayaxuping/p/9925675.html
Copyright © 2020-2023  润新知