学习笔记-设计模式之构造函数模式

构造函数用于创建特定类型的对象——不仅声明了使用的对象,构造函数还可以接受参数以便第一次创建对象的时候设置对象的成员值。
你可以自定义自己的构造函数,然后在里面声明自定义类型对象的属性或方法。

**原始包装函数

JavaScript里有3中原始包装函数:number, string, boolean,有时候两种都用:

1
2
3
4
5
6
7
8
9
10
// 使用原始包装函数
var s = new String("my string");
var n = new Number(101);
var b = new Boolean(true);


// 推荐这种
var s = "my string";
var n = 101;
var b = true;

推荐,只有在想保留数值状态的时候使用这些包装函数,关于区别可以参考下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 原始string
var greet = "Hello there";
// 使用split()方法分割
greet.split(' ')[0]; // "Hello"
// 给原始类型添加新属性不会报错
greet.smile = true;
// 单没法获取这个值(18章ECMAScript实现里我们讲了为什么)
console.log(typeof greet.smile); // "undefined"

// 原始string
var greet = new String("Hello there");
// 使用split()方法分割
greet.split(' ')[0]; // "Hello"
// 给包装函数类型添加新属性不会报错
greet.smile = true;
// 可以正常访问新属性
console.log(typeof greet.smile); // "boolean"

throttle_debounce

_.throttle方法源码

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
37
38
39
40
41
42
43
44
45
46
/**
* 频率控制 返回函数连续调用时,func 执行频率限定为 次 / wait
*
* @param {function} func 传入函数
* @param {number} wait 表示时间窗口的间隔
* @param {object} options 如果想忽略开始边界上的调用,传入{leading: false}。
* 如果想忽略结尾边界上的调用,传入{trailing: false}
* @return {function} 返回客户调用函数
*/

