认识javascript中的原型和原型链

原型和原型链是javascript中非常重要的概念,下面让我们来认识一下这两个熟悉的陌生人。

原型

概念:无论何时,只要创建一个函数,就会按照规则为这个函数创建一个prototype属性,prototype属性指向的对象也就是原型对象。每次调用这个函数创建一个新实例,这个实例内部指针([[prototype]])就会被赋值为这个函数的原型对象,由于javascript脚本中没有设置可以访问[[prototype]]特性的标准模式,所以Firefox,Safari和Choreme会在每个对象上暴露一个__proto__属性,通过这个属性就可以访问到对象的原型。

作用:通过对象的原型,我们可以获取到这个对象有哪些属性,并在实例化对象时,直接拥有这些属性。

下面,我们同样通过例子来理解原型的概念。


function Person() { //构造函数
}

Person.prototype.name = "张三";
Person.prototype.age = "18";
Person.prototype.sex = "man";

const person = new Person(); //实例1

person.name = '李四'

const person2 = new Person(); //实例2

console.log(person.__proto__ === Person.prototype) //true
console.log(person.__proto__ === person2.__proto__ ) //true

例子中,我们定义了构造函数Person,并给Person的原型对象上设置了三个属性。同时也通过Person函数构建了两个实例person和person2。

例子的输出结果都是true,所以我们可以看出,实例化的对象的__proto__属性是指向构造函数的prototype属性,所以这person.__proto__ 和 Person.prototype是全等的。

同时为了方便理解这个例子,我们可以画一个图来理解prototype和__proto__之间的关系。

认识javascript中的原型和原型链

绘画能力有限,不过应该还是能够看懂。通过这个图我们能清晰的看到,不管是构造函数的prototype属性还是实例的__proto__属性都是指向构造函数的原型对象。

现在我们了解了原型,那原型的作用是什么,这种规则有什么用,现在我们也来探索一下。

通过上面的例子,我们可以看到,实例对象person和person2都具有Person原型对象的属性。学习过面向对象思想的同学应该了解了,通过原型,我们可以将javascript 当做面向对象的语言使用,通过提炼公共属性与方法,实现代码优化。

同样,我们也通过一个例子来看看面向对象编程的优点。

function Person() { //构造函数
}

Person.prototype.name = "张三";
Person.prototype.age = "18";
Person.prototype.sex = "man";
/* 原型方式 */
const person = new Person(); //实例1
const person2 = new Person(); //实例2

/* 原始方式 */
let person3 = {
    name: '王五',
    age: 18,
    sex: 'man'
};

let person4 = {
    name: '周六',
    age: 18,
    sex: 'man'
}

相信例子中两种创建对象方式的优劣都是显而易见的。接下来我们了解下原型链。

原型链

了解原型之后,原型链的理解相信就是水到渠成的了。

概念:每一个构造函数都有一个原型对象,该原型对象有个属性回指向构造函数,通过该构造函数实例化的对象也有一个指针指向原型。如果当这个原型是另一个构造函数的实例时,这个原型的__proto__属性将指向另一个函数的原型对象。这样实例和原型之间就构造了一条原型链。

作用:实现继承。

同样我们也来一个例子。

function a() {
}

a.prototype.a = 'a';

function b() {
}

b.prototype.__proto__ = a.prototype;
b.prototype.b = 'b';

function c() {
}
c.prototype.__proto__ = b.prototype;
c.prototype.c = 'c';

let obj = new c();
console.log({a: obj.a, b: obj.b, c: obj.c})

例子中,我们声明了三个函数,并分别给三个函数的原型上添加了三个不同的属性。我们通过将c函数的原型对象的原型设置成b函数的原型对象(让c函数的原型对象是b函数的实例),实现了c继承b的效果,同时将b函数的原型对象的原型设置成a的原型对象(让b函数的原型对象是a函数的实例),实现了b继承a。通过串联c,b,a的原型,形成了一条原型链。

所以,上面这段程序最后的输出值是{a: "a", b: "b", c: "c"},因为实例obj通过原型链拿到了a,b,c三个属性。

同样我们用一张图描述下上面三个函数的关系。

认识javascript中的原型和原型链

 虽然图画的不怎么好,不过能看懂就行。相信通过这张图,你应该知道为什么叫原型链了吧。

总结:原型和原型链主要用于面向对象编程,实现类的封装与继承,是我们开发中不可获取的一部分。对他的使用要不断深研、探索。

浅陋见识,不足之处,请大神指正。