Underscore 常用方法

概述

Underscore.js是一个很精干的库,压缩后只有4KB。它提供了几十种函数式编程的方法,大大方便了Javascript的编程。MVC框架backbone.js就是基于这个库。

它定义了一个下划线(_)对象,函数库的所有方法都属于这个对象。这些方法大致上可以分成:集合(collection)、数组(array)、函数(function)、对象(object)和工具(utility)五大类。

 

在node.js下安装

Underscore.js不仅可以用于浏览器环境,还可以用于node.js。安装命令如下:

npm install underscore

但是,node.js不能直接使用_作为变量名,因此要用下面的方法使用underscore.js

var u = require("underscore");

 

与集合有关的方法

Javascript语言的数据集合,包括两种结构:数组和对象。以下的方法同时适用于这两种结构。

 

map

该方法对集合的每个成员依次进行某种操作,将返回的值依次存入一个新的数组。

_.map([1, 2, 3], function(num){ return num * 3; });  // [3, 6, 9]    _.map({one : 1, two : 2, three : 3}, function(num, key){ return num * 3; });  // [3, 6, 9]

 

each

该方法与map类似,依次对集合的每个成员进行某种操作,但是不返回值。

_.each([1, 2, 3], alert);    _.each({one : 1, two : 2, three : 3}, alert);

 

reduce

该方法依次对集合的每个成员进行某种操作,然后将操作结果累计在某一个初始值之上,全部操作结束之后,返回累计的值。

该方法接受三个参数。第一个参数是被处理的集合,第二个参数是对每个成员进行操作的函数,第三个参数是累计用的变量。

_.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);  // 6

reduce方法的第二个参数是操作函数,它本身又接受两个参数,第一个是累计用的变量,第二个是集合每个成员的值。

 

filter 和 reject

filter方法依次对集合的每个成员进行某种操作,只返回操作结果为true的成员。

_.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });  // [2, 4, 6]

reject方法只返回操作结果为false的成员。

_.reject([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });  // [1, 3, 5]

 

every 和 some

every方法依次对集合的每个成员进行某种操作,如果所有成员的操作结果都为true,则返回true,否则返回false。

_.every([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });  // false

some方法则是只要有一个成员的操作结果为true,则返回true,否则返回false。

_.some([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });  // true

 

find

该方法依次对集合的每个成员进行某种操作,返回第一个操作结果为true的成员。如果所有成员的操作结果都为false,则返回undefined。

_.find([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });  // 2

 

contains

如果某个值在集合内,该方法返回true,否则返回false。

_.contains([1, 2, 3], 3);  // true

 

countBy

该方法依次对集合的每个成员进行某种操作,将操作结果相同的成员算作一类,最后返回一个对象,表明每种操作结果对应的成员数量。

_.countBy([1, 2, 3, 4, 5], function(num) {    return num % 2 == 0 ? 'even' : 'odd';  });  // {odd: 3, even: 2}

 

shuffle

该方法返回一个打乱次序的集合。

_.shuffle([1, 2, 3, 4, 5, 6]);  // [4, 1, 6, 3, 5, 2]

 

size

该方法返回集合的成员数量。

_.size({one : 1, two : 2, three : 3});  // 3

 

与对象有关的方法

 

toArray

该方法将对象转为数组。

 _.toArray({a:0,b:1,c:2});  // [0, 1, 2]

 

pluck

该方法将多个对象的某一个属性的值,提取成一个数组。

var stooges = [{name : 'moe', age : 40}, {name : 'larry', age : 50}, {name : 'curly', age : 60}];    _.pluck(stooges, 'name');  // ["moe", "larry", "curly"]

 

与函数相关的方法

 

bind

该方法绑定函数运行时的上下文,作为一个新函数返回。

_.bind(function, object, [*arguments])

请看下面的实例。

var o = {      p: 2,      m: function (){console.log(p);}  };    o.m()  // 2    _.bind(o.m,{p:1})()  // 1

 

bindAll

该方法将某个对象的所有方法(除非特别声明),全部绑定在该对象上面。

var buttonView = {    label   : 'underscore',    onClick : function(){ alert('clicked: ' + this.label); },    onHover : function(){ console.log('hovering: ' + this.label); }  };    _.bindAll(buttonView);

 

partial

该方法绑定将某个函数与参数绑定,然后作为一个新函数返回。

var add = function(a, b) { return a + b; };    add5 = _.partial(add, 5);    add5(10);  // 15

 

memoize

该方法缓存一个函数针对某个参数的运行结果。

var fibonacci = _.memoize(function(n) {    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);  });

如果一个函数有多个参数,则需要提供一个hashFunction,用来生成标识缓存的哈希值。

 

delay

该方法可以将函数推迟指定的时间再运行。

var log = _.bind(console.log, console);    _.delay(log, 1000, 'logged later');  // 'logged later'

 

defer

