详解JavaScript原型与原型链

正如一些面向对象语言中所实现的那样,在JavaScript中我们有时也需要创建一个拥有公共函数与属性的类作为父类来减少代码重复、实现类型检查与实现更加清晰地代码结构。在JavaScript中,继承是通过原型链实现的。了解JavaScript的继承与原型链之前首先需要了解JavaScript中对象创建的方式。

在JavaScript中创建对象

JavaScript中对象创建的方式有两种:工厂方法(Factory Functions)、构造器方法(Constructor Functions) 。

工厂方法

工厂方法在编程领域是一个非类或构造器的返回对象的方法。在JavaScript中,任何返回不使用new关键词创建对象的方法都是工厂方法。

function person(firstName, lastName, age) {
 const person = {};
 person.firstName = firstName;
 person.lastName = lastName;
 person.age = age;
 return person;
}

构造器方法

构造器方法和工厂方法的区别仅在用例和命名规范上。命名规范上一个构造器方法的名字开头字母需要大写,我们需要通过new关键词来调用构造器方法生成实例。这个实例之后便可以通过instanceof关键词来检查。

function Person(firstName, lastName, age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
}

new的行为

当同时在工厂方法和构造器方法上使用new关键词创建时,工厂方法创建出的对象的__proto__属性指向Object.prototype,构造器方法创建出的对象的__proto__属性指向本身的Xxx.prototype。

const mike = new person('mike', 'grand', 23);

mike.__proto__	// Object.prototype
const jack = new Person('jack', 'grand', 23);

jack.__proto__	// Person.protytype这里的prototype指向Person的Prototype Object
jack.__proto__.__proto__	// Object.prototype

new关键词在后台为构造器方法执行了以下几步

  1. 在构造器方法内创建一个新对象并将其赋值到this上
  2. 设置对象的[[Prototype]]和__proto__为原型的构造函数,这一步也让新对象的构造函数在构造新对象时被添加到原型链上
  3. 如果这个方法内没有返回object、function或array类型的结果,就返回this
  4. 如果这个方法内没有返回任何值则返回this

下面是一个展示new关键词在JavaScript引擎当中执行效果的伪代码,注释当中的是用来示范new关键词添加语句的伪代码

function Person(firstName, lastName, age) {
 // this = {};
 // this.__proto__ = Person.prototype;
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
 // return this;
}

在构造器方法上没有返回值所以后台创建的this将被返回,而工厂方法内由于返回了对象所以后台不再添加return this自然返回的内容将不一致。

如果没有在构造器方法前使用new关键词,而将构造器方法直接调用执行,其仅作为一个方法来被执行而非构造器。

const bob = Person('bob', 'grand', 23);
bob	// undefined. 因为这里Person当作方法直接调用了且没有返回值
window.firstName	// bob. 函数内的this将指向全局作用域,导致意外操作

继承与原型链

原型

原型(Prototype)可以认为是一个JavaScript方法的属性,每次在JavaScript代码中创建方法时,JavaScript引擎会将一个名为prototype的属性添加上去,这个prototype属性是一个对象(原型对象),这个对象默认有一个constructor属性指向原方法对象。任何添加到prototype的属性和方法都在这个对象里面,所有该类实例共享这个原型对象,实例对象的__proto__属性指向这个对象,方法的prototype属性指向这个对象。

在ECMAScript的标准里object.[[Prototype]]是访问原型的方法,但在ECMAScript 2015中用Object.getPrototypeOf()和Object.setPrototypeOf()来替代。等价的__proto__是多数浏览器使用的事实上的但是非标准的实现。

function Person(firstName, lastName, age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
}

Person.prototype === Person.prototype.constructor.prototype	// 指向Person的原型对象
Person.prototype.constructor === Person	// 指向Person方法对象

let bob = new Person("Bob", "Ross", 21);
Person.prototype === bob.__proto__;	// true

