当前位置: 首页 > news >正文

js原型和类---prototype,__proto__,new,class

原型和原型链

在js中,所有的变量都有原型,原型也可以有原型原型最终都指向Object

什么是原型

在js中,一个变量被创建出来,它就会被绑定一个原型;比如说,任何一个变量都可以使用console.log打印,这里是调用了它的toString方法,而变量被创建后可能并没有设置toString方法,但是它任然可以打印,这就从原型中获取的toString方法

 所以可以得到第一点:原型可以提供方法给实例的变量,

原型也是一个对象,或者说对象可以作为原型并赋值给其他变量,这样对象成为了变量的原型,而对象本身也有原型,此时就形成了 ‘链’

同样的这个变量也是一个对象,他也可以作为其他变量的原型,这样‘链’就变得更长了,但是所有的链都有一个最终指向(root终点)--- Object,Obejct是最原始的对象,它包含了所有js变量都共享的方法,它不再有原型属性[[prototype]], 所以在js中一切皆对象中的对象就是指的继承自Object

这里可以总结一下:

  • 原型是一个对象,它可以向继承了自身的变量提供方法(属性)
  • 变量都拥有原型,也可以成为原型,循环下去可以形成‘链’,
  • 链的最顶端是Object对象,它提供了最基本的方法

js通过原型来复用通用的方法和属性,这样极大的减少了变量创建的成本(减少了内存支出,原型的方法属性都存储在原型上,变量中不会复制过来占用内存;也不必每个对象都去书写基本的方法),

tips:

原型链:就前面说到的 变量获得原型,原型又有原型,变量又可以作为原型,这样就形成了‘链’,链的最外层(底层),拥有最多的方法,继承了原型链上所有原型的方法和属性

prototype

在 JavaScript 中,对象有一个特殊的隐藏属性 [[Prototype]](如规范中所命名的),它要么为 null,要么就是对另一个对象的引用。当我们从 object 中读取一个缺失的属性时,JavaScript 会自动从原型中获取该属性。这就是继承,object也可以从中借用方法

prototype不能在变量中被直接引用,通常没有办法遍历或者读取这个属性,所以它在控制台的名称有些特殊,使用[[ ]]引用,但是可以直接去调用它里面的方法,当你使用变量中不存在的属性或者方法,此时会自动向原型中寻找,对应的属性方法并调用,若原型链中没有则返回undefined

但是也有特例,在构造函数中,可以给构造的实例添加原型属性或方法

__proto__

这是一个过时的属性,现在只能在浏览器中使用,它的作用就是指向prototype,给原型添加属性或方法,这样添加的原型属性或方法会被遍历出来(Object.keys,for in),

let animal = {eats: true
};
let rabbit = {jumps: true
};rabbit.__proto__ = animal; // 设置 rabbit.[[Prototype]] = animal

注意__proto__ 与内部的 [[Prototype]] 不一样__proto__ 是 [[Prototype]] 的getter/setter;获取和设置原型可以使用函数 Object.getPrototypeOf/Object.setPrototypeOf 来替代 __proto__ 去 get/set 原型

new

当使用 new 关键字调用函数时,该函数将被用作构造函数。new 将执行以下操作:

  1. 创建一个空的简单 JavaScript 对象作为实例。
  2. 如果构造函数的 prototype 属性是一个对象,则将实例的 原型[[Prototype]] 指向构造函数的 prototype 属性,否则实例将保持为一个普通对象,其 [[Prototype]]为 Object.prototype, 因此,通过构造函数创建的所有实例都可以访问添加到构造函数 prototype 属性中的属性/对象。
  3. 使用给定参数执行构造函数,并将this指向实例
  4. 如果构造函数返回非原始值,则该返回值成为整个 new 表达式的结果。否则,如果构造函数未返回任何值或返回了一个原始值,则返回实例。(通常构造函数不返回值,但可以选择返回值,以覆盖正常的对象创建过程。)

 new的关键点在于,它新建了一个实例对象,同时引入了原型,改变了构造函数的this指向,让实例对象成为了这个构造函数的构造结果

class

class是es6新增的语法糖,它简化了js中构造类的步骤,隐去了对原型的操作(根本上还是原型的操作),js中的类是基于原型的,使用原型达到继承的效果,

以下使用原型prototype和类class构建一个相同的类,

prototype.js

