prototype
原型,每一个函数都有一个prototype
属性,也叫原型对象
__proto__
原型链,每一个对象都有一个__proto__
属性,指向它的构造函数的prototype属性,也叫继承属性
上面两个定位不太准确,因为根据MDN文档,其实一个叫原型对象,一个“是”继承属性(也不是prototype属性的名称),具体真要说原型是哪个,我也找不到准确的定义,但MDN上说了__proto__指向一个原型对象的链,所以就是所谓的原型链,而我们开发时经常说原型上的属性,所以我就将其认为是原型(如果有具体说明的文章请给我留言,好涨点知识)
代码图示说明
function Animal () {
this.type = '动物';
}
Animal.prototype.type = '哺乳类';
let cat = new Animal();
console.log(cat.__proto__ === Animal.prototype); // true
原型与原型链
- 每一个函数定义的时候都会有一个prototype属性,prototype里会有一个constructor属性,保存该函数指向
- 当构造函数
Animal
通过new关键字实例出一个对象时,该对象cat
会有一个__proto__属性,指向原函数的prototype - 假如
cat
中有某个属性不在自己的实例上,那么就会通过原型链向上查找(下面是伪代码)
cat.__proto__ -> Animal.prototype
- 如果构造函数的原型上也没找到,那么会通过原型的__proto__继续向上查找(因为prototype也是对象),那么就会去到Object(下面是伪代码)
cat.__proto__ -> Animal.prototype -> Animal.prototype.__proto__ -> Object.prototype
- 当Object的原型上也找不到了的时候,就会通过Object的原型的__proto__继续查找。但原型链并不是无穷无尽的,Object.prototype.proto就是原型链的顶层,所以此时返回null
console.log(Object.prototype.__proto__); // null
验证:删除cat
自身属性type,那么它会往上层继续查找,所以会输出哺乳类
console.log(cat.type); // 动物
delete cat.type;
console.log(cat.type); // 哺乳类
特别说明
一般对象和函数都遵循上面说法,但有个比较特殊,那就是Function
和Object
之间在原型链上的关系,因为他们既是对象也是函数,所以有定义
- Function.prototype === Function.__proto__
- Object.__proto__ === Function.prototype
- Object.__proto__ === Function.__proto__
console.log(Function.prototype === Function.__proto__); // true
console.log(Object.__proto__ === Function.prototype); // true
console.log(Object.__proto__ === Function.__proto__); // true
hasOwnProperty 和 in 关键字
这两个都是用来查找对象属性的,区别在于:
-
Object.hasOwnProperty()
只会查看是否存在当前实例上 -
in
关键字会查找是否属于原型 或 实例上的属性
function Animal() {}
Animal.prototype.type = '动物';
let cat = new Animal();
console.log(cat.hasOwnProperty('type')); // false
console.log('type' in cat); // true
Object.getPrototypeOf() 和 Object.setPrototypeOf()
虽然很多浏览器都实现了__proto__,但是__proto__并非javascript标准,所以ES6新增了Object.getPrototypeOf()
和 Object.setPrototypeOf()
方法来获取原型链
网友评论