小结JS中的OOP(中)
此篇文章主要是提炼《JavaScript高级程序设计》中第六章的一些内容。
一:JS中OOP相关的概念
开始之前先总结JS中OOP相关的一些概念:
构造函数:JS中的构造函数就是普通的函数,当JS中的函数使用new调用时,这个函数就是构造函数。构造函数调用与普通函数调用相比会有以下两点不同:
① 在进入构造函数时,会先创建一个对象,并将构造函数的作用域赋值给这个对象(this指向这个对象)
② 在退出构造函数前,会默认返回创建的对象(返回this)
原型对象:每个函数都会有一个prototype属性,函数的prototype属性指向的就是(构造)函数的原型对象。默认情况下函数的原型对象都会有一个constructor属性,指向函数自身。
其实,JS中所有的对象都会有constructor属性,默认指向Object。
function foo(){}
//所有的函数都具有prototype属性
//所有函数的原型对象(函数的prototype属性)默认的constructor属性指向函数自身
foo.prototype.constructor === foo;
//所有对象都具有constructor属性,默认指向Object
({}).constructor === Object;
//对象实例内部都会有一个[[prototype]]指针,指向对象在创建时所依赖的原型对象
(new foo()).__proto__ === foo.prototype
({}).__proto__ === Object.prototype;
foo.prototype === (new foo).__proto__;
(new foo).__proto__.constructor === foo;
实例: 使用new产生的一个具体的对象
二: 封装类(创建自定义类型)
使用构造函数+原型模式封装类。具体做法是:
① 把实例属性(不共享的属性)写在构造函数中
② 把共享属性(包含constructor)写在函数原型对象中
function Animal(opts) {
this.cate = opts.cate;
}
Animal.prototype = {
constructor: Animal,
shout :function () {
console.log('animal shouted');
}
}
//为了封装看起来更优雅,也可以写成下面这样
function Animal(opts) { this.cate = opts.cate; if(typeof this.shout !== 'function') {
//这样直接将一个对象赋值给Animal.prototype会断开进入构造函数时创建的对象的__proto__属性与原型对象的链接
//所以实际new出来的第一个对象的__proto__上面不会有原型对象上的方法
//解决办法是手动在后面调用一次构造函数或像下面那样增加方法就不会断开构造函数时创建的对象的__proto__属性与原型对象的链接
/**
* Animal.prototype.shout = function() {}
* Animal.prototype.getCate = function() {}
*/
Animal.prototype = {
constructor: Animal,
shout :function () {
console.log('animal shouted');
},
getCate: function() {
return this.cate;
},
setCate: function(cate) {
this.cate = cate;
}
}
} }
//手动new一次Animal
new Animal();
这种封装的缺点:没有实现访问权限控制,所有的一切都是public的。
三:继承
使用借用构造函数+原型链接实现继承
function Animal(opts) {
this.cate = opts ? opts.cate : undefined;
if(typeof this.shout !== 'function') {
Animal.prototype = {
constructor: Animal,
shout :function () {
console.log('animal shouted');
},
getCate: function() {
return this.cate;
},
setCate: function(cate) {
this.cate = cate;
}
}
}
}
//手动new一次Animal
new Animal();
//定义Dog类,并让其从Animal继承
function Dog(opts) {
//继承Animal中的属性
Animal.call(this, opts);
//增加Dog的属性
this.name = opts.name;
//...
}
Dog.prototype = new Animal();
Dog.constuctor = Dog;
Dog.prototype.getName = function() {
return this.name;
}
缺点很明显:Dog.prototype = new Animal(); 要实例化Dog会先调用一次Animal(),同时在new Dog()时,在Dog的构造函数中又会调用一次Animal(), Animal.call(this, opts);
由于Dog.prototype = new Animal(); 只是想拿到Animal原型对象上的方法,所以我们可以改成这样,Dog.prototype = Animal.prototype; 但改成这样后,Dog.prototype与
Animal.prototype实际就都指向同一个对象了,所以Animal的实例也会有getName()方法。但我们可以先创建一个对象,再把Animal.prototype上的属性拷贝来过,再赋值给
Dog.prototype。
function Animal(opts) {
this.cate = opts ? opts.cate : undefined;
}
Animal.prototype = {
constructor: Animal,
shout :function () {
console.log('animal shouted');
},
getCate: function() {
return this.cate;
},
setCate: function(cate) {
this.cate = cate;
}
}
//定义Dog类,并让其从Animal继承
function Dog(opts) {
//继承Animal中的属性
Animal.call(this, opts);
//增加Dog的属性
this.name = opts.name;
//...
}
Dog.prototype = (function() {
var DogProto = {}, AnimalProto = Animal.prototype, key;
for(key in AnimalProto) {
AnimalProto.hasOwnProperty(key)
DogProto[key] = AnimalProto[key];
}
return DogProto;
})();
Dog.prototype.constructor = Dog;
Dog.prototype.getName = function() {
return this.name;
}
这样改了后,也还是有缺点: new Dog instanceof Animal;会返回false。但如果我们只关注对象能做什么,而不是对象的类是什么(鸭式辨型编程)这样做还是达到了我们想要的效果。
还有如果我们平时想使用一些带有自己方法的原生对象,但我们又不想去直接扩展原生对象的prototype,我们可以像下面这样做:
function enhancedString(str) {
str = new String(str);
//增加我们的方法
!str.statsWith && (str.startsWith = function(target) {
return this.indexOf(target) === 0;
});
//...
return str;
}
//测试:
var str = new enhancedString('test');
//可以使用string原生的方法
console.log(str.length);//4
console.log(str.slice(1));//est
//也可以使用我们在string上面扩展的方法
console.log(str.startsWith('t')); //true
小结JS中的OOP(中)的更多相关文章
- 不会JS中的OOP,你也太菜了吧!(第二篇)
一.你必须知道的 1> 原型及原型链在继承中起到了关键的作用.所以你一定要理解他们.2> 不会JS中的OOP,你也太菜了吧!(第一篇) 二.继承的6种方法 1> 原型链继承 原型链继 ...
- js oop中的三种继承方法
JS OOP 中的三种继承方法: 很多读者关于js opp的继承比较模糊,本文总结了oop中的三种继承方法,以助于读者进行区分. <继承使用一个子类继承另一个父类,子类可以自动拥有父类的属性和方 ...
- js中对arry数组的各种操作小结 瀑布流AJAX无刷新加载数据列表--当页面滚动到Id时再继续加载数据 web前端url传递值 js加密解密 HTML中让表单input等文本框为只读不可编辑的方法 js监听用户的键盘敲击事件,兼容各大主流浏览器 HTML特殊字符
js中对arry数组的各种操作小结 最近工作比较轻松,于是就花时间从头到尾的对js进行了详细的学习和复习,在看书的过程中,发现自己平时在做项目的过程中有很多地方想得不过全面,写的不够合理,所以说啊 ...
- 在Ext JS 5应用程序中如何使用路由
简介 Ext JS 5是一个重要的发布版本,它提供了许多新特性来创建丰富的.企业级的Web应用程序.MVVM和双向数据绑定为开发人员承担了大量的繁重工作.在Ext JS 5种,另一个新特性就是路由,它 ...
- 【翻译】在Ext JS 5应用程序中怎样使用路由
原文:How to Use Routing in Your Ext JS 5 Apps 简单介绍 Ext JS 5是一个重要的公布版本号,它提供了很多新特性来创建丰富的.企业级的Web应用程序.MVV ...
- 【翻译】Ext JS 5.0.1 中的新功能
原文:What's New in Ext JS 5.0.1 今天,我们很高兴的宣布Ext JS 5.0.1发布了!此维护版本基于Sencha社区的反馈做了一些改进.下面让我们来了解一下这些改变. 可访 ...
- 【翻译】在Ext JS 5应用程序中如何使用路由
原文:How to Use Routing in Your Ext JS 5 Apps 简介 Ext JS 5是一个重要的发布版本,它提供了许多新特性来创建丰富的.企业级的Web应用程序.MVVM和双 ...
- Js/Jquery获取iframe中的元素
转载: Js/Jquery获取iframe中的元素 - - ITeye技术网站http://java-my-life.iteye.com/blog/1275205 在web开发中,经常会用到ifram ...
- ActiveX(二)Js 监听 ActiveX中的事件
在上一篇随笔:ActiveX(一)第一个简单的Demo 中,已经可以实现 js 单向调用 ActiveX 中的方法,在很多情况下ActiveX中的方法的执行时相对耗时.耗性能的.在这样的情况下.Act ...
- js中获取URL中指定的查询字符串
js中获取URL中指定的搜索字符串,主要利用location对象实现,废话少说,上代码. function getSearchString(key) { // 获取URL中?之后的字符 var str ...
随机推荐
- JavaScript的基础语法,你真的了解吗?
这篇文章是在我们熟悉了JS的基础语法后,很少有人去关注的一些细节部分.如果掌握了某些细节也许会对代码的改善有着非凡的作用.也许会使我们的代码更严谨,更高效. 1.if语句的条件 if条件中,括号里是布 ...
- 8 simple things that will make you sexy
8 simple things that will make you sexy8种方法教你不动声色的性感What makes a women sexy? Is it her body? Is it t ...
- ./jad: error while loading shared libraries: libstdc++-libc6.2-2.so.3: cannot open shared object file: No such file or directory
Ubuntu 上使用jad,出现上面错误: ./jad: error while loading shared libraries: libstdc++-libc6.2-2.so.3: cannot ...
- RHEL7.2下netcat工具安装教程
1.下载 下载地址:http://sourceforge.net/projects/netcat/files/netcat/0.7.1/(下载的是netcat-0.7.1.tar.gz版本) 2.解压 ...
- c语言中argc和argv是什么意思?
argc是参数个数,定义为intargv是字符串数组,存的是参数,定义为char**或者char* argv[]比如你编译好的程序为my.exe在命令行执行 my.exe 1 2 3那argc就是4, ...
- AngularJs-ui modal 封装 dialog
常常在操作中和用户进行交互,及时反馈操作结果:用到alert 和confrim 功能 找到一个基于anguarjs-ui的modal,方便我们使用 angular-dialog-service 注意要 ...
- Mac 如何截屏(快捷键)
全屏截图:Command + Shift + 3 使用快捷键后会马上截取当前的全屏 指定区域截图:Command + Shift + 4 使用快捷键后会出来一个带有座标的瞄准器,用鼠标的拖放可以选择需 ...
- 详细记录python的range()函数用法
使用python的人都知道range()函数很方便,今天再用到他的时候发现了很多以前看到过但是忘记的细节.这里记录一下range(),复习下list的slide,最后分析一个好玩儿的冒泡程序. 这里记 ...
- [原]poj-3009-Curling 2.0-dfs
题目太长就不贴了,题意: 上下左右四联通块,2表示起点,3表示终点,1为block,0为空地,每动一次冰壶,冰壶就会向推动的方向一直移动,直到碰到block或出界,如果碰到block就在block前停 ...
- Google 网络库Volley简介
Volley是什么? 2013 Google I/O 大会发布的Android平台网络通讯库,旨在帮助开发者实现更快速,简单,健壮的网络通讯.支持网络图片的缓存加载功能. 适用场景:数据量不大,但是通 ...