// 使用原型构造一个P类// 构造器,大写开头规范(不强制)
function P (x,y){// this指向实例,此时this不生效,构造实例后指向实例this.x = x;this.y = y;// 实例方法,此处的this指向实例,可以使用实例的属性this.getXY = ()=>{return [this.x,this.y]}
}// 实例方法,此处的this指向windows,不能使用实例的属性
P.prototype.getPName = ()=>{return P.name
}// 实例属性
P.prototype.desc = '2维坐标'//类方法/静态方法 
P.getP = (p1,p2)=>{return [p1.getXY(),p2.getXY()]
}// 类属性/静态属性
P.des = '坐标'

class.js 

// 使用class构造一个P类class P{//构造器constructor(x,y){this.x = x;this.y = y;}// 实例属性desc = '2维坐标'// 实例方法getXY(){return [this.x,this.y]}getPName(){return P.name}// 静态属性static des = '坐标'// 静态方法static getP(p1,p2){return [p1.getXY(),p2.getXY()]}}

很明显,class的用法更加整体化,但实际上这两种的写法效果是完成相同的,

可以使用同一串代码来实例化这个类P

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>prototype,class</title>
</head><body><script src="class.js"></script><!-- <script src="prototype.js"></script> --><script>// new关键字,新建一个对象,原型指向类,获得构造器中的this指向let p = new P(1, 2);console.log(p);console.log(p.x);console.log(p.y);console.log(p.desc);console.log(p.getXY());console.log(p.getPName());console.log(P.getP(p, p));console.log(P.des);</script>
</body></html>

实现的效果是一致的方法上略有不同,对于类的构造,关键在于this的指向问题,属性和方法是挂在类名下的,还是挂在实例下的需要区分开,

挂在类下的属性方法被称为,类方法(属性)或者静态方法(属性),通过类名引用(Math.max)

挂在实例下的属性方法被称为,实例方法(属性),通过实例引用(arr.push)

总结

  • 在 JavaScript 中,所有的对象都有一个隐藏的 [[Prototype]] 属性,它要么是另一个对象,要么就是 null
  • 通过 [[Prototype]] 引用的对象被称为“原型”。
  • "prototype" 属性仅当设置在一个构造函数上,并通过 new 调用时,才具有这种特殊的影响。在常规对象上,prototype 会被当成是一个普通的属性名
  • 所以变量都通过原型/原型链使用共享的方法(即自身不存在,从原型/原型链中借用)
  • 类的使用要区分实例和静态类,哪些方法属性在类名下,哪些方法属性在实例下

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【嵌入式DIY实例-ESP8266篇】-LCD1602显示DS1631传感器数据
  • 前端八股文 vue2和vue3的区别
  • FlinkCDC-3.1.1 DataStream Source
  • 通过gateway 打印日志全局控制日志
  • Java通过GeoLite2-City.mmdb 进行IP信息查询地理定位和经纬度筛选。
  • java代理简单理解
  • 评估测试用例有效性 5个方面
  • 数学建模中常用的数据处理方法
  • c++:内存管理
  • Linux下使用arping检测IP地址是否冲突
  • 智慧园区管理系统建设方案(Word完整原件)
  • 双栈实现一个队列
  • 新手小白的pytorch学习第一弹-------张量
  • 生成日志系统和监控
  • 算法·高精度
  • (十五)java多线程之并发集合ArrayBlockingQueue
  • 2017 前端面试准备 - 收藏集 - 掘金
  • Android 控件背景颜色处理
  • Android交互
  • cookie和session
  • DataBase in Android
  • JS专题之继承
  • Linux中的硬链接与软链接
  • PAT A1092
  • React Transition Group -- Transition 组件
  • react 代码优化(一) ——事件处理
  • Redis字符串类型内部编码剖析
  • V4L2视频输入框架概述
  • VuePress 静态网站生成
  • Windows Containers 大冒险: 容器网络
  • 构建工具 - 收藏集 - 掘金
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 那些年我们用过的显示性能指标
  • 数据科学 第 3 章 11 字符串处理
  • 正则表达式小结
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • #NOIP 2014#day.2 T1 无限网络发射器选址
  • #pragma once与条件编译
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (3)STL算法之搜索
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (Java岗)秋招打卡!一本学历拿下美团、阿里、快手、米哈游offer
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (补充):java各种进制、原码、反码、补码和文本、图像、音频在计算机中的存储方式
  • (二十一)devops持续集成开发——使用jenkins的Docker Pipeline插件完成docker项目的pipeline流水线发布
  • (附源码)计算机毕业设计ssm基于B_S的汽车售后服务管理系统
  • (转)ObjectiveC 深浅拷贝学习
  • (总结)Linux下的暴力密码在线破解工具Hydra详解
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .gitignore文件忽略的内容不生效问题解决
  • .NET delegate 委托 、 Event 事件,接口回调
  • .NET MVC 验证码
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .NET 快速重构概要1