该方法可以将函数推迟到待运行的任务数为0时再运行,类似于setTimeout推迟0秒运行的效果。

_.defer(function(){ alert('deferred'); });

 

throttle

该方法返回一个函数的新版本。连续调用这个新版本的函数时,必须等待一定时间才会触发下一次执行。

// 返回updatePosition函数的新版本  var throttled = _.throttle(updatePosition, 100);    // 新版本的函数每过100毫秒才会触发一次  $(window).scroll(throttled);

 

debounce

该方法也是返回一个函数的新版本。每次调用这个新版本的函数,必须与上一次调用间隔一定的时间,否则就无效。它的典型应用是防止用户双击某个按钮,导致两次提交表单。

$("button").on("click", _.debounce(submitForm, 1000));

 

once

该方法返回一个新版本的函数,使得这个函数只能被运行一次。主要用于对象的初始化。

var initialize = _.once(createApplication);  initialize();  initialize();  // Application只被创造一次

 

after

该方法返回一个新版本的函数,这个函数只有在被调用一定次数后才会运行,主要用于确认一组操作全部完成后,再做出反应。

var renderNotes = _.after(notes.length, render);  _.each(notes, function(note) {    note.asyncSave({success: renderNotes});  });  // 所有的note都被保存以后,renderNote才会运行一次

 

wrap

该方法将一个函数作为参数,传入另一个函数,最终返回前者的一个新版本。

var hello = function(name) { return "hello: " + name; };  hello = _.wrap(hello, function(func) {    return "before, " + func("moe") + ", after";  });  hello();  // 'before, hello: moe, after'

 

compose

该方法接受一系列函数作为参数,由后向前依次运行,上一个函数的运行结果,作为后一个函数的运行参数。也就是说,将f(g(),h())的形式转化为f(g(h()))。

var greet    = function(name){ return "hi: " + name; };  var exclaim  = function(statement){ return statement + "!"; };  var welcome = _.compose(exclaim, greet);  welcome('moe');  // 'hi: moe!'

 

工具方法

 

template

该方法用于编译HTML模板。它接受三个参数。

_.template(templateString, [data], [settings])

三个参数的含义如下:

  • templateString:模板字符串
  • data:输入模板的数据
  • settings:设置

 

templateString

模板字符串templateString就是普通的HTML语言,其中的变量使用<%= … %>的形式插入;data对象负责提供变量的值。

var txt = "

<%= word %>

";    _.template(txt, {word : "Hello World"})  // "

Hello World

"

如果变量的值包含五个特殊字符(& < > ” ‘ /),就需要用<%- … %>转义。

var txt = "

<%- word %>

";    _.template(txt, {word : "H &amp; W"})  //

H & W

JavaScript命令可以采用<% … %>的形式插入。下面是判断语句的例子。

var txt = "&lt;% var i = 0; if (i&lt;1){ %&gt;"          + "&lt;%= word %&gt;"          + "&lt;% } %&gt;";    _.template(txt, {word : "Hello World"})  // Hello World

常见的用法还有循环语句。

var list = "&lt;% _.each(people, function(name) { %&gt;
  • <%= name %> <% }); %>”;    _.template(list, {people : [‘moe’, ‘curly’, ‘larry’]});  // “
  • moe
  • curly
  • larry”

如果template方法只有第一个参数templateString,省略第二个参数,那么会返回一个函数,以后可以向这个函数输入数据。

var t1 = _.template("Hello &lt;%=user%&gt;!");      t1({ user: "" })   // 'Hello !'

 

data

templateString中的所有变量,在内部都是obj对象的属性,而obj对象就是指第二个参数data对象。下面两句语句是等同的。

_.template("Hello &lt;%=user%&gt;!", { user: "" })  _.template("Hello &lt;%=obj.user%&gt;!", { user: "" })

如果要改变obj这个对象的名字,需要在第三个参数中设定。

_.template("&lt;%if (data.title) { %&gt;Title: &lt;%= title %&gt;&lt;% } %&gt;", null,                  { variable: "data" });

因为template在变量替换时,内部使用with语句,所以上面这样的做法,运行速度会比较快。

cursor — 定义鼠标样式

取值: [ [<uri> ,]* [ auto | crosshair | default | pointer | move | e-resize | ne-resize | nw-resize | n-resize | se-resize | sw-resize | s-resize | w-resize | text | wait | help | progress ] ] | inherit

  • [<uri> ,]*: 根据用户定义的资源显示
  • auto: 正常鼠标
  • crosshair: 十字鼠标
  • default: 默认鼠标
  • pointer: 点状鼠标
  • move: 移动鼠标
  • e-resize,ne-resize,nw-resize,n-resize,se-resize,sw-resize,s-resize,w-resize: 改变大小鼠标
  • text: 文字鼠标
  • wait: 等待鼠标
  • help: 求助鼠标
  • progress: 过程鼠标
  • inherit: 继承
