前言
JavaScript的学习需要慢慢沉淀,像过关斩将一般将一个个知识点掌握,在之前的学习中学习了作用域、预编译、闭包、对象与包装类,今天我们再继续攻克一个知识点:原型与原型链
原型
- 原型是函数自带的一个属性
prototype,它定义了构造函数的实例对象的公共祖先 通过构造函数创建的对象,可以继承该函数原型的属性 - 实例对象隐式具有构造函数原型上的属性,且是只读属性
看看例子吧
//Car.prototype.speed = 260;
//Car.prototype.lang = 5000;
Car.prototype={
speed:260,
lang:5000
}
function Car(color,owner){
this.color = color;//允许自定义
this.owner = owner;
}
let car = new Car("red","张三");
let car2 = new Car("blue","李四");
console.log(car);
console.log(car2.lang);
通过构造函数Car创建了两个实例对象car和car2,于是这两个对象可以继承构造函数的属性,只不过是隐式继承,因此输出car时,只有自带的显式属性color和owner,但当要求输出car2.lang时会显示出隐式属性lang
原型属性分为显式和隐式
-
实例具有的属性为显性
-
隐式原型:对象上的__proto__属性,它等于构造函数的prototype属性。
Person.prototype.like = 'fuck';// 原型具有的属性为隐性
function Person(){
this.speed = 260;
this.lang = 5000;
}
let p = new Person()
p.like = 'shit' // 实例具有的属性为显性
delete p.like // 删除实例的属性,原型的属性不会被删除
console.log(p.like)
通过构造函数Person创建了实例对象p,其具有Person.prototype.like的属性fuck,现在为p增加了.like属性,输出的是先在实例属性找到的shit
接着再删除实例对象的.like属性,再输出会发现结果不为undefined,而输出的是原型属性fuck,于是可以得到结论:删除实例的属性,原型的属性不会被删除
原型的属性和方法
Object.prototype:所有对象的原型链顶端都是Object.prototype,它提供了一些通用的方法,如toString(),hasOwnProperty(),isPrototypeOf()等。- 构造函数的
prototype属性:每个函数在创建时,都会自动创建一个prototype属性,这个属性是一个对象,包含了可以由该构造函数创建的所有实例共享的属性和方法。
原型的继承:JavaScript中的继承是通过原型链实现的。当一个对象作为另一个对象的原型时,子对象就可以访问父对象的属性和方法。
原型链
v8在查找对象的属性时,如果没有找到,就会顺着对象的隐式原型往上查找,还找不到, 再顺着隐式原型的隐式原型往上找,直到找到或者到达原型链的顶端,也就是null, 但凡这过程中有一个步骤能找到就会返回值。这个查找过程称为原型链。
Person.prototype.lastName = 'james';
function Grand(){
this.name = "tony";
}
Father.prototype = new Grand()
function Father(){
this.age = 18;
}
Son.prototype = new Father();
function Son(){
this.like = "goo";
}
let son = new Son();
console.log(son.like);
console.log(son.age);//18
这段代码定义了Person、Grand、Father和Son四个构造函数,通过原型链的方式,设置了它们之间的继承关系。Grand是Father的父类,Father是Son的父类。
在实例化Son对象时,会继承Father和Grand的属性和方法。最后通过创建Son的实例对象son,输出了son的like属性和age属性,结果分别为goo和18。
__proto__是对象的一个隐式属性,它用于指向父级对象的原型(prototype)。
prototype是显式属性。它主要用于函数对象(即构造函数),用来定义该函数作为构造函数时,其实例将继承的属性和方法。
它的查找顺序便是
son实例__proto__: 指向Son.prototypeSon.prototype.__proto__: 指向Father.prototypeFather.prototype.__proto__: 指向Grand.prototypeGrand.prototype.__proto__: 通常直接指向Object.prototypeObject.prototype.__proto__: 指向null,表示原型链的终点。
__proto__: Son.prototype == new Father(){
__proto__: Father.prototype == new Grand(){
__proto__: Grand.prototype == new Person(){
__proto__: Person.prototype == new Object{
__proto__: Object.prototype {
__proto__: null
}
}
}
}
每个构造函数的 .prototype 属性定义了由该构造函数创建的对象的原型,而这些原型对象通过 __proto__ 隐式链接到它们的父级原型,直至 Object.prototype,形成完整的原型链
注意事项
- 原型链查找是单向的,从子对象到父对象,直到
Object.prototype。- 原型链的末端是
null,当查找到达null时,表示链的结束。- 使用
new关键字创建对象时,新对象的__proto__属性(在某些浏览器中是prototype)会指向构造函数的prototype属性。
如果感觉掌握了那就上大“boss”
试着将这一幅图的每一条步骤梳理清楚吧
总结来说
显式原型prototype主要用于定义和管理构造函数的共享属性和方法,而隐式原型__proto__则负责在对象实例中建立到其构造函数原型的链接,实现继承和属性查找机制。两者共同构建了JavaScript强大的基于原型的继承系统。