将过去零零散散的问题收集记录于此

复制引用类型数据

经常会遇到需要复制一个array或者object的需求。
如果是简单粗暴的 a = b 这样复制那就可能出问题了,你会发现当b中数据发生变化时, a的数据竟然也改变了,这也许并不是你想见到的结果,因为 a = b 这样对引用类型赋值时,a实际上等于b对象的一个内存地址,也就是说,访问a时实际上访问的是b。
正确复制引用类型的方法如下:

  1. 复制array

    1
    2
    3
    4
    5
    6
    7
    // 方法一 简单粗暴循环生成新数组
    var arr = [];
    for (var i = 0; i < aUser.length; i++) {
    arr.push(aUser[i]);
    }
    // 方法二 用concat
    var arr = aUser.concat()
  2. 复制object
    当object中存的数据为基本数据类型时,可以使用浅拷贝。反之,如果object中有很多层数据时,若使用浅拷贝会发现其子层还是会遇到之前发生的问题

    1
    2
    3
    4
    5
    6
    7
    // 循环复制
    var obj = [];
    for (var key in oUserData) {
    obj[key] = oUserData[key];
    }
    // 深拷贝就是要拓展一个递归的方法,去一层一层遍历,当子层数据类型为object时递归遍历下一次,直至最后一层。网上很多代码的。不贴了……

在iframe子窗口调用父级窗口方法

iframe子窗口调用父级窗口方法分为两种情况,跨越及同域调用

iframe子窗口调用父级窗口

假设父级窗口index.html中有一个closeModal方法,和一个iframe,我们想在iframe中调用这个方法。

1
2
3
4
5
6
7
<!-- index.html -->
<iframe id="ifr" src=""></iframe>
<script type="text/javascript">
function closeModal() {
// todo
}
</script>

当iframe打开的页面与父窗口在同一个域名下时,我们通过window.parent拿到父窗口的window句柄,从而调用到父窗口window句柄下的方法

1
2
3
4
<!-- iframe content -->
<script type="text/javascript">
window.parent.closeModal();
</script>

由于js对跨域权限做了限制,当iframe打开的是另一个域名下的地址时,我们可以通过下面这种方法“巧妙”的调用到父窗口下的方法——在iframe中再嵌入一层子iframe用于打开一个与父级同域名的页面,由于这个子iframe与父级同域,因此可以通过他调用我们需要的方法

1
2
<!-- iframe content -->
<iframe id="child" src=""></iframe>

1
2
3
4
<!-- child content -->
<script type="text/javascript">
window.parent.parent.closeModal();
</script>

上述方法非常的“投机”,那么下面这种方法则可以说是名门正派了。

##HTML5中的postMessage
HTML5提供了新的通信api——postMessage,可以允许父容器与子容器间进行通信
那么实现的过程就如下:

1
2
3
4
5
6
7
8
9
10
11
<!-- index.html -->
<iframe id="ifr" src=""></iframe>
<script type="text/javascript">
function closeModal() {
// todo
}
window.addEventListener('message', function(e){
'closeModal' == e.data && closeModal();
},false);
</script>

iframe中通过postMessage向父窗口发消息

1
2
3
4
5
6
7
8
9
<!-- iframe.html -->
<script type="text/javascript">
parent.postMessage('closeModal', '*');
/*
postMessage(data, origin);
参数:data 消息内容
origin 发送消息窗口的源(协议+主机+端口号)
*/
</script>

prototype.function与this.function的区别

prototype.function与this.function都可以定义对象的方法,那二者有何区别呢?

初步分析

先用一段代码来说明二者的区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var actor = function() {
var param = 1;
this.act = function() {
return param;
}
};
actor.prototype.play = function() {
return typeof param;
};
var man1 = new actor();
var man2 = new actor();
console.log(man1.act === man2.act); // false
console.log(man1.play === man2.play); // true
console.log(man1.act()); // 1
console.log(man1.play()); // undefined

简单工厂模式

简单工厂模式(Simple Factory)又叫静态工厂方法,由一个工厂对象决定创建某种产品对象类的实例。
以我的理解,这种设计模式的目的是:统一几个对象的创建入口,这样就可以抽取这几个对象创建时的共性(共用代码),同时可以由该工厂方法决定具体创建那个对象。

比如屏幕中有modal和pop两种弹出窗体,他们在打开前都需要获取window的width和height属性,那么我们可以通过一个openWin方法实现对两者的调用。

1
2
3
4
5
6
7
8
9
10
11
var modal = function(){}
var pop = function(){}
var openWin = function(mode) {
var width = window.width;
var height = window.height;
if ('modal' == mode) {
new model(width, height);
} else if ('pop' == mode) {
new pop(width, height);
}
}

工厂方法模式

在上述的模式中有这样一个小缺陷,比方说当系统中新增了一个类dialog,此时我们不仅需要写dialog相关的构造放,还需要在openWin中的判断多加一条,这样静态的方法似乎显得不是很灵活。

而工厂方法模式比之前的简单工厂模式进一步的抽取了共性,不仅是通过一个方法的调用获得两种对象(统一入口),而且要实现两种对象可以通过同一个类(即工厂类)new出来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var Factory = function(type, content) {
// 先判断this是否指向Factory
if (this instanceof Factory) {
var s = new this[type](content);
return s;
} else {
return new Factory(type, content);
}
}
Factory.prototype = {
'modal': function(){}
, 'pop': function(){}
, 'dialog': function(){}
}

抽象工厂模式

抽象工厂模式通过对类的工厂抽象使其业务用于产品类簇的创建,而不负责创建某一类产品的实例。
比如在上面的工厂方法中,modal类还分为smallModal和bigModal两种子类,他们都有一个共同的属性type,那我们再把他们的共性抽取出来,作为一个抽象类,不用于实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 抽象工厂方法
var WinFactory = function(subType, superType) {
// 判断抽象工厂中是否有该抽象类
if (typeof WinFactory[superType] === 'function') {
// 缓存类
function F(){};
// 继承父类的属性和方法
F.prototype = new WinFactory[superType]();
// 将子类的构造器指向子类
subType.constructor = subType;
// 子类原型继承『父类』
subType.prototype = new F();
} else {
// 不存在该抽象类
throw new Error('未创建该抽象类');
}
}
WinFactory.modal = function() {
this.type = 'modal';
}
WinFactory.modal.prototype = {
show: function() {
return new Error('抽象方法不能调用');
}
}
// 生成一个smallModal子类
var smallModal = function() {
}
WinFactory(smallModal, 'modal');
smallModal.prototype.show = function() {
return 'show';
}
var modal = new smallModal();
console.log(modal.show());
console.log(modal.type);