JavaScrpt的面向对象全面解析


Posted in Javascript onMay 09, 2017

每次说到javascript的面向对象,总感觉自己心里懂,但是却不知道该怎么说,这就是似懂非懂到表现,于是乎,每次一说,就要到处去查找资料,零零碎碎到看了一些,感觉有懂了,但是过段时间,好像又不知道是怎么回事了,于是乎,又到处找资料,然道是我本来就缺对象?才不理解对象是啥,以至于现实中找找对象,javascript中也在找对象!哎,好尴尬啊!直到我看到了一个妹纸写到“不可不知的javascript面向对象”,我才明白面向对象是什么,这是不是说我要找到对象就是这个妹纸呢?,先记录一下备忘吧,下面是妹纸写到主要内容:

对象的创建:

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 构造函数模式

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到底做了什么?用不用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 obj = {}; //声明一个空对象obj 
 obj._proto_= CreatePerson.prototype;
 //把这个对象的_proto_属性指向构造函数的原型对象,这样obj就可以调用CreatePerson原型对象下的所有方法 ,这里原型先知道结论,下面会讲。
 CreatePerson.apply(obj); //用apply方法让this指向obj对象
 this.name = name; //obj对象添加属性,方法
 this.showName = function(){ 
  alert(this.name);
  }; 
 return obj;//返回这个对象
}

函数构造模式存在的问题:

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

JavaScrpt的面向对象全面解析

原型对象:

原型对象下可能有三种属性:

1 原型对象所带方法和属性 2 constructor 3_proto_属性

constructor:构造函数属性,每个函数的原型对象都有的默认属性,指向函数。

每个实例化对象本身是没有constructor属性的,他们下面默认只有一个_proto_属性,用来连接原型对象,而和构造函数本身是没有直接的联系的。所以它的constructor是访问的原型对象上的。所以当原型对象的constructor变化了,实例化对象的constructor也会改变。但是如果这个对象本身既是原型对象,又是实例化对象,那就拥有了constructor属性,无需从原型对象上面访问。**

看下面的例子,来验证我们所说的:

function CreatePerson(name){ 
 this.name = name;
}
CreatePerson.prototype.showName = function(){ 
 console.log(this.name);
 };
var p1 =new CreatePerson('haha');
p1.showName();
console.log(p1.constructor); // CreatePerson 来自CreatePerson.prototype
console.log(CreatePerson.prototype); 
// {showName:{},constructor:CreatePerson,__proto__:Object.prototype}
//可见,原型对象保存了
  1 自身添加的方法,
  2 构造函数constructor 
  3 _proto_(和上一层构造函数原型对象的连接)
console.log(CreatePerson.prototype.__proto__===Object.prototype);
// true 这个原型对象本身又是object的实例化对象,所有_proto_指向Object的原型对象
console.log(CreatePerson.prototype.__proto__===Object);
// false 可见是和构造函数下原型对象的连接,不是构造函数
console.log(CreatePerson.prototype.constructor);
//CreatePerson CreatePerson.prototype是Object实例化对象,也是原型对象,所以自身拥有constructor属性
console.log(Object.prototype.__proto__); 
// null 原型链的终点是null
console.log(CreatePerson.__proto__); //function.prototype
// CreatePerson本身既是构造函数又是function的实例化对象,拥有_proto_属性,指向function的原型对象
console.log(CreatePerson.constructor); 
// function 继承自function.prototype
console.log(CreatePerson.prototype instanceof CreatePerson ) 
//验证是否在一条原型链上 false

字面量法定义原型:

为了创建对象的代码更方便,你一定见过这样的代码,就是字面量法:

function Aaa(){}
Aaa.prototype = { 
 showName:function(){},
 showSex:function(){}
}; 
var a1 = new Aaa();
console.log(Aaa.prototype);
//{showName:function(){},_proto_} 
//你会发现constructor不见了,因为这种方式相当于重新赋值了Aaa.prototype 
console.log(Aaa.prototype.constructor);
//Object 因为自身没有了constructor属性,就去上级原型对象找,找到了Object
console.log(a1.constructor );
//Object 也变了,验证了它是访问的原型对象上的

因此我们在写的时候需要修正一下原型的指向:

