javaScript 原型与原型链

对于JavaScript来说,在ES6之前没有引入类的概念,所以创建实例是通过构造函数实现的。
 
在学习原型和原型链之前我们先要明白构造函数:

一、构造函数

1、什么是构造函数?

所谓构造函数,就是提供一个生成对象的模版,并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构。它的基本结构如下:
function Person(name, age, sex) { 
    this.name = name; 
    this.age = age; 
    this.sex = sex; 
    this.runing = function() { console.log("人走路"); } 
}

2、构造函数的特点

  • 函数名的首字母一般是大写;
  • 函数体内使用this关键字;
  • 生成对象的时候,必须使用new命令来调用构造函数。 

3、构造函数如何生成对象

function Person(name, age, sex) { 
    this.name = name; 
    this.age = age; 
    this.sex = sex; 
    this.runing = function() { console.log("人走路"); } 
} 

const person = new Person("余生", 27, '男'); 
console.log(person); // {name: "余生", age: 27, sex: "男", runing:f()}

上面的代码首先创建了一个构造函数Person,然后通过new命令调用了Person,并传入参数。最终创建了一个person对象。在Person构造函数中,有一个runing方法,每次new的时候都会生成这个方法,而且每次都是一摸一样的,为了把这个方法单独放到一个地方,能让所有的实例都能访问到,这就需要原型。

二、原型

1、prototype属性

我们知道在JavaScript中函数也是一个对象,是对象就有它的属性。(原型)prototype就是函数对象的一个属性。而且prototype是函数所独有的。

从上面的截图中可以看出:

 
创建的构造函数Person有一个prototype属性,这个属性是一个对象,这就是构造函数的原型(prototype)。并且原型(prototype)对象有一个constructor属性,constructor属性指向了Person构造函数。

2、 __ proto__ 属性

1)在JavaScript中所有的对象都有 __proto__,并且都指向创建该对象的函数的prototype。
2)所有的函数都是由Function函数创建的,所以函数的__proto__指向Function的prototype。
function Person() {}; 
Person.__proto__ === Function.prototype; // true

3)Function也是函数,因此它也由Function创建的,也就是说它自己创建了自己!所有Function的 __proto__指向的就是Function的prototype。

Function.__proto__ === Function.prototype; // true

4)Object函数也是Function函数创建的,因此Object的__proto__也是指向Function的prototype。

Object.__proto__ === Function.prototype; // true

5)prototype也是一个对象,它是Object函数创建的,所以prototype的__proto__指向Object的prototype。

function Person() {}; 
Person.prototype.__proto__ === Object.prototype; // true

6)但是Object.prototype却是一个特例,它的__proto__指向的是null。 设计上是为了避免死循环而设置的。

Object.prototype.__proto__ === null; // true

因此,根据上面的几条基本概念,从这段简单的代码我们可以画出这样一条关系链图:

function Person() {}; 
const person = new Person();

三、原型链

通过一段代码进入原型链的学习:
function Person(name) { 
    this.name = name; 
} 

Function.prototype.runing = function() { console.log('人会走路'); } 

const person = new Person("余生"); 

person.runing(); 

person.hasOwnProperty("name");

我们来分析一下上面这段代码:
 
首先我们定义了一个方法Person,然后在Function的prototype上添加了一个属性runing,这个属性是一个方法。 
 
接下来我们通过上面的Person方法new出来一个person对象,因此person.__proto__指向了Person.prototype。 
 
前面我们说过,Person.prototype也是一个对象,是通过Object函数生成,所以Person.prototype.__proto__指向了Object.prototype。 
 
上面的代码中,person本身是没有runing属性,但是却能成功访问。这里就需要原型链了。
 
如果一个对象访问某一个属性的时,它自身没有这个属性,那它就会顺着它的__proto__向上查找,如果它的__proto__上依然没有这个属性,那就继续向上查找,直到找到为止。
 
runing属性在person对象中没有找到,就会继续找person.__proto__,也就是Person.prototype,很显然,这里找到了,就不会再向上查找了。
 
hasOwnProperty属性显然person对象中没有找到,就会继续找person.__proto__,也就是Person.prototype,很显然,Person.prototype中依然找不到,于是继续向上在Person.prototype.__proto__中找。
 
Person.prototype是一个普通对象,它是由Object方法创建的,因此Person.prototype.__proto__就是Object.prototype,很显然,Object.prototype里面已经定义了hasOwnProperty方法(属性),因此在这里也找到了。
 
上面这种查找形式就成为原型链
posted @ 2022-08-12 11:15  纯白の约定  阅读(22)  评论(0编辑  收藏  举报