很开心,最近收获了很多知识,而且发现很多东西,以前理解的都是错的,或者是肤浅的,还以为自己真的就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面向对象,创建,继承相关推荐

  1. 捋一捋js面向对象的继承问题

    说到面向对象这个破玩意,曾经一度我都处于很懵逼的状态,那么面向对象究竟是什么呢?其实说白了,所谓面向对象,就是基于类这个概念,来实现封装.继承和多态的一种编程思想罢了.今天我们就来说一下这其中继承的问 ...

  2. js面向对象和继承的碎碎念

    2019独角兽企业重金招聘Python工程师标准>>> 一.prototype属性的特点: 1.定义在prototype中的方法是"实例方法",必须是new出来的 ...

  3. JS面向对象的程序设计之继承-继承的实现-借用构造函数

    JS面向对象的程序设计之继承-继承的实现-借用构造函数 前言:最近在细读Javascript高级程序设计,对于我而言,中文版,书中很多地方翻译的差强人意,所以用自己所理解的,尝试解读下.如有纰漏或错误 ...

  4. JS 面向对象编程、原型链、原型继承(个人学习总结)

    一.面向对象 1. 面向对象 是所有语言 都有的一种编程思想,组织代码的一种形式 基于对象的语言:JS语言 面向对象的语言:c++ java c# 2. 面向对象 3大特征 封装:将重用代码封装到函数 ...

  5. js面向对象之封装,继承,多态,类的详解

    封装 在面向对象的操作中,我们有完全不同的一些写法. 想要封装我们的对象,就要用到构造函数.我们需要创建构造函数,构造函数和函数一致,都是通过function创建的 首字母大写(规范,为了和普通函数进 ...

  6. js中的面向对象、继承、函数重写

    通过示例讲解 一下,先看一个示例 示例demo: <script>//创建一个父函数(父类)var Mammal = function (name) {this.name = name;} ...

  7. JavaScript(JS) 面向对象(封装、继承、多态)

    面向对象是把事物给对象化,包括其属性和行为.面向对象编程更贴近实际生活的思想.可以简单的理解面向对象的底层还是面向过程,面向过程抽象成类,然后封装,方便使用就是面向对象.本文主要介绍JavaScrip ...

  8. JS面向对象一:MVC的面向对象封装

    JS面向对象一:MVC的面向对象封装 MDNjavascript面向对象 面向对象(Object-Oriented) 面向对象里面向的意思是以...为主,面向对象编程既以对象为主的编程. 面向对象的一 ...

  9. 简单粗暴地理解js原型链–js面向对象编程

    简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...

  10. 对js面向对象的理解

    转自:http://www.cnblogs.com/jingwhale/p/4678656.html js面向对象理解 ECMAScript 有两种开发模式:1.函数式(过程化),2.面向对象(OOP ...

最新文章

  1. mysql文件查看工具_OpenDBViewer
  2. 监听浏览器返回上一页
  3. 通过Windows远程桌面连接将远程文件传输至本地
  4. 关于MD5破解这件事
  5. mysql 命令删库名,MySQL控制台删除数据库命令 drop database 数据库名
  6. MS SQL 语句中的字符串连接
  7. 移位 c语言一个变量存储两个值,【杭州C  培训】C语言中基础小问题总结
  8. 科学使用Live2D的方法
  9. Pycharm更换主题
  10. 双拼输入法是个啥以及我是如何学会使用它的
  11. 康佳电视应用助手服务器连接超时,康佳电视程序无响应怎么办?详细解决方法...
  12. Activity任务栈
  13. 基础篇:6.9)形位公差-检测方法Measurement
  14. 计算机d盘可以格式化吗,d盘怎么格式化
  15. AutoIt上路03-添加工具栏
  16. 2020南京市(徐庄)高层次创业人才引进计划开启申报
  17. 非共识大会 | 伍鸣博士:DApp发展需要一条高性能且安全的公链
  18. uniapp封装方法
  19. ferguson博弈_组合博弈游戏
  20. A代表数字1,B代表数字2,以此类推Z代表26

热门文章

  1. boost::contract模块实现name list名单的测试程序
  2. Boost:字符串裁剪Trim的测试程序
  3. ITK:使用曲率流平滑图像
  4. ITK:无写访问权限下遍历具有邻域的图像区域
  5. DCMTK:在OFFile类中non-trivial fseek和ftell实现的测试程序
  6. VTK:可视化之CollisionDetection
  7. VTK:Points之ExtractSurface
  8. OpenCV文件输入输出的序列化功能的实例(附完整代码)
  9. OpenCV点分类器points classifier的实例(附完整代码)
  10. OpenCV视网膜和现实世界的视野