_.throttle = function(func, wait, options) {
var context, args, result;
var timeout = null;
// 上次执行时间点
var previous = 0;
if (!options) options = {};
// 延迟执行函数
var later = function() {
// 若设定了开始边界不执行选项,上次执行时间始终为0
previous = options.leading === false ? 0 : _.now();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function() {
var now = _.now();
// 首次执行时,如果设定了开始边界不执行选项,将上次执行时间设定为当前时间。
if (!previous && options.leading === false) previous = now;
// 延迟执行时间间隔
var remaining = wait - (now - previous);
context = this;
args = arguments;
// 延迟时间间隔remaining小于等于0,表示上次执行至此所间隔时间已经超过一个时间窗口
// remaining大于时间窗口wait,表示客户端系统时间被调整过
if (remaining <= 0 || remaining > wait) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
//如果延迟执行不存在,且没有设定结尾边界不执行选项
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
};

_.debounce方法源码

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
37
38
39
40
41
42
43
/**
* 空闲控制 返回函数连续调用时,空闲时间必须大于或等于 wait,func 才会执行
*
* @param {function} func 传入函数
* @param {number} wait 表示时间窗口的间隔
* @param {boolean} immediate 设置为ture时,调用触发于开始边界而不是结束边界
* @return {function} 返回客户调用函数
*/

_.debounce = function(func, wait, immediate) {
var timeout, args, context, timestamp, result;

var later = function() {
// 据上一次触发时间间隔
var last = _.now() - timestamp;

// 上次被包装函数被调用时间间隔last小于设定时间间隔wait
if (last < wait && last > 0) {
timeout = setTimeout(later, wait - last);
} else {
timeout = null;
// 如果设定为immediate===true,因为开始边界已经调用过了此处无需调用
if (!immediate) {
result = func.apply(context, args);
if (!timeout) context = args = null;
}
}
};

return function() {
context = this;
args = arguments;
timestamp = _.now();
var callNow = immediate && !timeout;
// 如果延时不存在,重新设定延时
if (!timeout) timeout = setTimeout(later, wait);
if (callNow) {
result = func.apply(context, args);
context = args = null;
}

return result;
};
};

参考阅读

什么是面向对象

面试的时候还是经常会遇到的一个问题,在逛论坛的时候看到一个挺不错的回答的,所以分享下…
首先,它是解决的一种处理方式。将问题发出方和接收方的类型高度抽象成一个个的整体,
各个整体之间产生的关系后,将会产生某些问题,对这些关系问题的处理,在于各个整体之间的方法实现(怎么突然发现这么拗口呀)
这种处理方法:整体意为对象,方法也叫函数。整个的程序设计叫做面向对象程序设计…

传统面向对象….

1
2
3
4
5
6
7
8
9
var Anim = function(){...};
Anim.prototype = {
start:function() {
...
},
stop:function() {
...
}
};

另一种尝试,类面向对象的编程风格

1
2
3
4
5
6
7
Function.prototype.method = function(name,fn) {
this.prototype[name] = fn;
return this;
};//用于链式调用
var Anim = function(){};
Anim.method('start',function() {});
Anim.method('stop',function() {});

语义化标签

标签语义化的好处

  • 去掉样式或者样式丢失时页面结构依然清晰分明
  • 搜索引擎会根据标签的语义确定上下文和权重问题
  • 便于后期的开发以及维护,团队合作效率提高

用过哪些html5特性

  • localstorage的使用,canvas的使用,doctype只需要简单定义,设置charset=uft-8

ajax和跨域

  • 创建一个ajax的过程:
    创建引擎(xmlHttpRequest对象)new XMLHttpRequest or new ActiveXObject 事件处理函数,处理服务器的响应结果 onreadystatechange
    readyState == 4 or status == 200
    responseText包含了从服务器发送的数据
    每次 readyState 值的改变,都会触发 readystatechange 事件
    打开一个连接open(method, url, asynch) 发送数据send(data)
  • 跨域
    动态创建js,如jsonp的实现 document.domain+iframe的设置
    ** flash的实现
  • 事件代理

通过它你可以把事件处理器添加到一个父级元素上,这样就避免了把事件处理器添加到多个子级元素上。事件冒泡以及目标元素。
使用事件代理,我们可以把事件处理器添加到一个元素上,等待一个事件从它的子级元素里冒泡上来,并且可以得知这个事件是从哪个元素开始的。
性能要好 针对新创建的元素,直接可以拥有事件

  • 盒模型d
    有两种, IE 盒子模型、标准 W3C 盒子模型;IE的content部分包含了 border 和 padding;
    盒模型: 内容(content)、填充(padding)、边界(margin)、 边框(border).

  • css的position
    ** absolute

    生成绝对定位的元素,相对于 static 定位以外的第一个祖先元素进行定位。 
    

** fixed (老IE不支持)
生成绝对定位的元素,相对于浏览器窗口进行定位。

** relative
生成相对定位的元素,相对于其在普通流中的位置进行定位。

static 默认值。没有定位,元素出现在正常的流中
(忽略 top, bottom, left, right z-index 声明)。
inherit 规定从父元素继承 position 属性的值。

  • css的flex
1
2
3
4
5
6
7
8
9

/*flex布局(作用于容器)*/
display: flex;

/*水平居中(作用于容器)*/
justify-content: center;

/*垂直居中(作用于容器)*/
align-items: center;
  • 闭包
    一个函数能够访问到另一个函数内的变量!
    函数作为返回值,函数作为参数传递。

  • this
    在函数中this到底取何值,是在函数真正被调用执行的时候确定的,函数定义的时候确定不了
    因为this的取值是执行上下文环境的一部分,每次调用函数,都会产生一个新的执行上下文环境。

学习笔记-设计模式之创建者模式

创建者模式可以将一个复杂对象的构建与其表现形式相分离,使得同样的构建过程可以创建不同的表现形式。
也就是说如果我们用了创建者模式,那么用户只需制定需要建造的类型就可以得到,而具体建造的过程和细节无需了解。上个简单例子….

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function getBeerById(id, callback) {
//使用Id来请求数据,返回数据。
getRequest('get', 'beer.url ? id =' + id, function(resp) {
//callback调用responseTest
callback(resp.responseTest)
});
}

var elm = document.getElementById('test');
elm.addEventListener('click', getBeerByIdBridge, false);
function getBeerByIdBridge(e) {
getBeerById(this.id, function(beer) {
console.log('Requested beer:' + beer);
});
}

根据建造者的定义,表相即是回调,也就是说区数据后如何显示和处理取决于回调函数(callback)
相应的回调函数在处理数据的时候不需要关注是如何获取数据的。
我们在jquery的ajax方法里可以看到很多的回调函数,比如successerror登回调函数,这些都是创建者模式的经典例子
说白了:创建者模式就是-获取数据与处理数据是分离的!

notes

各种apply的妙用

合并数组

1
2
3
var a=[1,2,3], b=[4,5,6]
Array.prototype.push.apply(a, b);
//a = [1,2,3,4,5,6];

数组对象转数组

1
var arr = Array.prototype.slice.call(arguments);

用0补全位数

1
2
3
4
//TODO: 有问题!
function preFixInt(num, length) {
return (num / Math.pow(10,length)).toFixed(length).substr(2);
}

将一个数组插入另一个数组的指定位置

1
2
3
var a=[1,2,3,7,8,9], b=[4,5,6], insertIndex=3;
a.splice.apply(a, Array.prototype.concat(insertIndex, 0, b));
//a = [1, 2, 3, 4, 5, 6, 7, 8, 9]

快速取数组最大和最小值

1
2
Math.max.apply(Math, [1,2,3]); //3
Math.min.apply(Math, [1,2,3]); //1

有意思的技巧

反转字符串

1
2
var str = "aaaaabbbccccbddddd";
console.log(str.split("").reverse().join(""));

数组去重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
funciton unq(a) {
var b = [], c = {}, i;
for (i in a) {
c[a[i]] || (b.push(a[i])), c[a[i]] = true;
}
return b;
}

Array.prototype.unq = function () {
var tempArr = [];
var tempObj = {};
for (var i=0; i<this.length; i++) {
if (!(this[i] in tempObj) || !(this[i] === tempObj[this[i]])) {
tempArr.push(this[i]);
tempObj[this[i]] = this[i];
}

}
return tempArr;
}

生成随机数

1
2
3
4
function randomFrom(low, up) {
var choices = up - low + 1;
return Math.floor(Math.random()*choices + low);
}

学习笔记-设计模式之单例模式

所谓单例模式就是在保证一个类只有一个实例,实现的方法一般是先判断实例存在否,如果存在直接返回,如果不存在就创建了再返回。
那如何创建一个单例呢?其中最简单的一个方式是使用对象字面量的方法,其字面量可以包含大量的属性与方法。

1
2
3
4
5
6
7
var myTest = {
  property1:"something";
  property2:"something else";
  method1:function(){
    console.log("Hello world!");
  }
}

在扩展对象,可以添加自己的私有成员和方法,使用闭包的形式在其内部封装这些变量和函数声明,只暴露你想要暴露的public成员和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
var myTest = function() {
  //私有变量和方法
var pVariable = "some private";
function showPrivate() {
console.log(pVariable);
}
return {
publicMethod: function() {
showPrivate();
},
publicVar: "the public can see this"
};
}

使用的时候var test= myTest(); test.publicMethod();//输出some private
我们也可以在使用的时候才初始化!我们可以再另外一个构造函数里来初始化这些代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var myTest = function() {
var instantiated;
function init() {//这里定义单例代码
return {
publicMethod: function() {
console.log("Hello World");
},
publicProperty: "something testPublic"
}
};
return {
getInstance: function() {
if(!instantiated) {
instantiated = init();
}
return instantiated;
}
};
}

调用的时候var bbb = myTest1();bbb.getInstance().publicMethod();//输出Hello World
单例模式.一般用在系统间各种模式的通信协调上。下面是一个单例模式的最佳实践

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
var BestTest = function() {
//单例的一些参数集合
function bestTest(args) {
var args = args || {};
this.name = "bestTest";
this.pointX = args.pointX || 6;
this.pointY = args.pointY || 10;
}
var instance //实例的容器
var _static = {
name: "bestTest",
getInstance: function(args) {
if(instance === undefined) {
instance = new bestTest(args);
}
return instance;
}
}
return _static;
}

var sss = BestTest().getInstance({ pointX: 77 });
console.log(sss.pointX); // 输出 77