初涉JavaScript模式 (4) : 构造函数
什么是构造函数?
构造函数 是一种特殊的方法 主要用来在创建对象时初始化对象 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中 特别的一个类可以有多个构造函数 可根据其参数个数的不同或参数类型的不同来区分它们 即构造函数的重载 ---引自百度百科
在JavaScript中是没有类的,但是我们有构造函数(是不是很怪),很深的东西我也说不来,直接上代码:
```javascript
//工厂模式
function createCat(name){
var o = {};
o.name = name;
o.cry = function(){
console.log(this.name + " : " + "喵喵喵!");
};
return o;
}
var tom = createCat("tom");
tom.cry();
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
}
var jerry = new Mouse("jerry",5);
jerry.cry();
```
以上实例代码分别是工厂模式和构造函数模式,构造函数模式相比于工厂模式,存在一下几个不同之处:
- 没有显式的创建对象
- 直接将属性和方法赋给了this对象
- 没有return语句
实际上,调用构造函数会经历以下几个步骤:
- 创建一个新对象
- 将构造函数的作用域赋给新对象(因此this就指向了新对象)
- 执行构造函数中的代码(给这个新对象添加方法和属性)
- 返回这个新对象
我们要注意以上是JS隐式执行的,我们也可以显式的来,上代码:
```javascript
function Mouse(name){
var o = {};
var that = o;
that.name = name;
that.cry = function(){
console.log(that.name);
}
return that;
}
var jerry = new Mouse("jerry",5);
jerry.cry();
```
在隐式的构造函数中,我们要注意一个问题,return是隐式返回this的,但是我们可以手动return ,可是这有可能会return我们意料之外的结果:
```javascript
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
return "WeiRan"
}
Mouse.prototype.a = {};
var jerry = new Mouse("jerry",5);
jerry.cry(); // jerry : 吱吱吱!
```
以上代码,虽然我们手动返回的是字符串但是真正返回的还是this,其实JS会判断我们返回的是不是对象,数组,function 如果不是这还是会返回this(即便是undefined,null,空)
对象识别
虽然工厂模式解决了多个相似对象的问题,却没有解决对象识别的问题,但是构造函数模式却解决了这个问题,在构造函数模式中,每一个实例都有一个属性constructor,该属性指向他么的构造函数,可以这样来检测对象的类型
```javascript
console.log(jerry.constructor == Mouse); //true
```
但是这样做其实是不严谨的,可能会出现以下的问题:
```javascript
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
return;
}
var jerry = new Mouse("jerry",5);
Mouse.prototype.constructor = {};
console.log(jerry.constructor);//Object {}
```
这段代码说明,jerry的constructor其实指向的是Mouse的prototype的constructor,这样很不严谨,故我们可以采用instanceof来检测对象类型
```javascript
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
return;
}
var jerry = new Mouse("jerry",5);
Mouse.prototype.constructor = {};
console.log(jerry.constructor == Mouse);//false
console.log(jerry instanceof Mouse); //true
```
将构造函数当作函数
构造函数与其他函数的唯一不同,就在于调用他们的方式不同。但是构造函数也是函数,故我们可以以普通函数的方式执行构造函数,任何函数也可以通过new来调用(慎用),下面我列举了几个调用方式:
```javascript
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
}
//当作构造函数使用
var m1 = new Mouse("m1");
m1.cry(); //m1 : 吱吱吱!
//当作普通函数使用
Mouse("m2");
window.cry(); //m2 : 吱吱吱!
//在其他作用域调用
var obj = {};
Mouse.call(obj,"m3");
obj.cry(); //m3 : 吱吱吱!
```
第一种是用最常见的调用构造函数的方式,第二种,所有的属性和方法都被添加到Global对象上去了(在浏览器中就是window),第三种,我们制定了作用域,所以obj就有了所有的属性和方法
构造函数的问题
构造函数虽然好用,但是他也有缺点,使用构造函数的主要问题,就是每个方法都要在每个实例上重新创建一遍,即每个实例的方法都是不同的(虽然代码一样),上代码:
```javascript
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = function(){
console.log(this.name + " : " + "吱吱吱!");
}
}
var m1 = new Mouse();
var m2 = new Mouse();
console.log(m1.cry == m2.cry); //false
```
然而,创建两个完成相同功能的Function实例的确没有必要,而且有this对象在,根本没有必要在执行代码前就把函数绑定到特定的对象上去,以此我们可以用下面的代码来解决这个问题:
```javascript
//构造函数模式
function Mouse(name){
this.name = name;
this.cry = cry;
}
function cry(){
alert(this.name);
}
```
在上面的例子中我们把cry方法定义在了构造函数外部,这样大大避免了资源的浪费,我们创建的实例调用的都是同一个cry方法,但是新问题又来了,如果这种方法很多,我们就不得不在全局定义很多函数,于是我们这个自定义的引用类型就丝毫没有封装性可言了,好在这些我们可以用原型模式来解决(下一篇,呵呵)
后记 :
关于这篇,我开始是想写的非常全,但是奈何经验不足,大体框架也是按照书上的逻辑,最大的收获就是真的用心去看书了。如果在文中发现错误,请指正,共同进步
初涉JavaScript模式 (4) : 构造函数的更多相关文章
- 初涉JavaScript模式系列 阶段总结及规划
总结 不知不觉写初涉JavaScript模式系列已经半个月了,没想到把一个个小点进行放大,竟然可以发现这么多东西. 期间生怕对JS的理解不到位而误导各位,读了很多书(个人感觉JS是最难的oo语言),也 ...
- 初涉JavaScript模式 (7) : 原型模式 【三】
组合使用构造函数模式和原型模式 上篇,我们提到了原型模式的缺点,就是每个实例不能拥有自己的属性,因为纯原型模式所有的属性都是公开给每个实例的,故我们可以组合使用构造函数模式和原型模式.构造函数用来定义 ...
- 初涉JavaScript模式 (6) : 原型模式 【二】
原型与in操作符 有两种方式使用in操作符:单独使用和在for-in循环中使用. 在单独使用时,in操作符会遍历实例公开(可枚举)的属性,如果找到该指定属性则返回true,无论该指定属性是存在与实例中 ...
- 初涉JavaScript模式 (12) : 沙箱模式
引子 上一篇说了模块模式,而对于其中的命名空间模式其实也是有着一些问题,比如每添加一个模块或则深入叠加都会导致长命名,并且对于多个库的不同版本同时运行,一不小心就会污染全局标识,而这两天也发现了JSe ...
- 初涉JavaScript模式 (11) : 模块模式
引子 这篇算是对第9篇中内容的发散和补充,当时我只是把模块模式中的一些内容简单的归为函数篇中去,在北川的提醒下,我才发觉这是非常不严谨的,于是我把这些内容拎出来,这就是这篇的由来. 什么是模块模式 在 ...
- 初涉JavaScript模式 (5) : 原型模式 【一】
什么是原型模式? 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象.--引自JavaScript设计模式 我们创建的每一个函数都有一个prototype ...
- 初涉JavaScript模式 (2) : 基本技巧
尽量少用全局变量 大量使用全局变量会导致的后果 全局变量创建以后会在整个JavaScript应用和Web页面中共享.所有的全局变量都存在于一个全局命名空间内,很容易发生冲突 不知不觉创建了全局变量 其 ...
- 初涉JavaScript模式 (3) : 字面量
什么是字面量? 在编程语言中,字面量是一种表示值的记法.例如,"Hello, World!" 在许多语言中都表示一个字符串字面量(string literal ),JavaScri ...
- 初涉JavaScript模式 (13) : 代码复用 【上】
引子 博客断了一段时间,不是不写,一是没时间,二是觉得自己沉淀不够,经过一段时间的学习和实战,今天来总结下一个老生常谈的东西: 代码复用. 为何复用 JS门槛低,故很多人以为写几个特效就会JS,其实真 ...
随机推荐
- LightOJ 1135(线段树)
题解引自:http://www.cnblogs.com/wuyiqi/archive/2012/05/27/2520642.html 题意: 有n个数,刚开始都为0 add i , j 给i,j区间内 ...
- GitHub上线Trending功能,帮你轻松找到有潜力的开源项目
转自:http://www.csdn.net/article/2013-08-14/2816574-Github-Trending-Open-Source-Project Github开源项目 摘要: ...
- 【动态规划】Codeforces 711C Coloring Trees
题目链接: http://codeforces.com/problemset/problem/711/C 题目大意: 给N棵树,M种颜色,已经有颜色的不能涂色,没颜色为0,可以涂色,每棵树I涂成颜色J ...
- 福州大学 Problem 2168 防守阵地 I
http://acm.fzu.edu.cn/problem.php?pid=2168 最重要的是 dp[k]=dp[k-1]-ans[k-1]+x[i]*m; ans[k-1]是m个数求和. Pro ...
- hdu 4607 Park Visit (dfs)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4607 首先如果k小于等于直径长度,那么答案为k−1.如果k大于直径长度,设直径长度为r,那么答案为r− ...
- 拥有最小高度能自适应高度,IE、FF全兼容的div设置
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" " http://www.w3.org/TR/xh ...
- oracle 大文本由clob来存
file字段是varchar2类型(最多只能存储4000字符),空间不够用了,因此将其改为clob类型(支持4G存储量). 但是如果该字段中已经有数据,是不为空的,直接用语句改,会报错. 那么需要借助 ...
- Java中的字符串流的读取和写入(创建文件并判断重复账户)
各位我又来了!!哎!好心酸!我还没注册到三天!!没法登上博客的首页!!心累!! import java.io.BufferedOutputStream; import java.io.Buffered ...
- Windows7下32位IE异常不能打开解决方法
今天更新了Update及安装了一些软件,重启电脑后发现32位IE不能正常打开,而64位IE正常. 错误信息如下: 问题签名: 问题事件名称: BEX 应用程序名: iexplore.exe 应用 ...
- 在Quick-cocos2dx中使用云风pbc解析Protocol Buffers,支持win、mac、ios、android
本例主要介绍 如何将 pbc 集成到quick-cocos2dx框架中,让我们的cocos2dx客户端Lua拥有编解码Protocol Buffers能力. 参考: 云风pbc的用法: http:// ...