类、 prototype
、__proto__
、实例、constructor
之间的关联
1. prototype 和 constructor
我们创建的每个函数都有一个
prototype
(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype
属性,这个属性指向函数的原型对象。
在默认情况下,所有原型对象都会自动获得一个constructor
(构造函数)属性,这个属性包含一个指向prototype
属性所在函数的指针。
对于构造函数来说,生成实例的时候,这个原型对象prototype
会自动成为实例对象的原型。
2. __proto__
每个实例对象(object )都有一个私有属性(称之为 proto)指向它的原型对象(prototype)。
图片来自MDN.pngfunction Cat(name){
this.name = name;
}
Cat.prototype.sayName = function(){
console.log('My name is :' + this.name);
}
var cat1 = new Cat('Munchkin')
cat1.sayName();
- 通过函数定义了类 Cat,类(函数)自动获得属性
prototype
- Cat 的
prototype
也是一个对象,内部有一个constructor
属性,该属性指向 Cat
Cat.prototype.constructor === Cat // true
- 每个类的实例都会有一个内部属性
__proto__
,在这里是cat1 ,cat1 的__proto__
指向类的prototype
属性
Cat.prototype === cat1.__proto__ // true
cat1.__proto__.constructor === Cat.prototype.constructor // true
image.png
原型链
JavaScript 规定,每个函数都有一个 prototype 属性,该属性指向一个对象。
对于构造函数来说,生成实例的时候,这个原型对象prototype
会自动成为实例对象的原型。
每个实例对象(object )都有一个私有属性(称之为 __proto__
)指向它的原型对象(prototype
)。
该原型对象也有一个自己的原型对象 ,层层向上直到一个对象的原型对象为 null,这就形成了一个“原型链”。根据定义,null 没有原型,并作为这个原型链中的最后一个环节。
所有对象的原型都可以最终追溯到 Object.prototype
,即Object构造函数的prototype
属性。
原型链的尽头是null , null 没有任何属性和方法,也没有自己的原型。
一点点补充: 函数与对象的恩怨
- 函数是一种特殊的对象
- 所有的构造函数都是 Function 的实例~
所以:
Function.__proto__.__proto__ === Object.prototype // true
Object.__proto__ === Function.prototype // true
与原型和原型链相关的一些方法
instanceof
1. 作用
instanceof 运算符返回一个布尔值,表示对象是否为某个构造函数的实例。
2. 使用方法
实例对象 instanceof 构造函数
3. 原理
它会检查右边构造函数的原型对象(prototype),是否在左边实例对象的原型链上。
大概就是这样子:
function _instanceof(obj,Fn) {
if(obj.__proto__){
if(obj.__proto__ === Fn.prototype) {
return true
} else {
return _instanceof(obj.__proto__,Fn)
}
} else {
return false
}
}
let arr = [];
_instanceof(arr, Array ); // true
_instanceof(arr, Object ); // true
3. tips
- instanceof会遍历整个原型链,所以一个实例对象可能会对多个构造函数返回 true
- 如果一个对象的原型是 null ,instanceof 的判断会失真
Object.create(null) instanceof Object // false
- instanceof运算符只能用于对象,不适用原始类型的值
Object.create()
Object.create(proto, [propertiesObject])
Object.create()方法创建一个拥有指定原型和若干个指定属性的对象。
如果想生成一个不继承任何属性的对象,可以将Object.create() 的参数设为 null
hasOwnProperty
obj.hasOwnProperty(prop)
实例对象的 hasOwnProperty 方法返回一个布尔值,用于判断某个属性定义在对象自身还是定义在原型链上。
eg.
({}).hasOwnProperty('toString') // false
hasOwnProperty 方法使JavaScript 中唯一一个处理对象属性时,不会遍历原型链的方法。
继承
extends 关键字实现继承
class Animal {
constructor() {
this.body = '肉体'
}
eat() {
console.log('eat')
}
}
class Human extends Animal {
constructor(name) {
super() // 子类中存在构造函数的话,则需要在使用“this”之前首先调用 super()
this.name = name
}
cook() {
console.log('cook')
}
}
var p1 = new Human('xx')
原型链实现继承
使用Object.create()
function Animal() {
this.body = 'body'
}
Animal.prototype.eat = function () {
console.log('eat')
}
function Human(name) {
Animal.call(this)
this.name = name
}
Human.prototype = Object.create(Animal.prototype);
Human.prototype.constructor = Human; // 这一步不能省! 修改原型对象的同时,也要记得修改constructor属性的指向!
Human.prototype.cook = function () {
console.log('cook')
}
var p1 = new Human('xx')
p1.__proto__.constructor === Human // true
不使用Object.create()
function Animal() {
this.body = 'body'
}
Animal.prototype.eat = function () {
console.log('eat')
}
function Human(name) {
Animal.call(this)
this.name = name
}
// Human.prototype.__proto__ = Animal.prototype // 非法,用下面三句话代替
var F = function() {}
F.prototype = Animal.prototype;
Human.prototype = new F()
Human.prototype.constructor = Human; // 这一步不能省! 修改原型对象的同时,也要记得修改constructor属性的指向!
Human.prototype.cook = function () {
console.log('cook')
}
var p1 = new Human('xx')
网友评论