浅谈JS的原型和继承

参考文献

JavaScript原型与继承的秘密

__proto__

除null和undefined,JS中的所有数据类型都有这个属性; 它表示当我们访问一个对象的某个属性时,如果该对象自身不存在该属性, 就从它的__proto__属性上继续查找,以此类推,直到找到,若找到最后还是没有找到,则结果为undefined

我们把一个对象的__proto__属性所指向的对象叫该对象的原型;我们可以修改一个对象的原型来让这个对象拥有某种属性或某个方法

// 修改一个Number类型的值的原型
const num = 1;
num.__proto__.name = "My name is 1";
console.log(num.name); // My name is 1

// 修改一个对象的原型
const obj = {};
obj.__proto__.name = "dreamapple";
console.log(obj.name); // dreamapple

需注意的是,__proto__属性虽多数浏览器支持,但其实它仅在ECMAScript 2015规范中才被准确定义, 目的是为了给这个传统的功能定制一个标准,以确保浏览器间的兼容性。通过使用__proto__属性来修改一个对象的原型非常慢且影响性能。 所以,若想获取一个对象的原型,推荐用Object.getPrototypeOf 或Reflect.getPrototypeOf,设置一个对象的原型推荐用Object.setPrototypeOf或Reflect.setPrototypeOf

prototype

首先要记住的是,该属性一般只存在于函数对象上; 只要是能作为构造器的函数,都包含这个属性。即只要这个函数能通过new生成一个新对象, 那么这个函数肯定具有prototype属性。因为我们自定义的函数都可通过new生成一个对象,所以我们自定义的函数都有prototype 这个属性

// 函数字面量
console.log((function(){}).prototype); // {constructor: ƒ}

// Date构造器
console.log(Date.prototype); // {constructor: ƒ, toString: ƒ, toDateString: ƒ, toTimeString: ƒ, toISOString: ƒ, …}

// Math.abs 不是构造器,不能通过new操作符生成一个新的对象,所以不含有prototype属性
console.log(Math.abs.prototype); // undefined

prototype属性有什么作用呢?作用就是:函数通过new生成的一个对象, 这个对象的原型(__proto__)指向该函数的prototype属性:

// 其中F表示一个自定义的函数或者是含有prototype属性的内置函数
new F().__proto__ === F.prototype // true

// 通过函数字面量定义的函数的__proto__属性都指向Function.prototype
(function(){}).__proto__ === Function.prototype // true

// 通过对象字面量定义的对象的__proto__属性都是指向Object.prototype
({}).__proto__ === Object.prototype // true

// Object函数的原型的__proto__属性指向null
Object.prototype.__proto__ === null // true

// 因为Function本身也是一个函数,所以Function函数的__proto__属性指向它自身的prototype
Function.__proto__ === Function.prototype // true

// 因为Function的prototype是一个对象,所以Function.prototype的__proto__属性指向Object.prototype
Function.prototype.__proto__ === Object.prototype // true

constructor

constructor表示一个对象的构造函数,除null和undefined,JS中的所有数据类型都有这个属性; 我们可通过下面的代码来验证一下:

null.constructor // Uncaught TypeError: Cannot read property 'constructor' of null ...
undefined.constructor // Uncaught TypeError: Cannot read property 'constructor' of undefined ...

(true).constructor // ƒ Boolean() { [native code] }
(1).constructor // ƒ Number() { [native code] }
"hello".constructor // ƒ String() { [native code] }

一个对象的constructor属性确切地说并不是存在这个对象上面的; 而是存在这个对象的原型上(如果是多级继承需手动修改原型的constructor属性),我们可用下面的代码来解释一下:

const F = function() {};
// 当我们定义一个函数的时候,这个函数的prototype属性上面的constructor属性指向自己本身
F.prototype.constructor === F; // true

对JS的原始类型(string, number, boolean, null, undefined, symbol(new in ECMAScript2015)),它们的constructor属性是只读的,不可修改:

(1).constructor = "something";
console.log((1).constructor); // 输出 ƒ Number() { [native code] }

如果真想改这些原始类型的constructor属性,也不是不可以:

Number.prototype.constructor = "number constructor";
(1).constructor = 1;
console.log((1).constructor); // 输出 number constructor

当然上面的方式不推荐

