前端开发js的原型详解

web前端跨平台开发技术
web前端开发技术布局
web前端开发技术复习

JavaScript的面向对象是基于原型的,所有对象都有一条属于自己的原型链。那么js是如何实现原型的呢?js是以proto属性和prototype来实现原型的,普通对象只有proto属性,没有prototype属性;而函数既有proto属性,又有prototype属性。([color=Red]注意:proto 是隐藏的指针, 浏览器都有支持, 只不过IE很多版本不能访问而已。编程时尽量不要使用proto,要使用也要判断兼容性。也可以使用Object.setPrototypeOf()和Object.getPrototypeOf()来重设或者获取对象的原型对象[/color])

prototype属性是函数的属性,其指向一个普通对象(Function.prototype除外,其指向一个函数对象)。prototype的作用是在函数生成实例时,实例的proto属性指向该函数的prototype属性(详情参见js中new的详解),而该函数的prototype属性也是一个对象,其也有自己的proto属性并指向其构造函数的prototype属性。这样一层层嵌套,直到指向Object.prototype为止(因为Object.prototype的proto为null),形成了js对象的原型链。

声明函数时,函数会自动生成prototype属性,并指向一个Object对象。该Object对象默认有constructor属性和proto属性,constructor表示构造函数,指向声明的函数本身,proto属性指向Object.prototype
function F(){
}
console.log(F.prototype.proto===Object.prototype); //true
console.log(F.prototype.proto.proto); //null,原型链的终点
console.log(F.prototype);

生成实例时,实例的会自动生成proto属性并指向构造函数的prototype属性
代码片段 1

<script type=”text/javascript”>
    function F() {}
    var obj = new F()
    alert(obj.__proto__ === F.prototype)
</script>

js对象的属性读取是沿对象的原型链进行查找的,先在对象内部查找,看是否有该属性,如果有的话就返回该属性值,没有的话就在该对象的proto属性指向的对象中查找,如果有的话就返回该属性值,没有的话就再在该对象(最初对象的proto属性指向的对象)的proto属性指向的对象中查找。如此一层一层往上查找,直到原型链的终点,如果还没找到的话就返回undefined。
function F1(){
this.a=8;
}
console.log(‘F1的实例’,new F1());
function F2(){
this.b=10;
this.c=12;
}
F2.prototype=new F1();
console.log(‘F2的实例’,new F2());
function F3(){
this.c=14;
this.d=16;
}
F3.prototype=new F2();
var f3=new F3();
console.log(‘F3的实例’,f3);
console.log(f3.a); //8,实际在f3.proto.proto中才找到属性a
console.log(f3.b); //10,实际在f3.proto中才找到属性b
console.log(f3.c); //14,实际在f3中就找到了属性c,故没有沿原型链向上查找到f3.proto.c(f3.proto.c=12)
console.log(f3.d); //16,实际在f3中就找到了属性c
console.log(f3.e); //undefined,一直找到原型链的终点都没找到属性e,返回undefined

js对象的属性赋值与属性读取不同,属性赋值时先在对象中查找是否有该属性,如果有的话就重新设置该属性的值,如果没有的话并不是沿原型链向上查找,而是直接给对象新建该属性并赋值。(例:如果修改obj.attr,先判断obj是否直接有属性attr;如果修改obj.attr1.attr2,先判断obj.attr1是否直接有属性attr2(obj.attr1遵循js属性读取原则,即属性attr1并非一定是obj直接包含的属性,也可以是obj的原型链中的属性)。个人认为,js的这种特性是在模拟传统的OOP(如Java),让构造函数生成的所有实例保持属性修改的独立,一个实例修改了某个属性并不会导致另一个实例的该属性也被修改。如果想让实例(如obj)的某个属性修改能影响其他的实例,应该这样修改:obj.proto.attr=xxx; 这是因为所有实例的proto都指向同一个对象(构造函数的prototype))
function F1(){
this.a=8;
}
function F2(){
this.b=10;
}
F2.prototype=new F1();
var f2=new F2();
var f3=new F2();
console.log(‘F2的实例’,f2);
console.log(f2.a); //8,实际在f2.proto中才找到属性a
console.log(f3.a); //8,实际在f3.proto中才找到属性a
f2.a=function(){}; //在f2中没有直接找到属性a,故新建属性a并赋值为12
console.log(f2.proto.a); //8,f2.proto中的属性a并没有改变
console.log(f2.a); //匿名函数,因为前面在f2中新建了属性a,实际在f2中就直接找到了属性a
console.log(f3.a); //8,f2修改属性a并没有影响到f2.proto(f2.proto和f3.proto指向同一个对象)
console.log(‘F2的实例’,f2);
f2.proto.a=12;
console.log(f2.a); //匿名函数
console.log(f3.a); //12

下面的是参考博客:JavaScript的Function与Object浅析
将讲得好的地方抄过来下{:4_105:}

instanceof为js中判断实例的方法,判断的根据就是(例 a instanceof A) 判断a的原型链中是否含有A.prototype

解释: 所有函数的prototype属性均有constructor指向该函数。
所有对象均有原型链(Object.prototype的原型链为null,Function.proto与Function.prototype指向同一个对象,且该对象为函数)。

Object.prototype的原型链为空(即没有一个原型对象)。因此Object.prototype instanceof Object 为false,不是所有的对象均为Object对象实例。应该是除了Object.prototype除外的所有对象均为Object对象的实例
typeof Object.prototype===’object’ 为true

2017 前端开发新技术
传统的前端开发技术栈
前端开发技术未来趋势 知乎
» 本文来自:前端开发者 » 《前端开发js的原型详解》
» 本文链接地址:https://www.rokub.com/7486.html
» 您也可以订阅本站:https://www.rokub.com
赞(0)
64K

评论 抢沙发

评论前必须登录!