JS面向对象,创建,继承
很开心,最近收获了很多知识,而且发现很多东西,以前理解的都是错的,或者是肤浅的,还以为自己真的就get到了精髓,也很抱歉会影响一些人往错误的道路上走,不过这也告诉了我们,看任何一篇文章都不能盲目的去相信,要实践验证再验证。今天就重新整理一下,我对面向对象的理解,当然也不保证完全正确的,但绝对是在进步的,抛砖引玉,希望能带来一些新的感悟。
对象,通俗的来说,就是属性和方法。定义就不再多说,下面说对象的创建:
1 创建一个面向对象
var obj = new Object(); //创建一个空对象obj.name = 'haha'; obj.showName = function(){ alert(obj.name); } obj.showName();
缺点:当我们想创建多个面向对象的时候,重复代码过多,需要封装,所以有了下面的方法
2 工厂方式
function CreatePerson(name){ //原料var obj = new Object(); //加工obj.name = name;obj.showName = function(){ alert(this.name);} //出厂return obj; }var p1 = CreatePerson('haha'); p1.showName();var p2 = CreatePerson('hehe'); p2.showName();
这其实就是简单的封装函数,整个过程像工厂的流水线,所以叫工厂方式
缺点:无法识别创建的对象的类型。因为全部都是Object,没有区分度,不像Date、Array等,因此出现了构造函数模式。
3 构造函数模式
我们要通过这二个方面来改变:1 函数名首字母大写 2 New 关键字调用
function CreatePerson(name){ this.name = name; this.showName = function(){ alert(this.name); } } var p1 =new CreatePerson('haha'); p1.showName();var p2 = new CreatePerson('hehe');p2.showName();
1首字母大写,是为了区别于普通的函数,构造函数本身就是普通的函数,只是我们专门用它来实现了构造的功能,所以专门起了一个名字叫构造函数,任何函数都可以成为构造函数,这取决于你调用函数的方式。是否用了New。
2 调用函数的时候用了 New关键字,那么New到底做了什么?用不用New有什么区别?再来看下面的例子
function CreatePerson(name){ this.name = name; this.showName = function(){ alert(this.name); };console.log(this); } new CreatePerson('haha'); //CreatePerson{}CreatePerson('haha'); //window
我们会发现当用New去调用一个函数的时候,this的指向会不一样。其实New主要做了下面这些事,不过下面写的只是大概的行为,并不是内部源码。
function CreatePerson(name){ var res = {}; //声明一个空对象resres._proto_= CreatePerson.prototype;//这个对象的_proto_属性指向构造函数的原型对象,这样res就可以调用CreatePerson原型对象下的所有方法CreatePerson.apply(res);//把this指向改为res对象this.name = name; //res对象添加属性,方法this.showName = function(){ alert(this.name); }; return res;//返回这个对象}
关于New做时候都是内部的行为,看不到但确实存在,关于上面原型可以先大概知道结论,下面会说原型,接着看就懂了。
函数构造模式存在的问题:
alert(p1.showName==p2.showName);//false
测试这个代码,两个方法是不相同的,也就是说这两个对象并不是共用一个方法,每new一次,系统都会新创建一个内存,这两个对象各自有各自的地盘,但他们具有相同的功能,还不共用,肯定不是我们所希望的。所以就有了下一种方法,原型+构造模式
4 原型+构造模式
每个函数都有一个prototype属性,它是一个对象,也称作原型对象,这个原型对象,我们可以把方法和属性写在它上面(不过原型对象不仅仅有我们写的属性和方法,还有别的,下面会介绍),而通过这个函数创建出来的实例对象,都能共享这个原型对象下的方法和属性。所以我们只需要把想要共享的东西放在函数的prototype下,不想共享的东西通过构造函数来创建就可以了。
看个栗子(原型+构造)
function CreatePerson(name){ this.name = name; }CreatePerson.prototype.showName = function(){ alert(this.name); } var p1 =new CreatePerson('haha'); p1.showName(); var p2 = new CreatePerson('hehe'); p2.showName();alert(p1.showName==p2.showName);//true
通过最后一句的测试为true,可以看到在构造函数的原型下面加的方法showName()方法是所有通过这个构造函数创建出来的对象所共享的,也就是说他们共用一个内存,更进一步的说它们存在引用关系,也就是说你更改了p1的showName也会影响p2的showName。
所以我们在构造对象的时候,一般是原型模式和构造模式组合使用,变化的用构造模式 不变的公用的用原型模式,就像上面的这个栗子,属性用的构造函数,因为一般不同对象属性都不同,方法用原型模式。
_proto_属性:同一个函数造出来的实例对象能共享这个函数的prototype下的方法和属性,但是它是如何做到的呢?这里要出场的就是_proto_属性,每个实例化对象都有一个_proto_属性,它是一个指针,指向函数的prototype,也就是保存了它的地址。(JS中任何对象的值都是保存在堆内存中,我们声明的变量只是一个指针,保存了这个对象的实际地址,所以有了地址就能找到对象),所以总得来说,每个实例化对象都有_proto_属性,保存了构造函数的原型对象的地址,通过这个属性就可以拥有原型对象下的所有属性和方法,_proto_属性实际就是实例化对象和原型对象之间的连接。
原型链: 每个函数都可以成为构造函数,每个函数都有原型对象,每个原型对象也可以是一个实例化对象,比如,你创建了一个函数fun,它是构造函数function的实例化对象,而function的原型对象,又是Object的实例对象。所以fun有个_proto_属性可以访问到function的原型对象,function原型对象也是个实例对象,也有个_proto_属性,可以访问到Object的原型对象,所以通过_proto_属性,就形成了一条原型链。每个实例化对象都可以访问到链子上方的方法和属性,所以fun是可以访问Object原型对象下的方法和属性的。实际上所有对象都可以访问到Object的原型对象。
原型链的访问规则:先在自身的下面寻找,再去一级一级的往原型链上找。如下:
function Aaa(){} Aaa.prototype.num = 3;var a1 = new Aaa(); a1.num =10; alert(a1.num); //10
原型对象下的方法和属性:原型对象下面可能有三大类:1 原型对象所带方法和属性 2 constructor 3 _proto_
constructor:构造函数属性,每个函数的原型对象都有的默认属性,指向函数。每个实例化对象本身是没有constructor属性的,每个实例化对象下面都默认只有一个_proto_,用来连接原型对象,而和构造函数本身是没有直接的联系的。所以它的constructor是访问的原型对象上的。所以当原型对象的constructor变化了,实例化对象的constructor也会改变。但是如果这个对象本身既是原型对象,又是实例化对象,那就拥有了constructor属性,无需从原型对象继承。
看下面的例子,来验证我们所说的:
CreatePerson(name){ .name = name; } CreatePerson.prototype.showName = (){console.log(.name); }; p1 = CreatePerson('haha'); p1.showName(); console.log(p1.constructor); console.log(CreatePerson.prototype); console.log(CreatePerson.prototype.__proto__===Object.prototype);console.log(CreatePerson.prototype.__proto__===Object);console.log(CreatePerson.prototype.constructor);console.log(Object.prototype.__proto__); console.log(CreatePerson.__proto__); console.log(CreatePerson.constructor); console.log(CreatePerson.prototype CreatePerson )
字面量法定义原型:
为了创建对象的代码更方便,你一定见过这样的代码,就是字面量法:
function Aaa(){} Aaa.prototype = {showName:function(){alert(10);} }; var a1 = new Aaa(); console.log(Aaa.prototype);//{showName:function(){},_proto_} 你会发现constructor不见了,因为这种方式相当于重新赋值了Aaa.prototype console.log(Aaa.prototype.constructor);//Object 因为自身没有了constructor属性,就去上级原型对象找,找到了Objectconsole.log(a1.constructor );//Object 也变了,验证了它是访问的原型对象上的
因此我们在写的时候需要修正一下原型的指向:
function Aaa(){} Aaa.prototype = {constructor:Aaa,num1:function(){alert(10);} } var a1 = new Aaa(); a1.constructor // Aaa
理解了这些,继承就很好理解了,下回继续补充。有错误,欢迎纠正。
转载于:https://blog.51cto.com/12879490/1921937
JS面向对象,创建,继承相关推荐
- 捋一捋js面向对象的继承问题
说到面向对象这个破玩意,曾经一度我都处于很懵逼的状态,那么面向对象究竟是什么呢?其实说白了,所谓面向对象,就是基于类这个概念,来实现封装.继承和多态的一种编程思想罢了.今天我们就来说一下这其中继承的问 ...
- js面向对象和继承的碎碎念
2019独角兽企业重金招聘Python工程师标准>>> 一.prototype属性的特点: 1.定义在prototype中的方法是"实例方法",必须是new出来的 ...
- JS面向对象的程序设计之继承-继承的实现-借用构造函数
JS面向对象的程序设计之继承-继承的实现-借用构造函数 前言:最近在细读Javascript高级程序设计,对于我而言,中文版,书中很多地方翻译的差强人意,所以用自己所理解的,尝试解读下.如有纰漏或错误 ...
- JS 面向对象编程、原型链、原型继承(个人学习总结)
一.面向对象 1. 面向对象 是所有语言 都有的一种编程思想,组织代码的一种形式 基于对象的语言:JS语言 面向对象的语言:c++ java c# 2. 面向对象 3大特征 封装:将重用代码封装到函数 ...
- js面向对象之封装,继承,多态,类的详解
封装 在面向对象的操作中,我们有完全不同的一些写法. 想要封装我们的对象,就要用到构造函数.我们需要创建构造函数,构造函数和函数一致,都是通过function创建的 首字母大写(规范,为了和普通函数进 ...
- js中的面向对象、继承、函数重写
通过示例讲解 一下,先看一个示例 示例demo: <script>//创建一个父函数(父类)var Mammal = function (name) {this.name = name;} ...
- JavaScript(JS) 面向对象(封装、继承、多态)
面向对象是把事物给对象化,包括其属性和行为.面向对象编程更贴近实际生活的思想.可以简单的理解面向对象的底层还是面向过程,面向过程抽象成类,然后封装,方便使用就是面向对象.本文主要介绍JavaScrip ...
- JS面向对象一:MVC的面向对象封装
JS面向对象一:MVC的面向对象封装 MDNjavascript面向对象 面向对象(Object-Oriented) 面向对象里面向的意思是以...为主,面向对象编程既以对象为主的编程. 面向对象的一 ...
- 简单粗暴地理解js原型链–js面向对象编程
简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...
- 对js面向对象的理解
转自:http://www.cnblogs.com/jingwhale/p/4678656.html js面向对象理解 ECMAScript 有两种开发模式:1.函数式(过程化),2.面向对象(OOP ...
最新文章
- mysql文件查看工具_OpenDBViewer
- 监听浏览器返回上一页
- 通过Windows远程桌面连接将远程文件传输至本地
- 关于MD5破解这件事
- mysql 命令删库名,MySQL控制台删除数据库命令 drop database 数据库名
- MS SQL 语句中的字符串连接
- 移位 c语言一个变量存储两个值,【杭州C 培训】C语言中基础小问题总结
- 科学使用Live2D的方法
- Pycharm更换主题
- 双拼输入法是个啥以及我是如何学会使用它的
- 康佳电视应用助手服务器连接超时,康佳电视程序无响应怎么办?详细解决方法...
- Activity任务栈
- 基础篇:6.9)形位公差-检测方法Measurement
- 计算机d盘可以格式化吗,d盘怎么格式化
- AutoIt上路03-添加工具栏
- 2020南京市(徐庄)高层次创业人才引进计划开启申报
- 非共识大会 | 伍鸣博士:DApp发展需要一条高性能且安全的公链
- uniapp封装方法
- ferguson博弈_组合博弈游戏
- A代表数字1,B代表数字2,以此类推Z代表26
热门文章
- boost::contract模块实现name list名单的测试程序
- Boost:字符串裁剪Trim的测试程序
- ITK:使用曲率流平滑图像
- ITK:无写访问权限下遍历具有邻域的图像区域
- DCMTK:在OFFile类中non-trivial fseek和ftell实现的测试程序
- VTK:可视化之CollisionDetection
- VTK:Points之ExtractSurface
- OpenCV文件输入输出的序列化功能的实例(附完整代码)
- OpenCV点分类器points classifier的实例(附完整代码)
- OpenCV视网膜和现实世界的视野