/**
* 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;
})
})
http://www.51xuediannao.com/javascript/javascriptjtszbh_1258.html
