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 页面只自动刷新一次
Jul 10 Javascript
js淡入淡出焦点图幻灯片效果代码分享
Sep 08 Javascript
jQuery+CSS实现滑动的标签分栏切换效果
Dec 17 Javascript
vue2.0 element-ui中el-select选择器无法显示选中的内容(解决方法)
Aug 24 Javascript
原生JS实现简单的无缝自动轮播效果
Sep 26 Javascript
Vue动态组件与异步组件实例详解
Feb 23 Javascript
生产制造追溯系统之再说条码打印
Jun 03 Javascript
Vue  webpack 项目自动打包压缩成zip文件的方法
Jul 24 Javascript
axios如何取消重复无用的请求详解
Dec 15 Javascript
jquery将信息遍历到界面上实例代码
Jan 21 jQuery
jQuery实现飞机大战小游戏
Jul 05 jQuery
nuxt.js服务端渲染中axios和proxy代理的配置操作
Nov 06 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
10个超级有用的PHP代码片段果断收藏
2015/09/23 PHP
thinkPHP自定义类实现方法详解
2016/11/30 PHP
PHP面向对象程序设计之类与反射API详解
2016/12/02 PHP
php指定长度分割字符串str_split函数用法示例
2017/01/30 PHP
js post方式传递提交的实现代码
2010/05/31 Javascript
jquery div 居中技巧应用介绍
2012/11/24 Javascript
window.showModalDialog参数传递中含有特殊字符的处理方法
2013/06/06 Javascript
基于jQuery实现文本框只能输入数字(小数、整数)
2016/01/14 Javascript
JavaScript基本语法学习教程
2016/01/14 Javascript
js HTML5多图片上传及预览实例解析(不含前端的文件分割)
2016/08/26 Javascript
JS简单实现禁止访问某个页面的方法
2016/09/13 Javascript
Html5+jQuery+CSS制作相册小记录
2016/12/30 Javascript
jQuery实现对象转为url参数的方法
2017/01/11 Javascript
详解vue-cli之webpack3构建全面提速优化
2017/12/25 Javascript
vue-cli 如何打包上线的方法示例
2018/05/08 Javascript
微信小程序按钮去除边框线分享页面功能
2018/08/27 Javascript
webpack@v4升级踩坑(小结)
2018/10/08 Javascript
layDate插件设置开始和结束时间
2018/11/15 Javascript
vue组件中实现嵌套子组件案例
2020/08/31 Javascript
node koa2 ssr项目搭建的方法步骤
2020/12/11 Javascript
Python multiprocessing模块中的Pipe管道使用实例
2015/04/11 Python
python for 循环获取index索引的方法
2019/02/01 Python
Django Sitemap 站点地图的实现方法
2019/04/29 Python
用Q-learning算法实现自动走迷宫机器人的方法示例
2019/06/03 Python
利用 CSS3 实现的无缝轮播功能代码
2017/09/25 HTML / CSS
html5 touch事件实现触屏页面上下滑动(一)
2016/03/10 HTML / CSS
HTML5新控件之日期和时间选择输入的实现代码
2018/09/13 HTML / CSS
AVIS安飞士奥地利租车官网:提供奥地利、欧洲和全世界汽车租赁
2016/11/29 全球购物
DataList 能否分页,请问如何实现?
2015/05/03 面试题
机关门卫岗位职责
2013/12/30 职场文书
县人大领导班子四风对照检查材料思想汇报
2014/10/09 职场文书
2014年教师学期工作总结
2014/11/08 职场文书
创先争优承诺书
2015/01/20 职场文书
考研英语辞职信
2015/05/13 职场文书
代码解析React中setState同步和异步问题
2021/06/03 Javascript
Python 中的Sympy详细使用
2021/08/07 Python