标签:Douglas-Crockford Javascript 最佳实践
原文链接更好的阅读体验
Function.PRototype.method = function (name, func) { if (!this.prototype[name]) { this.prototype[name] = func; } return this;}
Number.method("integer", function () { return Math[this < 0 ? 'ceil' : 'floor'](this);});
String.method("trim", function () { return this.replace(/^/s+|/s+$/g, '');})
var myObject = (function () { var value = 0; return { increment: function (inc) { value += typeof inc === "number" ? inc : 1; }, getValue: function () { return value; } };}());
// 定义var memoizer = function (memo, formula) { var recur = function (n) { var result = memo[n]; if (typeof result !== 'number') { result = formula(recur, n); memo[n] = result; } return result; }; return recur;};// 使用var fibonacci = memoizer([0, 1], function (recur, n) { return recur(n-1) + recur(n - 2);});for (var i = 0; i <= 10; i++) { console.log("%d : %d", i, fibonacci(i));}// 扩展用法 阶乘var factorial = memoizer([1, 1], function (recur, n) { return n * recur (n - 1)});for (var i = 1; i <= 10; i++) { console.log("%d : %d", i, factorial(i));}
var
语句定义的普通变量// 这里是一个函数化构造器的伪代码模板(加粗的文本表示强调):var **constructor** = function (spec, my) { // 代码快内部不知道怎么加粗,哪位大神指点一下 var that, **其他私有变量**; my = my || {}; // **把共享的变量和函数添加到my中** that = { name: "**一个新对象**" }; // **给that添加特权方法** return that;}// spec 对象包含构造器需要构造一个新实例的所哟信息。spec 的内容可能会被复制到私有变量中,或者被其他函数改变,或者方法可以在需要的时候访问spec的信息。(一个简化的方式是替换spec为一个单一的值。当构造对象过程中并不需要整个spec对象的时候,这是有用的。)// my 对象是一个为继承链中的构造器提供秘密共享的容器。my对象可以选择性地使用。如果没有传入一个my对象,那么会创建一个my对象// demovar mammal = function (spec) { var that = {}; that.get_name = function () { return spec.name; }; that.says = function () { return spec.saying || ""; } return that;};var cat = function (spec) { spec.saying = spec.saying || 'meow'; var that = mammal(spec); that.purr = function (n) { var i, s = ''; for (i = 0; i < n; i += 1) { if (s) { s += "-"; } s += "r"; } return s; }; that.get_name = function () { return that.says() + " " + spec.name + " " + that.says(); }; return that;};var myCat = cat({name: "Henrietta"});
Object.method('superior', function (name) { var that = this, method = that[name]; return function () { return method.apply(that, arguments); };});
让我们在coolcat上试验一下,coolcat就像cat一样,除了它有一个更酷的调用父类方法的get_name方法。它只需要一点点的准备工作。我们会声明一个super_get_name变量,并且把调用superior方法所返回的结果赋值给它。
var coolcat = function (spec) { var that = cat(spec), super_get_name = that.superior('get_name'); that.get_name = function (n) { return 'like ' + super_get_name() + ' baby'; }; return that;};var myCoolCat = coolcat({name: 'Bix'});var name = myCoolCat.get_name();console.log(name); // "like meow Bix meow baby"
我们可以从一套部件中把对象组装出来。例如,我们可以构造一个给任何对象添加简单事件处理特性的函数。他会给对象添加一个on
方法、一个fire
方法和一个私有的事件注册表对象:
var eventuality = function (that) { var registry = {}; that.fire = function (event) { // 在一个对象上触发一个事件。该事件可以是一个包含事件名称的字符串 // 或者是一个拥有包含事件名称的 type 属性的对象。 // 通过'on'方法注册的事件处理程序中匹配事件名称的函数将被调用。 var array, func, handler, i, type = typeof event === 'string' ? event : event.type; if (registry.hasOwnProperty(type)) { array = registry[type]; for (i = 0; i < array.length; i += 1) { handler = array[i]; // 每个处理程序包含一个方法和一组可选的参数。 // 如果该方法是一个字符串形式的名字,那么寻找到该函数。 func = handler.method; if (typeof func === 'string') { func = this[func]; } // 调用一个处理程序。如果该条目包含参数,那么传递它们过去。否则,传递该事件对象。 func.apply(this, handler.parameters || [event]); } } return this; }; that.on = function (type, method, parameters) { // 注册一个事件。构造一条处理程序条目。将它插入到处理程序数组中, // 如果这种类型的事件还不存在,就构造一个。 var handler = { method: method, parameters: parameters }; if (registry.hasOwnProperty(type)) { registry[type].push(handler); } else { registry[type] = [handler]; } return this; }; return that;};
我们可以在任何单独的对象上调用eventuality, 授予它事件处理方法。我们也可以赶在that
被返回之前在一个构造器函数中调用它 eventuality(that);
eventuality(myCoolCat);myCoolCat.health = 100;myCoolCat.on('dead', function (event) { var date = event.date; var killer = event.killer; console.log("%s killed me at %s", killer, date);});myCoolCat.on('hurt', function () { this.health -= 50; if (this.health <= 0) { var event = { type: 'dead', killer: 'stone from sky', date: new Date() }; this.fire(event); } else { console.log('nothing, who is the strong guy.'); }});myCoolCat.fire("hurt"); //nothing, who is the strong guy.myCoolCat.fire("hurt"); //stone from sky killed me at Sat Mar 14 2015 15:47:29 GMT+0800 (CST)
javascript 编程中,一个常见的错误是在必须使用数组时使用了对象,或者在必须使用对象时使用了数组。其实规则很简单:当属性名是小而连续的整数时,你应该使用数组。否则,使用对象。javascript 本身没有一个好的机制来区分数组和对象。我们可以通过定义自己的is_array函数来弥补这个缺陷:
var is_array = function (value) { return value && typeof value === 'object' && value.constructor === Array;};// 不过该方法在识别从不同的窗口(window)或者frame里构造的数组时会失败。下面是一个更好的方式// 上面这句话这里本人尚未理解,请高手指点var is_array = function (value) { return Object.prototype.toString.apply(value) === '[object Array]';};
Array.method('reduce', function (f, value) { var i; for (i = 0; i < this.length; i += 1) { value = f(this[i], value); } return value;});// DEMOvar data = [4, 8, 15, 16, 23, 42];var add = function (a, b) { return a + b;};var mult = function (a, b) { return a * b;};var sum = data.reduce(add, 0);console.log(sum);// 108var product = data.reduce(mult, 1);console.log(product); // 7418880// 因为数组其实就是对象,所以我们可以直接给一个单独的数组添加方法data.total = function () { return this.reduce(add, 0);};var total = data.total();console.log(total); // 108
Array.dim = function (dimension, initial) { var a = [], i; for (i = 0; i < dimension; i += 1) { a[i] = initial; } return a;};var myArray = Array.dim(10, 0); //[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]// 注意这里不能使用我们之前说的method方法,应为那个方法是给某个类型的每一个具体的对象增加方法的,而这里我们是给Array这个 类型 增加方法,类似于某些静态语言中的静态方法或者类方法
sort
方法会array
中的内容进行排序。但是它不能正确第给
新闻热点
疑难解答