用控制台输入如下命令
$ var arr = [];
$ arr.length // 0问题:为什么arr会有length属性?
1. 显示原型prototype
- JavaScript中每一个函数,都有一个prototype属性, 这个属性指向函数的原型对象
1.1 自定义函数的prototype
var fn = function() {}
console.log( fn.prototype );
fn.prototype.constructor === fn; // true1.2 内置构造器的prototype
Array是什么?
答:Array是一个函数
那么Array一定也有一个prototype属性了
$ Array.prototype.constructor // f Array()
$ Array.prototype.constructor === Array // true
$ Number.prototype.constructor === Number // true
$ String.prototype.constructor === String // true
$ Function.prototype.constructor === Function // true
$ Object.prototype.constructor === Object // true1.3 改变prototype
结论:
- 给prototype添加或者删除属性会影响所有已经或者未实例化的对象
- 重写prototype只会影响新new出来的对象
2. 隐式原型__proto__
- JavaScript中任意对象都有一个内置属性proto, 指向创建这个对象的函数(constructor)的prototype
var arr = new Array();
arr.__ptoto__ === Array.prototype // true根据"JavaScript中任意对象都有一个内置属性__proto__, 指向创建这个对象的函数(constructor)的prototype",函数Array创建了对象arr,因此arr的__proto__指向Array.prototype。即
- 此处提一下Object.create(),Object.create接收两个参数,第一个参数用来作为新对象的隐式原型, 第二个参数是对象的属性描述符。因此
var person = {LEG_NUM:2 }; var xiaoMing = Object.create(person); xiaoMing.__proto__ === person; // true2.1 改变__proto__
结论
- 改变arr.proto等价于改变Array.prototype
3. 原型链
- 当我们访问某个对象中的某个属性时,如果该对象本身具有这个属性,则直接使用,如果该对象本身没有这个属性,那么就会沿着__proto__依次查找
上图中,访问obj.z的时候在obj中没有访问到,就会沿着__proto__向上查找,于是在foo.prototype中找到了返回3.
访问obj.hasOwnProperty()时,同样在obj中没有找到这个属性,沿着__proto__向上查找,直到在Object.prototype中找到这个属性。
4. instanceof
instanceof, 左边是一个对象,右边必须是一个函数或构造器。它会判断右边构造器的prototype属性是否出现在左边对象的原型链上。
[] instanceof Array // true
[] instanceof Object // true5. 原型链的优缺点
- 优点: 节省内存、方便维护
- 缺点: 更改原型将影响所有指向它的对象
以下是《Javascript高级程序设计》中使用到的例子
改变person1的friends,会同时改变person2的friends,因为它们共用一个prototype.这显然不是我们想要的。可以通过如下方法改进
小结
- 显式原型的作用
用来实现基于原型的继承与属性的共享。 - 隐式原型的作用
构成原型链,同样用于实现基于原型的继承。举个例子,当我们访问obj这个对象中的x属性时,如果在obj中找不到,那么就会沿着__proto__依次查找。 - 二者的关系
隐式原型指向创建这个对象的函数(constructor)的prototype
参考文献
- www.zhihu.com/question/34…
- www.kancloud.cn/wangfupeng/…
- 《Javascript高级程序设计》(第3版)第6章