原 型
平时我们常常这样定义一个构造函数:
function Animal(name) {
this.name = name
}
Animal.prototype.eat = function() {
console.log(this.name + ' is eating')
}
Animal.prototype.run = function() {
console.log(this.name + ' is running')
}
const dog = new Animal('dog')
dog.eat() // 'dog is eating'
const cat = new Animal('cat')
cat.run() // 'cat is running'
在JavaScript中,每个函数有拥有一个prototype
属性,指向这个函数的原型对象,原型对象的属性和方法会被构造函数的实例所继承。上例中Animal.prototype
就是指向Animal
的原型,原型方法eat
和run
会被dog
和cat
所继承。
我们知道JavaScript中:
实例都有constructor
属性,指向它的构造函数:dog.constructor === Animal
;
函数的原型对象的constructor
又指向该函数自身:Animal.prototype.constructor === Animal
;
另外,JavaScript对象都拥有一个__proto__
属性,它指向该对象的构造函数的原型对象:dog.__proto__ === Animal.prototype
原型链
试想:既然对象都有__proto__
属性,那么函数的原型对象的__proto__
属性指向谁呢?我们可以通过构造函数的名字来得到答案:
Animal.prototype.__proto__.constructor.name // 'Object'
它指向一个对象,那么这个对象的__proto__
又指向谁呢?我们继续:
Animal.prototype.__proto__.__proto__.constructor.name // 报错了
Animal.prototype.__proto__.__proto__ // 结果是null了
我们发现object
再往上查看原型,就得到null
了,上面这些不断向上查找原型的过程,就得到了js原型链。
扩 展
我们知道JavaScript中所有的数据类型都是继承自Object
的,我们可以根据以上内容来验证。
[].__proto__.constructor.name; // 'Array'
[].__proto__.__proto__.constructor.name; // 'Object'
''.__proto__.constructor.name; // 'String'
''.__proto__.__proto__.constructor.name; // 'Object'
Function.prototype.__proto__.constructor.name; // 'Object'
Object.prototype.__proto__ // null
熟话说:“一切皆对象”,原来null
才是最后赢家,因为typeof null === 'object'
!
网友评论