目录javascript
@java
1.函数与函数的原型对象(prototype object):浏览器
(1) 构造函数-->原型对象 (A.prototype-->B)安全
(2) 原型对象-->构造函数 (B.constructor-->A)ecmascript
(3) 实例对象-->原型对象 (A1.[[Prototype]]/A1._ proto _-->B)
函数
2.基于三种引用的操做
如上图,咱们基于这三种引用会有许多的操做(修改,替换,删除),咱们来进行一个分析总结.性能
构造函数建立实例的具体过程
参考资料:
英文版--new [[Construct]] [[Call]]
中文版--new [[Construct]] [[Call]]
new A();
1.令ref = 构造函数A的引用(地址)
2.令变量constructor = GetValue(ref): 按照ref找到函数对象A的存储单元
3.调用constructor的[[Construct]]内部方法:测试
总结: 由上面的分析可知,若是在构造函数A的函数体内用this给实例添加的属性,是不会反映到原型上的,属于实例的自己的属性.this
三种引用是否能够被更改的测试
prototype
//TEST:三种引用是否均可以修改替换
function A (){}
var B = A.prototype;
var A1 = new A();
//A.prototype与B.constructor
console.log(Object.getOwnPropertyDescriptor(A,'prototype'));//可修改
console.log(Object.getOwnPropertyDescriptor(B,'constructor'));//可修改
//[[Prototype]]
console.log('prototype' in A1); //false,内部属性不属于原型属性
console.log(A1.hasOwnProperty('prototype'));//false,内部属性不属于自身属性
//只有获取方法,没有手动修改方法
//__ proto __
console.log(' __ proto __ ' in A1);
console.log(A1.hasOwnProperty(' __ proto __ '));//false, __ proto __ 属于原型属性
console.log(Object.prototype.hasOwnProperty(' __ proto __ '));//true,__ proto __ 定义在Object.prototype上
console.log(Object.getOwnPropertyDescriptor(Object.prototype, ' __ proto __ '));//configurable:true enumerable:false
//利用 __ proto __ 间接修改[[prototype]] (不推荐)
function C() {}
var D = C.prototype;
console.log(Object.getPrototypeOf(A1));
A1. __ proto __ = D; //利用非规范属性 __ proto __ 间接修改[[prototype]]
console.log(Object.getPrototypeOf(A1));
总结: __ proto __属性是非标准的,是定义在Object.prototype上的一个暴露实例内部[[prototype]]属性的访问器属性.若是咱们考虑到代码的安全和性能,咱们能够在代码开始位置用delete Objet.prototype. _ _ proto _ _
来删除掉.
替换构造函数A的原型--修改A.prototype的值
预计的影响:
1.已有实例的原型不变,但没法再用A.prototype添加或修改原型属性
2.新实例的原型是A.prototype修改后的值,而且能够用A.prototype添加或修改原型属性
//TEST:构造函数替换原型对象的影响
function A() {}
function B() {}
var A1 = new A();
var B1 = new B();
A.prototype.say = function (){
alert('A链的方法');
}
B.prototype.say = function (){
alert('B链的方法');
}
var temp = B.prototype;
B.prototype = A.prototype;
A.prototype = temp;
var A2 = new A();
var B2 = new B();
//检测A1 A2 B1 B2 各自的原型链
A1.say();
B1.say();
A2.say();
B2.say();
//尝试经过原有构造函数向A1添加原型属性
A.prototype.say2 = function (){
alert('仍能够经过A向A1添加原型属性');
}
A.prototype.say3 = function (){
alert('能够经过A向A2添加原型属性');
}
alert('say2' in A1);//false,A1.say2方法不存在.不能再经过A向A1添加原型属性
A2.say3();//添加成功
替换已有实例的原型
预计影响:
1.接上了另外一条原型链
2.没法再用A.prototype添加或修改原型属性
//TEST:已有实例对象修改原型对象的影响
function A() {}
function B() {}
var A1 = new A();
var B1 = new B();
A.prototype.say = function (){
alert('A链的方法');
}
B.prototype.say = function (){
alert('B链的方法');
}
//测试是否接到另外一条原型链
var A2 = Object.create(A1);
A2.say();
A2.__ proto __ = B1;
A2.say();
//测试是否不能再用原来的构造函数添加原型属性
var A3 = new A();
A3.__ proto __ = B1;
A.prototype.say2 = function (){
alert('仍然可用构造函数添加原型属性');
}
A3.say2(); //出错,A3中找不到方法say2()
替换原型的构造函数--A.prototype.constructor
影响:
1.只是没法再用A.prototype.constructor获取构造函数A,没法便捷地添加'静态方法'了
2.仍能正经常使用A建立实例,用A.prototype添加或修改原型属性
1.instanceof运算符
参考资料:instanceof [[HasInstance]](V)
instaceof运算符,是将左边对象的原型做为参数,来调用右边函数的[[HasInstance]] (V)内部方法,所得返回值即为运算符的结果.
[[HasInstance]] (V)方法大体过程:(以A.[[HasInstance]] (V)为例)
//TEST: instanceof原理测试:向上搜索实例的原型链,看由构造函数所指向的原型对象是否在其中
function A() {}
var A1 = new A();
var B = A.prototype;
console.log(A1 instanceof A);//true
B.constructor = null;
console.log(A1 instanceof A);//true
A.prototype = {};
console.log(A1 instanceof A);//false
2.属性遍历
注:欢迎转载,转载请注明出处