JavaScript温故而知新——原型和原型链

栏目: JavaScript · 发布时间: 6年前

内容简介:在当前Vue、React、Angular三驾马车齐驱的前端领域,我们对于框架的学习是无可厚非的,毕竟日常工作当中做的最多的就是业务的开发,框架的灵活运用大大提高了我们的开发效率。只不过我们前端框架的底层也终归是原生的JS,如果我们对于原生的东西了然于胸,那么对于框架的使用自然是更加得心应手。不过原生JS我们往往用的比较少,这也造成了对于很多概念和原理很容易就被我们所遗忘,这也是我写这个系列的初衷,在自己回顾这些知识的同时将其记录下来,时常拿出来翻看翻看,反复咀嚼,尽量把它牢牢锁在脑海。下面是这个系列的一篇:

在当前Vue、React、Angular三驾马车齐驱的前端领域,我们对于框架的学习是无可厚非的,毕竟日常工作当中做的最多的就是业务的开发,框架的灵活运用大大提高了我们的开发效率。只不过我们前端框架的底层也终归是原生的JS,如果我们对于原生的东西了然于胸,那么对于框架的使用自然是更加得心应手。

不过原生JS我们往往用的比较少,这也造成了对于很多概念和原理很容易就被我们所遗忘,这也是我写这个系列的初衷,在自己回顾这些知识的同时将其记录下来,时常拿出来翻看翻看,反复咀嚼,尽量把它牢牢锁在脑海。

下面是这个系列的一篇:《原型和原型链》

一、原型模式

我们创建的每一个函数都有一个 prototype (原型)属性,这个属性指向的是通过调用构造函数来创建出来的 对象实例原型对象 ,这个原型对象可以让所有对象实例 共享 它所包含的属性和方法。

function Person () {
    
}
Person.prototype.name = "xiao";
Person.prototype.sayName = function () {
    alert('this.name')
}
var person1 = new Person();
var person2 = new Person();
person1.sayName()  // "xiao"
console.log(person1.name == person2.name)   // "true"
复制代码

上面的例子当中我们创建了一个构造函数 Person ,并通过它的 prototype 属性在它的 原型对象 中定义了 name 属性并赋值,然后通过调用构造函数 Person 实例化出来两个对象实例,通过打印出来的值我们可以得知, person1person2 共享了原型对象中的属性和方法。

构造函数,原型对象和对象实例的关系

我们知道每个函数都有一个 prototype 属性指向函数的原型对象。在默认情况下,所有原型对象都有一个 constructor (构造函数)属性,这个属性指向了 prototype 属性所在的函数,比如前面的例子中, Person.prototype.constructor 就指向 Person

另外,当调用构造函数创建一个新实例后,该实例的内部将包含一个 __porto__ 属性(仅在Firefox、Safari、Chrome中支持),这个属性指向的就是构造函数的原型对象。由此我们可以得出以下图示的结论:

JavaScript温故而知新——原型和原型链

通过代码来验证:

# 实例和原型对象之间的关系
console.log(person.__proto__ == Person.prototype) // true

# 也可以通过isPrototypeOf()和ES5中的Object.getPrototypeOf()方法来判断
console.log(Person.prototype.isPrototypeOf(person1)) // true
console.log(Object.getPrototypeOf(person) === Person.prototype) // true

# 原型对象和构造函数的关系
console.log(Person.prototype.constructor == Person) // true
复制代码

二、原型链

通过前面我们对构造函数,对象实例和原型对象三者关系的描述可知,实例都包含了指向原型对象的内部指针。

那么假如现在我们有两个构造函数 AB ,我们让构造函数 A 的原型对象等于构造函数 B 的实例,根据前面的推论,这个时候 A 的原型对象就包含指向B的原型对象的指针,再假如又有一个构造函数 C ,让 A 的原型对象等于 C 的实例,上述关系依旧成立,以此类推便形成了实例与原型的链条,即原型链,它主要作为JS中实现继承的主要方法。

原型链的基本实现

function SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
}

# 继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
    return this.subproperty;
}

var instance = new SubType();
console.log(instance.SuperValue()); // true
复制代码

在上面的代码中,我们没有使用 SubType 默认的原型,而是将 SuperType 的实例赋给它,重写了 SubType 的原型对象;这样一来 SubType.prototype 的内部便具有一个指向 SuperType 原型的指针,原来存在于 SuperType 的实例中的所有属性和方法,现在也存在于 SubType.prototype 中了。

instance 同理,还要注意的是由于 SubType 的原型指向了 SuperType 的原型,而 SuperType 的原型的 constructor 属性指向的是 SuperType 构造函数,那么 instance.constructor 也就指向了 SuperType

如下图所示蓝色的线就代表了原型链

JavaScript温故而知新——原型和原型链

原型搜索机制

当访问一个实例属性或方法时,在通过原型链实现继承的情况下,首先会在实例中搜索该属性,在没有找到属性或方法时,便会沿着原型链继续往上搜索,直到原型链末端才会停下来。

这里还有一个重要的点,事实上所有引用类型默认都继承了 Object ,而这个继承也是通过原型链实现的,也就是说,所有函数的默认原型都是 Object 的实例,这也是所有自定义类型都会继承 toString()valueOf() 等默认方法的根本原因。

Object.prototype的原型

既然所有类型默认都继承了 Object ,那么 Object.prototype 又指向哪里呢,答案是 null ,我们可以通过下面的代码打印试试看:

console.log(Object.prototype.__proto__ === null) // true
复制代码

null 即没有值,也就是说属性或方法的查找到 Object.prototype 就结束了。

这个时候,我们就可以看到完整的原型链关系图如下:

JavaScript温故而知新——原型和原型链

以上所述就是小编给大家介绍的《JavaScript温故而知新——原型和原型链》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

HTML5

HTML5

Matthew David / Focal Press / 2010-07-29 / USD 39.95

Implement the powerful new multimedia and interactive capabilities offered by HTML5, including style control tools, illustration tools, video, audio, and rich media solutions. Understand how HTML5 is ......一起来看看 《HTML5》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具