javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JavaScript原型和原型链

JavaScript原型和原型链详解

作者:程序员李林

在面向对象的编程语言中,类和对象的关系是铸模和铸件的关系,对象总是从类创建而来,比如Java中,必须先创建类再基于类实例化对象,这篇文章主要介绍了JavaScript原型和原型链的相关知识,需要的朋友可以参考下

基于原型编程

在面向对象的编程语言中,类和对象的关系是铸模和铸件的关系,对象总是从类创建而来,比如Java中,必须先创建类再基于类实例化对象。
而在基于原型编程的思想中,类并不是必须的,对象都是通过克隆另外一个对象而来,这个被克隆的对象就是原型对象。
基于原型编程的语言通常遵循下面的规则:

函数和对象

JavaScript是基于原型的语言,但JavaScript并非严格遵循原型编程的第一条规则,其中基本类型undefined、number、string、boolean就不是对象,其模仿Java,分为了基本类型和对象类型,当然和Java一样,基本类型可以使用包装的形式变为对象。
这里先探讨一个问题,有助于后面理解原型和原型链,那就是“所有的数据都是对象,函数也是对象“,虽然函数是对象,但是函数拥有很多普通对象不具备的特性:

JavaScript原型

从上面可以得知,函数都有 prototype 属性,称之为原型,也称为原型对象,原型对象里面可以存放属性和方法,共享给实例对象使用,用于实现继承效果。
这里的函数指的是构造函数,即可以通过new创建对象的函数,在JavaScript中普通函数都可以是构造函数,除了箭头函数。

箭头函数没有 prototype 属性是为了保持它们的设计简洁性,避免与原型链相关的复杂性和潜在问题。箭头函数同时不能使用new实例化对象。如果你需要定义一个构造器函数,应该使用普通函数而不是箭头函数。

举例说明:

const arr = new Array(1, 2, 3)
arr.reverse()
arr.sort()

在上面的代码中 Array 就是一个构造函数,reverse和sort都是 Array.prototype 原型对象上的函数。
这里有个问题,为何要将这些方法放在 prototype 原型属性上,而不是放在构造函数内部呢?
我们来看下面的代码:

function Person() {
  this.getName = function () {
    console.log('person')
  }
}
Person.prototype.getProtoName = function () {
  console.log('proto person')
}
const person = new Person()
const person1 = new Person()
console.log(person.getName === person1.getName) // false
console.log(person.getProtoName === person1.getProtoName) // true

很明显,虽然在实例化对象上都可以调用这些方法,但两者有本质的不同,将方法放在 prototype 原型对象上,之后实例化的对象使用的都是同一个方法,类似于Java的类方法,而构造函数内的方法,则会重新创建,也就是实例对象方法。

JavaScript原型链

了解完原型之后,再来看原型链就非常简单了。

如图所示:

解读:

原型链经典图片

最后结合上面的内容,来看看下面的经典原型链图:

从上图可以看出左边是实例对象,中间是构造函数,右边是原型对象,图中还包含了一些其它内容:
函数是一个函数,同时也是一个对象:
构造函数作为一个函数时,拥有原型对象属性 prototype同时函数也是一个对象,函数都是由构造函数 Function 构造出来的,包括 Function 函数本身,可以看上图中 function Foo()function Object()function Function() 的 __proto__ 都是指向 Funtion.prototype,这是函数比较特殊的一点。
这个地方有点绕,再理一下,函数的 prototype 属性是这个函数自己的属性,而函数的 __proto__ 指向的是其构造函数的原型对象,可以理解为父级的属性,两者是不同的。

总结

到此这篇关于JavaScript原型和原型链的文章就介绍到这了,更多相关JavaScript原型和原型链内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文