function Aaa(){}
Aaa.prototype = { 
constructor:Aaa, 
num1:function(){alert(10);}
}
var a1 = new Aaa();
a1.constructor // Aaa

 以上所述是小编给大家介绍的JavaScrpt的面向对象全面解析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
js 数组克隆方法 小结
Mar 20 Javascript
javascript Event对象详解及使用示例
Nov 22 Javascript
JS OffsetParent属性深入解析
Jan 13 Javascript
jquery.Ajax()方法调用Asp.Net后台的方法解析
Feb 13 Javascript
jQuery实现滚动切换的tab选项卡效果代码
Aug 26 Javascript
jQuery操作基本控件方法实例分析
Dec 31 Javascript
require.js 加载 vue组件 r.js 合并压缩的实例
Oct 14 Javascript
js获取元素下的第一级子元素的方法(推荐)
Mar 05 Javascript
angularJs-$http实现百度搜索时的动态下拉框示例
Feb 27 Javascript
AngularJS实现与后台服务器进行交互的示例讲解
Aug 13 Javascript
一文了解vue-router之hash模式和history模式
May 31 Javascript
JS使用正则表达式判断输入框失去焦点事件
Oct 16 Javascript
ES6正则表达式的一些新功能总结
May 09 #Javascript
Vuex和前端缓存的整合策略详解
May 09 #Javascript
基于JS实现限时抢购倒计时间表代码
May 09 #Javascript
js使用i18n实现页面国际化的方法
May 09 #Javascript
Angular中$state.go页面跳转并传递参数的方法
May 09 #Javascript
Vue 2.0中生命周期与钩子函数的一些理解
May 09 #Javascript
JavaScript中splice与slice的区别
May 09 #Javascript
You might like
微信随机生成红包金额算法php版
2016/07/21 PHP
javascript新手语法小结
2008/06/15 Javascript
jQuery DIV弹出效果实现代码
2009/07/03 Javascript
Javascript 继承机制的实现
2009/08/12 Javascript
JQuery中判断一个元素下面是否有内容或者有某个标签的判断代码
2012/02/02 Javascript
jquery 事件冒泡的介绍以及如何阻止事件冒泡
2012/12/25 Javascript
js简单的表格添加行和删除行操作示例
2014/03/31 Javascript
jQuery聚合函数实例
2015/05/21 Javascript
JavaScript操作Cookie方法实例分析
2015/05/27 Javascript
简介JavaScript中Math.cos()余弦方法的使用
2015/06/15 Javascript
微信小程序 点击控件后选中其它反选实例详解
2017/02/21 Javascript
JS实现上传图片实时预览功能
2017/05/22 Javascript
Angular2学习教程之TemplateRef和ViewContainerRef详解
2017/05/25 Javascript
vue 2.0项目中如何引入element-ui详解
2017/09/06 Javascript
JS实现简单的浮动碰撞效果示例
2017/12/28 Javascript
Vue2.5通过json文件读取数据的方法
2018/02/27 Javascript
angular中两种表单的区别(响应式和模板驱动表单)
2018/12/06 Javascript
js仿京东放大镜效果
2020/08/09 Javascript
Python的高级Git库 Gittle
2014/09/22 Python
基于Python中求和函数sum的用法详解
2018/06/28 Python
python设计微型小说网站(基于Django+Bootstrap框架)
2019/07/08 Python
python生成任意频率正弦波方式
2020/02/25 Python
pandas使用函数批量处理数据(map、apply、applymap)
2020/11/27 Python
python制作微博图片爬取工具
2021/01/16 Python
css3 利用transform打造走动的2D时钟
2020/10/20 HTML / CSS
波兰最早的运动鞋精品店之一:Street Supply
2019/08/29 全球购物
英国婚礼商城:Wedding Mall
2019/11/02 全球购物
小学生评语大全
2014/04/18 职场文书
超市创业计划书
2014/09/15 职场文书
深入开展党的群众路线教育实践活动心得体会
2014/11/05 职场文书
初中生300字旷课检讨书
2014/11/19 职场文书
教师见习总结范文
2015/06/23 职场文书
比赛口号霸气押韵
2015/12/24 职场文书
60句有关成长的名言
2019/09/04 职场文书
mybatis使用oracle进行添加数据的方法
2021/04/27 Oracle
详解Laravel框架的依赖注入功能
2021/05/27 PHP