post

windows 下安装nodejs及其配置环境

相信对于很多关注javascript发展的同学来说,nodejs已经不是一个陌生的词眼。有关nodejs的相关资料网上已经铺天盖地。由于它的高并发特性,造就了其特殊的应用地位。

国内目前关注最高,维护最好的一个关于nodejs网站应该是http://www.cnodejs.org/

这里不想谈太多的nodejs的相关信息。只说一下,windows系统下简单nodejs环境配置。

第一步:下载安装文件

下载地址:官网http://www.nodejs.org/download/ 

 

这里用的是 

第二步:安装nodejs

下载完成之后,双击 node-v0.8.16-x86.msi,开始安装nodejs,默认是安装在C:\Program Files\nodejs下面

第三步:安装相关环境

打开C:\Program Files\nodejs目录你会发现里面自带了npm,直接用npm安装相环境既可

进入node.js command prompt 命令窗口

进入nodejs 安装目录 C:\Program Files\nodejs

键入命令:cd C:\Program Files\nodejs 既可

现在开始安装相关环境

键入命令:npm express 回车等待安装express……..

键入命令:npm jade 回车等待安装jade……..

键入命令:npm mysql回车等待安装mysql……..

……..安装什么组件,取决于环境搭建需求

默认情况下上述组件都是安装在C:\Program Files\nodejs\node_modules文件夹下 这也是nodejs相关组件的自动查找路径

第四步:创建一个工程

现在已经有express

express命令安装在全局才起作用!

所以express安装的时候要用 npm install express -g

或者直接修改全局路径:

npm config set prefix “C:\Program Files\nodejs

npm config set cache “C:\Program Files\nodejs\cache” (先建好cache目录)

键入:express myapp (myapp是随意起的工程名称)

你会发现多了一个 C:\Program Files\nodejs\myapp 目录

默认情况下:里会自动创建 

这几个文件,不做解释,相信有过开发经验的同学都能一眼明了。

复制node_modules到myapp下面

环境搭建到此完工,下面做一个demo测试!

在myapp下新建helloworld.js

复制代码
var http = require("http");
http.createServer(function(request, response) {  
    response.writeHead(200, {"Content-Type": "text/plain"});  
    response.write("Hello World");  
    response.end();
}).listen(8888);
console.log("nodejs start listen 8888 port!");
复制代码

进入node.js command prompt 命令窗口,进入C:\Program Files\nodejs\myapp目录

键入node helloworld.js

打开地址http://127.0.0.1:8888/

发现输出 :

Hello World

CSS3的响应式布局

做手机端网页需要用到响应式布局,首先需要再HTML文件头声明一下:

&lt;meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" /&gt;

主要目的是宽度控制和禁止用户缩放,具体参数自己GOOGLE一下。

下面是CSS判断是PC端还是移动端
其实很简单,用CSS3的媒体查询就可以非常方便去实现,不需要用userAgent神马的那么麻烦。

/*最小宽度800就是PC端*/
@media all and (min-width: 800px) {
  #nav {
    width: 300px;
    float: left;
    margin-right: 20px;
  }
  #grid {
    width: 450px;
    float: left;
  }
}
/*最大宽度799就是移动端*/
@media all and (max-width: 799px) {
  #nav {
    width: 100%;
  }
  #grid {
    width: 100%;
  }
}

知道了上面2点就可以实现响应式布局了,是不是非常简单?
移动端还有一些特殊的事件(手指滑动)神马的,后续我再专门写篇移动端的JS文章好了。

云盘助手1.0 上线了

最近发现百度云上面资源真多,可以说已经离不开她了,未来云存储也是个趋势,不过百度云有一个缺点,就是没有搜索功能,找起东西来很不爽,于是云盘助手(使用backbone+seajs开发的MVC架构webapp,源码没有压缩加密可以随便看哈~)就诞生了,不仅仅搜索百度云喔~~

因为刚上线还没什么流量,暂时放在我的2级域名下面吧,观察一段时间再决定要不要加强它。
云盘助手地址:http://search.liuxiaofan.com/

JS将所有对象s的属性复制给对象r

原生写法:

/**
		 * 将所有 s 的属性复制给 r
		 * @param r {Object}
		 * @param s {Object}
		 * @param is_overwrite {Boolean} 如指定为 false ,则不覆盖已有的值,其它值
		 *	  包括 undefined ,都表示 s 中的同名属性将覆盖 r 中的值
		 */
		mix: function (r, s, is_overwrite) { //TODO:
			if (!s || !r) return r;

			for (var p in s) {
				if (is_overwrite !== false || !(p in r)) {
					r[p] = s[p];
				}
			}
			return r;
		}

jQuery写的话就太方便了

var a={
        aa:1,
        ab:2
    };
    var b={
        ba:1,
        bb:2
    };
    $.extend(a,b);
    console.info(a);