class括号里的object_使用es5和es6实现继承详解以及class的基本使用
1.所有的对象都是由Object构造的,所以对象的__ proto __最终都指向于Object.prototype
//下面两个都是对象
2.js继承的实质就是两次的原型搜索就是继承
比如:
var
上面的a可以使用valueOf方法实际上是通过了两次原型链的搜索最终在Object.prototype里拿到了valueOf方法,所以可以说valueOf方法是继承来的
再换一种通俗易懂的方法来描述对于下图
父元素div里面有个span,父元素div的fontsize是18px,如果给span设置一个14px,那span里面的字就是14px,这不叫继承,这是span本身就有的,而如果不给span设置字体大小span里的字就是18px,这叫继承,继承了div的18px,所以上面的Array.prototype就相当于span,Object.prototype就相当于div
自己实现原型链继承
上面的结构就是我们要实现的,其中子类的Human和父类Object之间的继承是自带的,我们需要在Human后再加一个Man继承Human
使用es5实现继承
function
上面的代码实现了最底层的Man,但是他还没有Human的属性和方法,因为男人是人的一种需要有名字和会跑,也就是我们需要Man继承Human的属性和方法,这时候我们只需要在第一层原型和第二层中间加一层,让这一层指向Human.prototype就行,然后因为每个人都有自己的名字,所以name要加在sex下,也就是下图(这里注意一点chrome里面显示的__proto__后面没有带prototype)
第一步:将name加到Man本身,也就是将Human本身的属性直接写在Man上,
function
这时候就实现了我们的第一步,接下来就是在两层原型之间再加一层也就是让第一层的Man.prototype.__ proto __ = Human.prototype
这样一个继承就实现了
最后把前面的代码总结一下:
function
- 继承的私房图
构造函数里面有prototype,而函数.prototype实际上是一个对象,所以存的是一个内存地址,也就是存放共有属性的地址,上图中Object里的prototype存放的是左边的101,Human存放的是309,然后Man中存放的是401,之后当我们声明一个实例对象的时候(这里以图中的m为例),m里面就有我们的sex和name属性还有对象固有的__proto__;
因为实例对象. _proto__指向构造函数.prototype所以它的 __ proto __ 指向的是Man.prototype而它存的地址是401,所以m里的 __ proto __ 指向的就是401,这也就是第一层;
然后继续401也就是Man.prototype.__proto__ 指向的是Human.prototype也就是309,这也就是第二层;
之后309也就是Huam.prototype._proto_ 指向的是Object.prototype也就是101,这也就是第三层;
最后101也就是Object.prototype.__proto__指向的是null
2.改进
因为ie不支持__proto__的操作,所以我们不能直接用
Man.prototype.__proto__ = Human.prototype
使用下面三句代码可以代替上面的一句
var
我们先通过一个简单的例子来对上面的三句话理解,比如我要实现一个a.__ proto __ = b,因为我不能直接操作__ proto __,但是我可以通过new来操作它,因为当我们new一个实例对象的时候,这里以var obj = new Fn()为例,其实这个new的过程中进行了五步操作
1. 产生一个空对象
2. this = 空对象
3. this.__ proto __ = Fn.prototype
4. 执行Fn.call(this,x,y,z...)
5. 返回 this
一、我们想对__ proto __进行操作直接在new的第3步中就可以,只要能让this等于a,让Fn.prototype等于b就可以。
首先让this等于a,因为this本身就是实例对象,所以我们只需要把obj换成a就可以了也就是a = new Fn(); 其次让Fn.prototype等于b,也就是直接将b赋值给Fn.prototype,即Fn.prototype = b
二、然后把a. __ proto _ = b换成我们一开始的Man.prototype.__proto__ = Human.prototype,所以a就是Man.prototype,b就是Human.prototype
这时候我们一中的Fn.prototype = b就可以换成Fn.prototype = Human.prototype,所以Fn就等于Human,接着我们就可以把a = new Fn()换成Man.prototype = new Human(),所以Man.prototype = new Human()就等价于Man.prototype. __ proto __ = Human.prototype
问题:上面的Man.prototype = new Human()虽然实现了我们想要的Man.prototype. __ proto __ = Human.prototype,但是因为new过程中的第四步对this的操作,会导致我们的Human.prototype中会有我们不想要的东西,比如将上面的实现继承的代码进行更改
运行后发现Man.prototype里面多了个name,因为在我们new Human()的时候,它会去执行Human,在你当前对象中加个name,当前对象就是Man.prototype,所以才会多个name,但是我们又不能直接把Human里的this.name=name删掉,所以我们就需要一个没有this.name=name的但是还保留Human.prototype里原型的属性和方法的空函数,也就是我们最开始的三句代码
var
最终es5实现继承的完整代码:
function
es6实现继承
class
代码详解:
es6中类的写法:自身属性写在constructor里面,共有属性(原型链上的)run直接和他并列着写
继承的写法:class后面是子类然后extends你的父类
也就是
Man
然后super(name)就等价于Human.call(this,name),super就是调用Human
另外如果要使用class在原型中声明一个属性的话需要通过get
class
static
static关键字用来定义一个类的一个静态方法。调用静态方法不需要实例化该类,但不能通过一个类实例调用静态方法,也就是我们通过static声明的方法可以直接通过类名.方法使用,但不可以通过实例.方法使用
比如:
上面的One这个类里的a方法没有使用static关键字,所以我们直接调用One.a()报错,而通过实例化One后在调用a方法就可以
Two这个类里的a使用了static所以可以直接通过Two.a()调用,但是通过Two的实例调用a方法就会报错
使用:一般我们需要调用一个方法给当前类添加一个属性的时候使用
比如:
class Validator {constructor(){}static add(name,fn){Validator.prototype[name]=fn}
}
//给当前类添加一个
Validator.add('hasNumber',(value)=>{if(!/d/.test(value)){return '必须含有数字'}
})
class括号里的object_使用es5和es6实现继承详解以及class的基本使用相关推荐
- 夯实基础,彻底掌握js的核心技术(四):ES5、ES6对象方法详解
ES5 Object 对象方法扩展 ES5给Object扩展了一些静态方法,常用的2个 Object.create(prototype,[descriptors]) 作用:以指定对象为原型创建新的对象 ...
- ES5和ES6的继承有哪些优劣?
突然看到继承,感觉对这个概念有点模糊,掌握的知识点不太全面牢固,所以才有了这篇博客. 在我的印象里,ES5的继承我只知道三种:通过构造函数继承.通过原型链继承.通过构造函数和原型链组合继承 对ES6的 ...
- golang 解析php序列化,golang实现php里的serialize()和unserialize()序列和反序列方法详解...
Golang 实现 PHP里的 serialize() . unserialize() 安装 go get -u github.com/techleeone/gophp/serialize 用法 pa ...
- C语言标准库里的获取时间函数及时间格式转换详解
C语言标准库里的获取时间函数及时间格式转换详解 头文件: #include <time.h> 相关库函数(截图摘自:https://www.runoob.com/cprogramming/ ...
- class括号里的object_听说你在找python中class的定义及使用教程?看这里就对了
这篇文章主要介绍了python中class的定义及使用,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下. 类的定义 class classname[(父类名)]: ...
- jsx怎么往js里传参数_给js文件传参数(详解)
一.利用全局变量 这是最简单的一种方式,比如Google Adsense: 缺点是引入了全局变量.其中引入文件的方式还有两个变体: // 变体1:用document.write输出 document. ...
- JavaScript ES5之Object.create函数详解
介绍 在创建对象的时候,我们有2种常用方法 一个是文本标记法(var obj = {}),一种是运用Object函数进行对象的创建(new Object()). 但是这两种方式并不是创建的一个完完全全 ...
- oracle里面的terminate,c++ ooci oracle中的ResultSet详解
这篇文章并没有给出如何使用ResultSet的具体例子,只是从ResultSet的功能性上进行了详细的讲述.希望这篇文章对大家理解ResultSet能够有所帮助.下面就是这篇文章的具体内容. 结果集( ...
- java里类得继承详细讲解_java中类的继承详解。
前言 继承是面向对象的三大特征之一. 也是实现软件复用的重要手段. Java继承具有单继承的特点, 每个子类只有一个直接父类. 继承的特点 Java的继承通过extends关键字实现. 实现继承的类被 ...
- android里的editText怎么用,Android自定义控件EditText使用详解
本文实例为大家分享了Android自定义控件EditText的具体代码,供大家参考,具体内容如下 自定义控件分三种: 1. 自绘控件 2. 组合控件 3. 继承控件 代码已上传到 github 以后的 ...
最新文章
- 【iOS 开发】iOS 10.3 如何更换 app 图标
- token 的设计方案
- 玩转Win10的45个快捷键
- 通过 .NET NativeAOT 实现用户体验升级
- 【转】什么是CORS
- java 嵌套listview_ListView嵌套GridView使用详解
- DiskFileItemFactory类的使用
- JSK-17 X的平方根【二分法】
- 每日 30 秒 ⏱ 字符编码排雷录
- 6.解决AXIOS的跨域问题
- HDU 2196 Computer 树形DP
- sonar pmd\p3c插件源码初步解析
- 图像检索--联合加权聚合深度卷积特征的图像检索方法
- 万字讲述如何通过Doris构建数据中台
- 2021-07-27 Vue修改主页
- 主表先查出数据再左连接
- mysql 错误 1548_mysql报1548错误-Cannot load from mysql.proc. The table is probably corrupted
- java流意外结束_SyntaxError:输入节点js的意外结束
- 基于yolov5+deepsort的智能售货机商品目标检测种类识别计数
- linux 搭建webserver-Goahead
热门文章
- 几个更新(Update声明)查询方法
- 会翻页GridView-1
- xcode 4.5中设置程序名字多语言
- Android系统Surface机制的SurfaceFlinger服务渲染应用程序UI的过程分析(2)
- 对MYSQL进行压力测试
- Web API 2 入门——使用Web API与ASP.NET Web窗体(谷歌翻译)
- Svn常见问题及相关原因
- for循环与each的区别
- android sqlite 保存图片,android-如何将图像在Sqlite数据库中另存为blob?
- python试卷生成_小学初中高中试卷自动生成