此篇文章主要是提炼《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. Project Euler 102:Triangle containment 包含原点的三角形

    Triangle containment Three distinct points are plotted at random on a Cartesian plane, for which -10 ...

  2. android-exploitme(四):参数篡改

    今天我们来测试请求中参数的篡改,这个在web安全测试中是常用的,拦截请求包,修改参数,提交 1.  首先我们需要启动模拟器,并使用本机的代理(加上参数-partition-size的目的是为了可以往a ...

  3. Centos环境下部署游戏服务器-权限

    部署Web服务器的时候,在"DocumentRoot"指向的根目录新建一个文件夹,然后将网页和资源放在这个文件夹里,通过地址http://192.168.0.100/Res/ind ...

  4. lua标签解析器

    lua 标签解析器 概述 一个类xml标签解析函数,将标签解析成Lua中的表结构它可以用来解析简单xml结构,可以作为RichLabel控件的字符串解析组件(其实它现在就是这么用的;-)) 原理 使用 ...

  5. PHP,单项查询及多项查询

    先封装对象class DBDA { public $host = "localhost"; //数据库地址 public $uid = "root"; //数据 ...

  6. .net Windows服务程序和安装程序制作图解 及 VS 2010创建、安装、调试 windows服务(windows service)

    .net Windows服务程序和安装程序制作 最近项目中用到window服务程序,以前没接触过,比较陌生,花了两天的时间学习了下,写了个简单的服务,但在制作安装程序的时候,参照网上很多资料,却都制作 ...

  7. opencv实现KNN手写数字的识别

    人工智能是当下很热门的话题,手写识别是一个典型的应用.为了进一步了解这个领域,我阅读了大量的论文,并借助opencv完成了对28x28的数字图片(预处理后的二值图像)的识别任务. 预处理一张图片: 首 ...

  8. find-right-interval

    https://leetcode.com/problems/find-right-interval/ Java里面TreeMap或者TreeSet有类似C++的lower_bound或者upper_b ...

  9. Machine Learning for hackers读书笔记(五)回归模型:预测网页访问量

    线性回归函数 model<-lm(Weight~Height,data=?) coef(model):得到回归直线的截距 predict(model):预测 residuals(model):残 ...

  10. 用AngularJS开发下一代Web应用 系列入门基础教程

    开篇介绍 AngularJS是什么东西?我觉得不用再描述了.可自行去充电一下.按照惯例,让我们先看看一个Hello World的开门简介吧. <!doctype html> <htm ...