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

猜你喜欢

转载自www.cnblogs.com/yayaxuping/p/9925675.html