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