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 

  1. 继承的私房图

构造函数里面有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的基本使用相关推荐

  1. 夯实基础,彻底掌握js的核心技术(四):ES5、ES6对象方法详解

    ES5 Object 对象方法扩展 ES5给Object扩展了一些静态方法,常用的2个 Object.create(prototype,[descriptors]) 作用:以指定对象为原型创建新的对象 ...

  2. ES5和ES6的继承有哪些优劣?

    突然看到继承,感觉对这个概念有点模糊,掌握的知识点不太全面牢固,所以才有了这篇博客. 在我的印象里,ES5的继承我只知道三种:通过构造函数继承.通过原型链继承.通过构造函数和原型链组合继承 对ES6的 ...

  3. golang 解析php序列化,golang实现php里的serialize()和unserialize()序列和反序列方法详解...

    Golang 实现 PHP里的 serialize() . unserialize() 安装 go get -u github.com/techleeone/gophp/serialize 用法 pa ...

  4. C语言标准库里的获取时间函数及时间格式转换详解

    C语言标准库里的获取时间函数及时间格式转换详解 头文件: #include <time.h> 相关库函数(截图摘自:https://www.runoob.com/cprogramming/ ...

  5. class括号里的object_听说你在找python中class的定义及使用教程?看这里就对了

    这篇文章主要介绍了python中class的定义及使用,本文通过实例代码给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下. 类的定义 class classname[(父类名)]: ...

  6. jsx怎么往js里传参数_给js文件传参数(详解)

    一.利用全局变量 这是最简单的一种方式,比如Google Adsense: 缺点是引入了全局变量.其中引入文件的方式还有两个变体: // 变体1:用document.write输出 document. ...

  7. JavaScript ES5之Object.create函数详解

    介绍 在创建对象的时候,我们有2种常用方法 一个是文本标记法(var obj = {}),一种是运用Object函数进行对象的创建(new Object()). 但是这两种方式并不是创建的一个完完全全 ...

  8. oracle里面的terminate,c++  ooci  oracle中的ResultSet详解

    这篇文章并没有给出如何使用ResultSet的具体例子,只是从ResultSet的功能性上进行了详细的讲述.希望这篇文章对大家理解ResultSet能够有所帮助.下面就是这篇文章的具体内容. 结果集( ...

  9. java里类得继承详细讲解_java中类的继承详解。

    前言 继承是面向对象的三大特征之一. 也是实现软件复用的重要手段. Java继承具有单继承的特点, 每个子类只有一个直接父类. 继承的特点 Java的继承通过extends关键字实现. 实现继承的类被 ...

  10. android里的editText怎么用,Android自定义控件EditText使用详解

    本文实例为大家分享了Android自定义控件EditText的具体代码,供大家参考,具体内容如下 自定义控件分三种: 1. 自绘控件 2. 组合控件 3. 继承控件 代码已上传到 github 以后的 ...

最新文章

  1. 【iOS 开发】iOS 10.3 如何更换 app 图标
  2. token 的设计方案
  3. 玩转Win10的45个快捷键
  4. 通过 .NET NativeAOT 实现用户体验升级
  5. 【转】什么是CORS
  6. java 嵌套listview_ListView嵌套GridView使用详解
  7. DiskFileItemFactory类的使用
  8. JSK-17 X的平方根【二分法】
  9. 每日 30 秒 ⏱ 字符编码排雷录
  10. 6.解决AXIOS的跨域问题
  11. HDU 2196 Computer 树形DP
  12. sonar pmd\p3c插件源码初步解析
  13. 图像检索--联合加权聚合深度卷积特征的图像检索方法
  14. 万字讲述如何通过Doris构建数据中台
  15. 2021-07-27 Vue修改主页
  16. 主表先查出数据再左连接
  17. mysql 错误 1548_mysql报1548错误-Cannot load from mysql.proc. The table is probably corrupted
  18. java流意外结束_SyntaxError:输入节点js的意外结束
  19. 基于yolov5+deepsort的智能售货机商品目标检测种类识别计数
  20. linux 搭建webserver-Goahead

热门文章

  1. 几个更新(Update声明)查询方法
  2. 会翻页GridView-1
  3. xcode 4.5中设置程序名字多语言
  4. Android系统Surface机制的SurfaceFlinger服务渲染应用程序UI的过程分析(2)
  5. 对MYSQL进行压力测试
  6. Web API 2 入门——使用Web API与ASP.NET Web窗体(谷歌翻译)
  7. Svn常见问题及相关原因
  8. for循环与each的区别
  9. android sqlite 保存图片,android-如何将图像在Sqlite数据库中另存为blob?
  10. python试卷生成_小学初中高中试卷自动生成