当前位置: 首页 > 编程笔记 >

浅谈JS的原型和继承

胥英奕
2023-03-14
本文向大家介绍浅谈JS的原型和继承,包括了浅谈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 ECMAScript 2015)),它们的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原型和继承详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对小牛知识库网站的支持!

 类似资料:
  • 本文向大家介绍再谈javascript原型继承,包括了再谈javascript原型继承的使用技巧和注意事项,需要的朋友参考一下 真正意义上来说Javascript并不是一门面向对象的语言,没有提供传统的继承方式,但是它提供了一种原型继承的方式,利用自身提供的原型属性来实现继承。 原型与原型链 说原型继承之前还是要先说说原型和原型链,毕竟这是实现原型继承的基础。 在Javascript中,每个函数都

  • 本文向大家介绍浅谈Javascript中的对象和继承,包括了浅谈Javascript中的对象和继承的使用技巧和注意事项,需要的朋友参考一下 Javascript是一门函数式编程语言,Javascript当中函数是核心,在Javascript中函数也是对象,函数对象在创建的时候会被添加属性和方法。 在Javascript中函数对象有两种调用方式,一种是new关键字的调用,另一种是没有new关键字的调

  • 本文向大家介绍浅谈js构造函数的方法与原型prototype,包括了浅谈js构造函数的方法与原型prototype的使用技巧和注意事项,需要的朋友参考一下 把方法写在构造函数内的情况我们简称为函数内方法,把方法写在prototype属性上的情况我们简称为prototype上的方法。 •函数内的方法: 使用函数内的方法我们可以访问到函数内部的私有变量,如果我们通过构造函数new出来的对象需要我们操作

  • 本文向大家介绍浅谈C# 类的继承,包括了浅谈C# 类的继承的使用技巧和注意事项,需要的朋友参考一下 继承 一个类可以继承自另一个类。在 C#中,类与类之间只存在单一继承。也就是说,一个类的直接基类只能有一个。当类与类之间实现继承的时候,子类可以将它的直接基类的所有成员当做自己的成员,除了类的静态构造方法、实例构造方法和析构方法。但是,虽然基类的所有成员都可以当做子类的成员,但是如果基类的成员设置了

  • 本文向大家介绍浅谈JS之tagNaem和nodeName,包括了浅谈JS之tagNaem和nodeName的使用技巧和注意事项,需要的朋友参考一下 nodeName是节点的属性,tagName是元素的属性。元素是节点的子集。不是任何节点都有tagName的,比如文本节点,仅有nodeName属性。 这个和css中的倾斜和斜体的关系是一样的。不是所有元素都有斜体的,但是都能倾斜。 以上这篇浅谈JS之

  • 这里我们只介绍继承、原型的基本概念和其常见使用方式。要完整理解继承,需要读者自行补充阅读面向对象编程的发展历史和一些核心思想。简而言之,继承是为了更好的代码或接口复用。 举个例子,如果我们要在界面上构建若干个面板组件,每个面板包含不同的内容和元素,但要求每个面板都可以被隐藏或显示、漂浮或定位,那么最原始的方法是在每个面板对象中添加show/hide/float/dock方法。 这样就存在大量的代码