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