此篇文章主要是提炼《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(中)的更多相关文章

  1. 不会JS中的OOP,你也太菜了吧!(第二篇)

    一.你必须知道的 1> 原型及原型链在继承中起到了关键的作用.所以你一定要理解他们.2> 不会JS中的OOP,你也太菜了吧!(第一篇) 二.继承的6种方法 1> 原型链继承 原型链继 ...

  2. js oop中的三种继承方法

    JS OOP 中的三种继承方法: 很多读者关于js opp的继承比较模糊,本文总结了oop中的三种继承方法,以助于读者进行区分. <继承使用一个子类继承另一个父类,子类可以自动拥有父类的属性和方 ...

  3. js中对arry数组的各种操作小结 瀑布流AJAX无刷新加载数据列表--当页面滚动到Id时再继续加载数据 web前端url传递值 js加密解密 HTML中让表单input等文本框为只读不可编辑的方法 js监听用户的键盘敲击事件,兼容各大主流浏览器 HTML特殊字符

    js中对arry数组的各种操作小结   最近工作比较轻松,于是就花时间从头到尾的对js进行了详细的学习和复习,在看书的过程中,发现自己平时在做项目的过程中有很多地方想得不过全面,写的不够合理,所以说啊 ...

  4. 在Ext JS 5应用程序中如何使用路由

    简介 Ext JS 5是一个重要的发布版本,它提供了许多新特性来创建丰富的.企业级的Web应用程序.MVVM和双向数据绑定为开发人员承担了大量的繁重工作.在Ext JS 5种,另一个新特性就是路由,它 ...

  5. 【翻译】在Ext JS 5应用程序中怎样使用路由

    原文:How to Use Routing in Your Ext JS 5 Apps 简单介绍 Ext JS 5是一个重要的公布版本号,它提供了很多新特性来创建丰富的.企业级的Web应用程序.MVV ...

  6. 【翻译】Ext JS 5.0.1 中的新功能

    原文:What's New in Ext JS 5.0.1 今天,我们很高兴的宣布Ext JS 5.0.1发布了!此维护版本基于Sencha社区的反馈做了一些改进.下面让我们来了解一下这些改变. 可访 ...

  7. 【翻译】在Ext JS 5应用程序中如何使用路由

    原文:How to Use Routing in Your Ext JS 5 Apps 简介 Ext JS 5是一个重要的发布版本,它提供了许多新特性来创建丰富的.企业级的Web应用程序.MVVM和双 ...

  8. Js/Jquery获取iframe中的元素

    转载: Js/Jquery获取iframe中的元素 - - ITeye技术网站http://java-my-life.iteye.com/blog/1275205 在web开发中,经常会用到ifram ...

  9. ActiveX(二)Js 监听 ActiveX中的事件

    在上一篇随笔:ActiveX(一)第一个简单的Demo 中,已经可以实现 js 单向调用 ActiveX 中的方法,在很多情况下ActiveX中的方法的执行时相对耗时.耗性能的.在这样的情况下.Act ...

  10. js中获取URL中指定的查询字符串

    js中获取URL中指定的搜索字符串,主要利用location对象实现,废话少说,上代码. function getSearchString(key) { // 获取URL中?之后的字符 var str ...

随机推荐

  1. 解决IIS应用程序池DefaultAppPool关闭超时错误

    错误系统日志: 为应用程序池“DefaultAppPool”提供服务的进程关闭时间超过了限制.进程 ID 是“3060”. 有关更多信息,请参阅在http://go.microsoft.com/fwl ...

  2. 对QT的理解——能在公司里不做Java,不做很偏门的产品,不使用偏门的语言,还有钱挣,要有感恩的心

    我的理解: QT做应用软件可以很强大,界面足够漂亮(最有意思的是QSS,让我刮目相看),应该是足够了.同时QT也提供了源码,不过超级复杂,难以理解,所以还是无法深入底层.另外它提供了一个额外的好处,就 ...

  3. Java:日历类、日期类、数学类、运行时类、随机类、系统类

    一:Calendar类 java.util 抽象类Calendar   1.static Calendar getInstance()使用默认时区和语言环境获得一个日历. 2. int get(int ...

  4. RichLabel基于Cocos2dx+Lua v3.x

    RichLabel 简介 RichLabel基于Cocos2dx+Lua v3.x解析字符串方面使用了labelparser,它可以将一定格式的字符串,转换为lua中的表结构扩展标签极其简单,只需添加 ...

  5. c语言类型转换注意事项

    转载自: http://blog.csdn.net/zhuimengzh/article/details/6728492 1.隐式转换     C在以下四种情况下会进行隐式转换:        1.算 ...

  6. dotfuscator初步

    从此链接下载的http://www.uzzf.com/soft/85836.html 1.安装之前,先去控制面板将VS自带的dotfuscator卸载掉 2.关闭360安全卫士 3.安装下载的程序 安 ...

  7. Setup Entity Framework Environment

    http://www.entityframeworktutorial.net/EntityFramework5/setup-entityframework-environment.aspx Entit ...

  8. SQL[连载3]sql的一些高级用法

    SQL[连载3]sql的一些高级用法 SQL 高级教程 SQL SELECT TOP SQL SELECT TOP 子句 SELECT TOP 子句用于规定要返回的记录的数目. SELECT TOP ...

  9. HDFS的体系结构和操作

    1.对hdfs操作的命令格式是hadoop fs 1.1 -ls <path> 表示对hdfs下一级目录的查看 1.2 -lsr <path> 表示对hdfs目录的递归查看 1 ...

  10. hdu4422The Little Girl who Picks Mushrooms

    4422 小于等于3 的时候就是1024 4的时候 讨论 5的时候讨论 注意重量为0的情况 #include <iostream> #include<cstdio> #incl ...