您的位置: 翼速应用 > 业内知识 > web前端 > 正文

JavaScript原型与原型链

与大部分面向对象语言不同,JavaScript中并没有引入类(class)的概念,但JavaScript仍然大量地使用了对象,为了保证对象之间的联系,JavaScript引入了原型与原型链的概念。

QQ截图20200526181505.png

构造函数与原型

在Java中,声明一个实例的写法是这样的:

ClassName obj = new ClassName()

JavaScript中也加入了类似的new操作符:

var obj = new FunctionName()

与Java不同的是,JavaScript中的new操作符后面跟的是函数名,而不是类名。因为JavaScript使用过构造函数而非类来创建实例。

声明一个构造函数并通过构造函数创建实例的过程:

function Dog(namecolor){
   this.name = name
   this.color = color
   this.bark = () => {
       console.log('wangwang~')
   }
}

const dog1 = new Dof('dog1''black')
const dog2 = new Dof('dog2''black')

但上面的例子有一个大问题:实例中的属性继承自构造函数,且都是独立不共享的,这无疑会造成浪费。对于namecolor来说,由于属性一定不同,属性必须独立,但是bark()方法都是一样的,这就需要原型(prototype),使其共享使用。

原型的一些基本概念:

  • 每一个构造函数都拥有一个prototype属性,这个属性指向一个对象,也就是原型对象。当使用这个构造函数创建实例的时候,prototype属性指向的原型对象就成为实例的原型对象。

  • 原型对象默认拥有一个constructor属性,指向指向它的那个构造函数(也就是说构造函数和原型对象是互相指向的关系)。

  • 每个对象都拥有一个隐藏的属性[[prototype]],指向它的原型对象,这个属性可以通过 Object.getPrototypeOf(obj)obj.__proto__ 来访问。

  • 实际上,构造函数的prototype属性与它创建的实例对象的[[prototype]]属性指向的是同一个对象,即 对象.__proto__ === 函数.prototype

  • 如上文所述,原型对象就是用来存放实例中共有的那部分属性。

  • 在JavaScript中,所有的对象都是由它的原型对象继承而来,反之,所有的对象都可以作为原型对象存在。

  • 访问对象的属性时,JavaScript会首先在对象自身的属性内查找,若没有找到,则会跳转到该对象的原型对象中查找。

学会了原型,就可以对上面的例子进行改造,把bark()放到Dog构造函数的原型中:

function Dog(namecolor){
   this.name = name
   this.color = color
}

Dog.prototype.bark() = () => {
   console.log('wangwang~')
}

const dog1 = new Dog('dog1''black')
const dog2 = new Dog('dog2''white')
dog2.bark = () => {
   console.log('miaomiaomiao???')
}

dog1.bark()  // wagnwang~
dog2.bark()  // miaomiaomiao???

dog2重写了bark()方法,但没有对dog1造成影响,因为它重写的bark()方法的操作实际上是对自己添加了一个新的方法,使原型中的bark()方法被覆盖了,原型中的方法是不会受影响的。若想修改原型中的方法,需要通过构造函数的prototype属性:

Dog.prototype,bark = () => {
   console.log('haha ~')
}
dog1.bark()  //  haha ~
dog2.bark()  //  haha ~

小结

将实例中共有的属性放到原型对象中,让所有实例共享这部分属性。如果想统一修改所有实例继承的属性,只需要直接修改原型对象中的属性即可。

同时,每个实例仍然可以重写原型中已经存在的属性来覆盖这个属性,并且不会影响到其他的实例。

原型链与继承

JavaScript中的所有对象都是由它的原型对象继承而来的,而原型对象自身也是一个对象,它也有自己的原型对象,这样层层上溯,就形成了一个类似链表的结构,这就是原型链。

所有原型链的终点都是Object函数的prototype属性,因为在JavaScript中的对象都默认有Object()构造。Obejct.prototype指向的原型对象,同样拥有原型,不过它的原型是null,而null则没有原型。

通过原型链就可以在JavaScript中实现继承,JavaScript中的继承相当灵活,有多种继承方法,比如组合继承。

function Dog(namecolor){
   this.name = name
   this.color = color
}

Dog.prototype.bark = () => {
   console.log('wangwang~')
}

function Husky(namecolorweight){
   Dog.call(thisnamecolor)
   this.weight = weight
}

Husky.prototype = new Dog()


这里声明了一个新的构造函数Husky,通过call()方法继承Dog中的属性(call方法的作用可以简单理解为将Dog中的属性添加到Husky中),并添加了一个weight属性,然后用Dog函数创建了一个实例作为Husky的原型对象并赋值给Husky.prototype以继承方法。这样,通过Husky函数创建的实例就拥有了Dog中的属性和方法。

我来说两句

0 条评论

推荐阅读

  • 响应式布局CSS媒体查询设备像素比介绍

    构建响应式网站布局最常见的是流体网格,灵活调整大小的站点布局技术,确保用户在使用的幕上获得完整的体验。响应式设计如何展示富媒体图像,可以通过以下几种方法。

    admin
  • 提升网站的性能快速加载的实用技巧

    网站速度很重要,快速加载的网站会带来更好的用户体验、更高的转化率、更多的参与度,而且在搜索引擎排名中也扮演重要角色,做SEO,网站硬件是起跑线,如果输在了起跑线,又怎么跟同行竞争。有许多方法可提升网站的性能,有一些技巧可以避免踩坑。

    admin
  • 织梦CMS TAG页找不到标签和实现彩色标签解决方法

    织梦cms是我们常见的网站程序系统的一款,在TAG标签中常常遇到的问题也很多。当我们点击 tags.php 页的某个标签的时候,有时会提示:“系统无此标签,可 能已经移除!” 但是我们检查程序后台,以及前台显示页面。这个标签确实存在,如果解决这个问题那?

    admin
  • HTML关于fieldset标签主要的作用

    在前端开发html页面中常用的标签很多,今天为大家带来的是关于HTML中fieldset标签主要的作用说明,根据技术分析HTML

    admin

精选专题