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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM