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 相关文章推荐
通过Javascript创建一个选择文件的对话框代码
Jun 16 Javascript
javascript获取和判断浏览器窗口、屏幕、网页的高度、宽度等
May 08 Javascript
推荐6款基于jQuery实现图片效果插件
Dec 07 Javascript
javascript模拟map输出与去除重复项的方法
Feb 09 Javascript
AngularJs表单验证实例详解
May 30 Javascript
原生javascript 学习之js变量全面了解
Jul 14 Javascript
jQuery实现的无限级下拉菜单功能示例
Sep 12 Javascript
关于Vue实现组件信息的缓存问题
Aug 23 Javascript
浅析Vue自定义组件的v-model
Nov 26 Javascript
ES6 对象的新功能与解构赋值介绍
Feb 05 Javascript
mpvue全局引入sass文件的方法步骤
Mar 06 Javascript
js canvas实现星空连线背景特效
Nov 01 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 date函数常用时间处理方法
2015/05/11 PHP
Linux系统中设置多版本PHP共存配合Nginx服务器使用
2015/12/21 PHP
基于jQueryUI和Corethink实现百度的搜索提示功能
2016/11/09 PHP
PHP框架实现WebSocket在线聊天通讯系统
2019/11/21 PHP
Javascript 篱式条件判断
2008/08/22 Javascript
利用Keydown事件阻止用户输入实现代码
2014/03/11 Javascript
javascript生成不重复的随机数
2015/07/17 Javascript
javascript基础知识
2016/06/07 Javascript
jQuery实现为LI列表前3行设置样式的方法【2种方法】
2016/09/04 Javascript
微信小程序简单实现form表单获取输入数据功能示例
2017/11/30 Javascript
原生JS实现的碰撞检测功能示例
2018/05/18 Javascript
浅谈redux以及react-redux简单实现
2018/08/28 Javascript
微信开发之企业付款到银行卡接口开发的示例代码
2018/09/18 Javascript
手挽手带你学React之React-router4.x的使用
2019/02/14 Javascript
js纯前端实现腾讯cos文件上传功能的示例代码
2019/05/14 Javascript
微信打开网址添加在浏览器中打开提示的办法
2019/05/20 Javascript
了解javascript中变量及函数的提升
2019/05/27 Javascript
Vue中实现权限控制的方法示例
2019/06/07 Javascript
vue使用微信JS-SDK实现分享功能
2019/08/23 Javascript
[13:25]VP vs VICI (BO3)
2018/06/07 DOTA
[51:50]完美世界DOTA2联赛 Magma vs GXR 第一场 11.07
2020/11/10 DOTA
Python各类图像库的图片读写方式总结(推荐)
2018/02/23 Python
Python简单实现两个任意字符串乘积的方法示例
2018/04/12 Python
python连接mongodb集群方法详解
2020/02/13 Python
Python3读写Excel文件(使用xlrd,xlsxwriter,openpyxl3种方式读写实例与优劣)
2020/02/13 Python
python爬虫中的url下载器用法详解
2020/11/30 Python
美国社交购物市场:MassGenie
2019/02/18 全球购物
PHP数据运算类型都有哪些
2013/11/05 面试题
医学专业大学生求职的自我评价
2013/11/27 职场文书
儿媳婚宴答谢词
2014/01/14 职场文书
年终晚会主持词
2014/03/25 职场文书
作风建设年活动实施方案
2014/10/24 职场文书
小学四年级班主任工作经验交流材料
2015/11/02 职场文书
《鲸》教学反思
2016/02/23 职场文书
2019事业单位个人工作总结范文
2019/08/26 职场文书
Java实现带图形界面的聊天程序
2022/06/10 Java/Android