以上所述是小编给大家介绍的JS原型和继承详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 深入理解javascript原型链和继承

    在上一篇文章中,介绍了原型的概念,了解到在javascript中构造函数.原型对象.实例三个好基友之间的关系:每一个构造函数都有一个"守护神"--原型对象,原型对象心里面也存着一个构造函数的"位置",两情相悦,而实例呢却又"暗恋"着原型对象,她也在心里留存了一个原型对象的位置. javascript本身不是面向对象的语言,而是基于对象的语言,对于习惯了其他OO语言的人来说,起初有些不适应,因为在这里没有"类"的概念,或者说&q

  • js原型继承的两种方法对比介绍

    在实际的项目中,我们通常都是用构造函数来创建一个对象,再将一些常用的方法添加到其原型对象上.最后要么直接实例化该对象,要么将它作为父类,再申明一个对象,继承该父类. 而在继承的时候有两种常用方式,今天我们就来稍作探讨 复制代码 代码如下: //父类 function Person(name){    this.name = name;}; // 子类 function Student(sex){  Person.apply(this,arguments); //继承父类的构造函数  this.s

  • JS继承--原型链继承和类式继承

    什么是继承啊?答:别人白给你的过程就叫继承. 为什么要用继承呢?答:捡现成的呗. 好吧,既然大家都想捡现成的,那就要学会怎么继承! 在了解之前,你需要先了解构造函数.对象.原型链等概念...... JS里常用的两种继承方式: 原型链继承(对象间的继承)类式继承(构造函数间的继承) 原型链继承: 复制代码 代码如下: //要继承的对象var parent={name : "baba" say : function(){ alert("I am baba");}} //

  • JavaScript的模块化:封装(闭包),继承(原型) 介绍

    虽然 JavaScript 天生就是一副随随便便的样子,但是随着浏览器能够完成的事情越来越多,这门语言也也越来越经常地摆出正襟危坐的架势.在复杂的逻辑下, JavaScript 需要被模块化,模块需要封装起来,只留下供外界调用的接口.闭包是 JavaScript 中实现模块封装的关键,也是很多初学者难以理解的要点.最初,我也陷入迷惑之中.现在,我自信对这个概念已经有了比较深入的理解.为了便于理解,文中试图封装一个比较简单的对象. 我们试图在页面上维护一个计数器对象 ticker ,这个对象维护一

  • JavaScript继承基础讲解(原型链、借用构造函数、混合模式、原型式继承、寄生式继承、寄生组合式继承)

    说好的讲解JavaScript继承,可是迟迟到现在讲解.废话不多说,直接进入正题. 既然你想了解继承,证明你对JavaScript面向对象已经有一定的了解,如还有什么不理解的可以参考<面向对象JS基础讲解,工厂模式.构造函数模式.原型模式.混合模式.动态原型模式>,接下来讲一般通过那些方法完成JavaScript的继承. 原型链 JavaScript中实现继承最简单的方式就是使用原型链,将子类型的原型指向父类型的实例即可,即"子类型.prototype = new 父类型();&qu

  • 详解JavaScript中基于原型prototype的继承特性

    JavaScript 中的继承比较奇葩,无法实现接口继承,只能依靠原型继承. 原型链 原型就是一个对象,通过构造函数创建出来的实例会有指针指向原型得到原型的属性和方法.这样,实例对象就带有构造函数的属性方法和原型的属性方法,然后将需要继承的构造函数的原型指向这个实例,即可拥有这个实例的所有属性方法实现继承. 看下面演示代码: //声明超类,通过构造函数和原型添加有关属性和方法 function Super(){ this.property = true; } Super.prototype.ge

  • JavaScript的原型继承详解

    JavaScript是一门面向对象的语言.在JavaScript中有一句很经典的话,万物皆对象.既然是面向对象的,那就有面向对象的三大特征:封装.继承.多态.这里讲的是JavaScript的继承,其他两个容后再讲. JavaScript的继承和C++的继承不大一样,C++的继承是基于类的,而JavaScript的继承是基于原型的. 现在问题来了. 原型是什么?原型我们可以参照C++里的类,同样的保存了对象的属性和方法.例如我们写一个简单的对象 复制代码 代码如下: function Animal

  • JavaScript使用原型和原型链实现对象继承的方法详解

    本文实例讲述了JavaScript使用原型和原型链实现对象继承的方法.分享给大家供大家参考,具体如下: 实际上JavaScript并不是一门面向对象的语言,不过JavaScript基于原型链的继承方式.函数式语法,使得编程相当灵活,所以可以利用原型链来实现面向对象的编程. 之前对JavaScript一直都是一知半解,这两天看了一下原型链这一块知识,综合练习了一下JavaScript的对象继承方式. 以下就是原型链和原型的关系,引用网上的一张图 在Javascript中,每个函数都有一个原型属性p

  • 再谈javascript原型继承

    真正意义上来说Javascript并不是一门面向对象的语言,没有提供传统的继承方式,但是它提供了一种原型继承的方式,利用自身提供的原型属性来实现继承. 原型与原型链 说原型继承之前还是要先说说原型和原型链,毕竟这是实现原型继承的基础. 在Javascript中,每个函数都有一个原型属性prototype指向自身的原型,而由这个函数创建的对象也有一个__proto__属性指向这个原型,而函数的原型是一个对象,所以这个对象也会有一个__proto__指向自己的原型,这样逐层深入直到Object对象的

  • 深入理解JS继承和原型链的问题

    对于那些熟悉基于类的面向对象语言(Java 或者 C++)的开发者来说,JavaScript 的语法是比较怪异的,这是由于 JavaScript 是一门动态语言,而且它没有类的概念( ES6 新增了class 关键字,但只是语法糖,JavaScript 仍旧是基于原型). 涉及到继承这一块,Javascript 只有一种结构,那就是:对象.在 javaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接.这个原型对象又有自己的原型,直到某个对象的原型为null 为止

随机推荐