/**
 
  
 * 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