小结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 ...
随机推荐
- 读取MySQL中的数据并显示在JSP上
<%@ page language="java" import="java.sql.*,java.io.*,java.util.*,java.sql.SQLExce ...
- iOS开发--iOS及Mac开源项目和学习资料
文/零距离仰望星空(简书作者)原文链接:http://www.jianshu.com/p/f6cdbc8192ba著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 原文出处:codecl ...
- 超级内存NVDIMM
1.序言 基于非易失性内存(NVDIMM)的新一代内存条规格已经研制成功,其中集成了DRAM和非易失性存储芯片,能够在完全断电的时候完整保存内存数据,并支持主内存在持久高速高性能计算上的应用.区别于普 ...
- 285. Inorder Successor in BST
题目: Given a binary search tree and a node in it, find the in-order successor of that node in the BST ...
- sql 随笔 2015-08-07
xls 导入数据库 --删除现有数据 DELETE FROM dbo.PhoneList --插入数据 insert into dbo.PhoneList --读取xls数据 ) , as [Enab ...
- linux下c程序调用reboot函数实现直接重启【转】
转自:http://www.blog.chinaunix.net/uid-20564848-id-73878.html linux下c程序调用reboot函数实现直接重启 当然你也可以直接调用syst ...
- Maven POM.xml详解[转]
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...
- Support Library(5)在eclipse中导入SupportXXXDemos
Support4Demos只用一个v4.,Support7Demos只要v13.jar, SupportAppNavigation只要一个v4.jar. Support7Demos 需要资源全部v7系 ...
- Regex count lowercase letters
Description: Your task is simply to count the total number of lowercase letters in a string. Example ...
- What is Entity Framework?
1.什么是EntityFramework? http://www.entityframeworktutorial.net/what-is-entityframework.aspx Writing an ...