JavaScript_patterns
一些问题的记录
如何添加事件
// the interface
var utils = {
addListener: null,
removeListener: null
};
// the implementation
if (typeof window.addEventListener === 'function') {
utils.addListener = function (el, type, fn) {
el.addEventListener(type, fn, false);
};
utils.removeListener = function (el, type, fn) {
el.removeEventListener(type, fn, false);
};
} else if (typeof document.attachEvent === 'function') { // IE
utils.addListener = function (el, type, fn) {
el.attachEvent('on' + type, fn);
};
utils.removeListener = function (el, type, fn) {
el.detachEvent('on' + type, fn);
};
} else {
utils.addListener = function (el, type, fn) {
el['on' + type] = fn;
};
utils.removeListener = function (el, type, fn) {
el['on' + type] = null;
};
}
call和apply
// define a function
var sayHi = function (who) {
console.log("Hello" + (who ? ", " + who : "") + "!");
};
// invoke a function
sayHi(); // "Hello"
sayHi('world'); // "Hello, world!"
// apply a function
sayHi.apply(null, ["hello"]); // "Hello, hello!"
sayHi.apply(null); // "Hello!"
// call a function
sayHi.call(null,'hello'); // "Hello, hello!"
sayHi.call(null); // "Hello!"
Curry
function add(x) {
return function (y) {
return x + y;
};
}
console.log(add(3)(4)); // 7
console.log(add(3)); // function
// create and store a new function
var add2000 = add(2000);
console.log(add2000(10)); // 2010
通用化Curry
function curry(fn) {
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function () {
var new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
}
}
function add(x, y) {
return x + y;
}
var add = curry(add, 5);
console.log(add(4)); // 9
用闭包实现只get
var my;
(function () {
var name = "my";
my = {
getName: function () {
return name;
}
};
}());
console.log(my.getName());
var your = (function () {
var name = "your";
return {
getName: function () {
return name;
}
};
}());
console.log(your.getName());
暴露方法
Util.array = (function () {
// private properties
var array_string = "[object Array]",
ops = Object.prototype.toString,
// private methods
inArray = function (haystack, needle) {
for (var i = 0, max = haystack.length; i < max; i += 1) {
if (haystack[i] === needle) {
return i;
}
}
return -1;
},
isArray = function (a) {
return ops.call(a) === array_string;
};
// revealing public API
return {
isArray: isArray,
indexOf: inArray
};
}());
类式继承#1->指向父函数的实例
function Parent(name) {
this.name = name || 'parent';
this.age = 10;
}
Parent.prototype.say = function () {
return this.name;
};
function Child(name) {
this.name = name;
}
function inherit(C, P) {
/**
*该继承模式同时继承了两个对象的属性,即添加到this的属性以及原型属性。
*在绝大多数的时候,并不需要这些自身的属性。
*/
C.prototype = new P();
}
inherit(Child, Parent);
var child = new Child('child');
console.log(child.name); //child
console.log(child.__proto__.name); //parent
console.log(child.age); //10
类式继承#2-> 借用构造函数
function Parent(name) {
this.name = name || 'parent';
}
Parent.prototype.say = function () {
return this.name;
};
function Child(name) {
/**
*可以获得父对象自身成员的真实副本,不会存在覆盖
* 无法从原型中继承任何东西 ,它并不会为每个实例重新创建原型。
*/
Parent.apply(this, arguments);
}
var child = new Child('child');
console.log(child.name); //child
console.log(child.say()); //Uncaught TypeError: undefined is not a function
类式继承#3->借用并设置原型
function Parent(name) {
this.name = name || 'parent';
}
Parent.prototype.say = function () {
return this.name;
};
function Child(name) {
//借用构造函数
Parent.apply(this, arguments);
}
//子构造函数的原型使其指向父构造函数创建的新实例
Child.prototype = new Parent();
var child = new Child('child');
console.log(child.say()); //child
类式继承#4->共享原型
function Parent(name) {
this.name = name || 'parent';
}
Parent.prototype.say = function () {
return this.name;
};
function Child(name) {
this.name = name;
}
/**
* 所以的对象实例实际上都共享了同一个原型。但是,这同时也是一个缺点,
* 继承链下方的某处存在一个子对象修改了原型,它将会影响到所有的父对象和祖先对象。
*/
function inherit(C, P) {
C.prototype = P.prototype;
}
inherit(Child, Parent);
var parent = new Parent();
var child = new Child('child');
console.log(child.say()); //child
console.log(parent.say()); //parent
Child.prototype.say = function () {
return this.name+' changed!';
};
console.log(child.say()); //child changed!
console.log(parent.say()); //parent changed!
类式继承#5->临时构造函数
function Parent(name) {
this.name = name || 'parent';
}
Parent.prototype.say = function () {
return this.name;
};
function Child(name) {}
/**
* 这里的子对象仅仅继承了父对象的原型中的属性,原型正是放置可复用功能的位置。
* 父构造函数添加到this中的任何成员都不会被继承。
*/
function inherit(C, P) {
var F = function () {};
F.prototype = P.prototype;
C.prototype = new F();
}
inherit(Child, Parent);
var child = new Child('child');
console.log(child.name); //undefined
console.log(child.say); //function () {...}
现代继承方式#1->原型继承
function object(o) {
function F() {};
F.prototype = o;
return new F();
}
function Person() {
this.name = 'parent';
}
Person.prototype.getName = function () {
return this.name;
};
var parent = new Person();
var child = object(parent);
console.log(child.getName()); //parent
现代继承方式#2->复制对象
//浅复制
function extend(parent, child) {
var i;
child = child || {};
for (i in parent) {
if (parent.hasOwnProperty(i)) {
child[i] = parent[i];
}
}
return child;
}
//深度复制
function extendDeep(parent, child) {
var i,
toStr = Object.prototype.toString,
astr = '[object Array]';
child = child || {};
for (i in parent) {
if (parent.hasOwnProperty(i)) {
if (typeof parent[i] === 'object') {
child[i] = (toStr.call(parent[i]) === astr) ? [] : {};
extendDeep(parent[i], child[i]);
} else {
child[i] = parent[i];
}
}
}
return child;
}
//测试深度复制
var parent = {
counts: [1, 2, 3],
reads: {paper: true}
};
var child = extendDeep(parent);
child.counts.push(4);
console.log(child.counts.toString()); //1,2,3,4
console.log(parent.counts.toString()); //1,2,3
现代继承方式#3->方法借用
只是方法借用而已用call或者apply去调用父类的方法
单例实现
function Singleton() {
// the cached instance
var instance = this;
// proceed as normal
this.name = 'Singleton';
// rewrite the constructor
Singleton = function () {
return instance;
};
}
var s1 = new Singleton();
var s2 = new Singleton();
console.log(s1===s2); //true
console.log(s1.name); //Singleton
迭代器
var Iterator = function (arr) {
return {
index: -1,
hasNext: function () {
//console.log('index ' + this.index)
return this.index < arr.length-1;
},
hasPrevious: function () {
return this.index > 0;
},
current: function () {
return arr[ this["index"] ];
},
next: function () {
if (this.hasNext()) {
this.index = this.index + 1;
return this.current();
}
return false;
}
}
};
var arr = [1, 2, 3, 4, 5];
var iterator = Iterator(arr);
while (iterator.hasNext()) {
console.log(iterator.next());
}