let alex = new Person("Alex", "Wang", 21);
Person.prototype === alex.__proto__;	// true
alex.__proto__ === bob.__proto__;	// true

原型链

首先我们需要了解对象查找机制。当我们使用一个对象的属性时,JavaScript引擎会首先查找本对象里是否有对应属性,如果没有则去对象的原型里查找属性,如果没有则去对象的原型对象的原型对象里查找属性,直至查询到对象的__proto__为null的时候停止。

const obj = {};
console.log(obj);	// [object Object]	obj的toString()方法从Object的原型中查找到并使用

function Person(firstName, lastName, age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
 // 在Person.prototype上定义了toString覆写了Object.prototype上的toString
 Person.prototype.toString = function() {
  return `${this.firstName} It Is`;
 }
}

let bob = new Person("Bob", "Ross", 21);
let alex = new Person("Alex", "Wang", 21);
console.log(bob);	// Bob It Is
console.log(alex);	// Alex It Is

以上就是详解JavaScript原型与原型链的详细内容,更多关于JavaScript原型与原型链的资料请关注我们其它相关文章!

(0)

相关推荐

  • JS学习笔记之原型链和利用原型实现继承详解

    本文实例讲述了JS学习笔记之原型链和利用原型实现继承.分享给大家供大家参考,具体如下: 原型链 原型链是一种关系,实例对象和原型对象之间的关系,关系是通过原型(__proto__)来联系的 实例对象中有__proto__,是对象,叫原型,不是标准的属性,浏览器使用,并且有的游览器不支持 构造函数中有prototype属性,也是对象,叫原型 注意 原型中的方法是可以互相访问的 实例代码 function Animal(name,age){ this.name=name; thia.age=age;

  • JavaScript对象原型链原理解析

    这篇文章主要介绍了JavaScript对象原型链原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一个js对象,除了自己设置的属性外,还会自动生成proto.class.extensible属性,其中,proto属性指向对象的原型. 对象的属性也有writable.enumerable.configurable.value和get/set的配置方法. 对象的创建方式有三种: 一.使用字面量直接创建. 二.基于原型链创建. 分析上图,要点如

  • JavaScript中构造函数与原型链之间的关系详解

    在Javascript中不存在class的概念,它的class概念是通过构造函数(constructor)与原型链(prototype)来实现. 1.构造函数(constructor):创建对象时的初始化对象,总是与new 关键是一同出现. 构造函数存在以下特点: 1.构造函数内的this 指向当前实例对象. 2.使用new 关键字实例化当前对象. 3.构造函数首字母大写,区分普通函数. 4.实例对象都可以继承构造函数中的属性和方法.但是,同一个对象实例之间,无法共享属性. 2.原型(proto

  • JavaScript进阶(四)原型与原型链用法实例分析

    本文实例讲述了JavaScript原型与原型链用法.分享给大家供大家参考,具体如下: 一句话说明什么是原型:原型就是一个JavaScript对象,原型能存储我们的方法,构造函数创建出来的实例对象能够引用原型中的方法. 一.传统构造函数的问题 有如下代码 function Foo(){ this.sayHello = function(){ } } 由于对象是调用new Foo()所创建出来的,因此每一个对象在创建的时候,函数 sayHello 都会呗创建一次 那么有没一个对象都含有一个独立的,不

  • JavaScript原型链与继承操作实例总结

    本文实例讲述了JavaScript原型链与继承操作.分享给大家供大家参考,具体如下: 1. JavaScript继承 JavaScript继承可以说是发生在对象与对象之间,而原型链则是实现继承的主要方法: 1.1 原型链 利用原型让一引用类型继承另一个引用类型的属性和方法. 构造函数中有个prototype(每个函数中都有),指向他的原型对象,每个原型对象中也有一个constructor属性,指向原构造函数.通过构造函数创建的新对象中都有一个无法直接访问的[[proto]]属性,使得对象也指向构

  • 深入浅析js原型链和vue构造函数

    一.什么是原型链? 简单回顾下构造函数,原型和实例的关系: 每个构造函数(constructor)都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针,而实例(instance)都包含一个指向原型对象的内部指针. 然鹅,在js对象里有这么一个规则: 如果试图引用对象(实例instance)的某个属性,会首先在对象内部寻找该属性,直至找不到,然后才在该对象的原型(instance.prototype)里去找这个属性. 少废话,先来看个例子: function Fun1 ()

  • 图解JS原型和原型链实现原理

    在我初学 JS 语言的继承机制原型和原型链的时候,我一直理解不了这种设计机制,再加上之前原有对 Java继承的理解,在学习 JS 继承机制的设计上踩了一个大坑,很多知识点前期都是死记硬背,无法真正的理解它的设计思想. JS 中的继承机制思想可以说是学习 JS 的一个核心思想,更可以说是 JS 中的一个命脉,往往这些复杂.抽象的继承关系,以及专业术语.代名词确成为了困扰初学者的绊脚石.当我真正理解它的设计思想时,其实并没有那么复杂,而且觉得非常简单. 在写这篇 JS 的原型和原型链的文章之前,我在

  • JS原型和原型链原理与用法实例详解

    本文实例讲述了JS原型和原型链原理与用法.分享给大家供大家参考,具体如下: Javascript语言的继承机制一直很难被人理解. 它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instance)的区分,全靠一种很奇特的"原型链"(prototype chain)模式,来实现继承. Brendan Eich设计javascript之初是为了实现网页与浏览器之间交互的一种简单的脚本语言

  • JavaScript原型继承和原型链原理详解

    这篇文章主要介绍了JavaScript原型继承和原型链原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在讨论原型继承之前,先回顾一下关于创建自定义类型的方式,这里推荐将构造函数和原型模式组合使用,通过构造函数来定义实例自己的属性,再通过原型来定义公共的方法和属性. 这样一来,每个实例都有自己的实例属性副本,又能共享同一个方法,这样的好处就是可以极大的节省内存空间.同时还可以向构造函数传递参数,十分的方便. 这里还要再讲一下两种特色的构造

  • 一文秒懂JavaScript构造函数、实例、原型对象以及原型链

    1概述 ES6, 全称 ECMAScript 6.0 ,2015.06 发版.在ES6之前,对象不是基于类创建的,而是用一种称为构造函数的特殊函数来定义对象和它们的特征. 2构造函数 构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 一起使用.我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面. // 利用构造函数创建对象 function Person(uname, age) { this.uname = uname; this.age

  • javascript 原型与原型链的理解及应用实例分析

    本文实例讲述了javascript 原型与原型链的理解及应用.分享给大家供大家参考,具体如下: javascript中一切皆对象,但是由于没有Class类的概念,所以就无法很好的表达对象与对象之间的关系了. 比如对象A与对象B之间,它们两个是相对独立的个体,互不干扰,对象A修改自身的属性不会影响到对象B. 虽然这很好,但是有一个问题,如果对象A与对象B都有一个方法 run() ,并且代码也一样,那对象A与对象B各自都独立拥有一份 run() 方法的完整代码,这是需要资源去保存的. 一旦我们程序中

  • JS原形与原型链深入详解

    本文实例讲述了JS原形与原型链.分享给大家供大家参考,具体如下: 前言 在JS中,我们经常会遇到原型.字面上的意思会让我们认为,是某个对象的原型,可用来继承.但是其实这样的理解是片面的,下面通过本文来了解原型与原型链的细节,再顺便谈谈继承的几种方式. 原型 在讲到原型之前,我们先来回顾一下JS中的对象.在JS中,万物皆对象,就像字符串.数值.布尔.数组等.ECMA-262把对象定义为:无序属性的集合,其属性可包含基本值.对象或函数.对象是拥有属性和方法的数据,为了描述这些事物,便有了原型的概念.

随机推荐