Monthly Archives: 1 月 2012

Hello World 他山石

3D立方体

只支持safari和chrome 😉

1
2
3
4
5
6
7
8
9
10
11
12


转自:http://www.webkit.org/blog-files/3d-transforms/morphing-cubes.html

Hello World 业界杂谈

整站ajax中url的处理

早在两年前,互联网中的网页数量就已超过了1万亿,并且,每天还会增加数十亿。虽然是如此浩瀚的世界,我们却可以通过url轻而易举的找到每一个页面,可见url对于网络世界时多么的重要。

随着浏览器的进步和对用户体验要求的提升,整站ajax之类的一站式前端应用正在逐步取代传统的一个url对一个页面的展示方式。在整站ajax中,数个模块在一个url下,采用无刷新的方式切换,通过减少页面刷新有效的提升了用户体验,但也带来了一些问题:

1. 某些用户习惯根据url判断自己所在的位置,如果明明点击了链接,页面变化了,url却没有变化,用户会比较晕

2. 用户保存书签后,在打开这个书签,得到的可能并不是自己想要的内容

3. 模块间切换后,不能使用浏览器的回退键退回去

针对上述问题,比较简单的方式是使用锚点做标记:每个模块切换时,锚点都会有所变化,比如:/index#list,/index#edit,这样,可以有效的解决上面提到的第1个问题;对第2个问题,前端代码初始化时根据当前页面的hash做些处理也就行了;第3个问题稍微麻烦一些,需要监控页面url的变化。

浏览器不可以给地址栏添加监听时间,只能通过定时读取location.hash/href来判断锚点是否发生了变化。定时长度不能太长,否则影响用户体验,也不能太频,会耗太多资源。这种定时的方式虽然很土,但出了“坚挺”浏览器是否回退、前进以外,却还可以减少很多绑定链接click的操作:只需要给按钮链接的href加上锚点,将参数写在锚点里,用户点击这个url时,锚点变化被定时程序“监听”到,就可以执行相应的逻辑(还顺道解决了按钮重复点击的问题,一举多得呀 :-))。关于如何把button按钮转变为锚点链接的点击可以参考本人以前的博文:js触发链接

不过使用定时方式“监听”浏览器回退,还有一个无法解决的缺陷(只是本人还未发现解决方法),IE6/7的锚点跳转记录不会进入history对象,也就是在IE6/7里,有A页面进入B页面后,B页面内由/B跳到/B#1,再跳到/B#2,再“回退”,也还是会回到A页面,无法回到中间的/B跳和/B#1…….IE而已,可以暂时不去理它。

前面说,使用方式监听地址栏变化有些土,那么,有跟好的办法吗?

之前转发的一篇博文(使用ajax和history.pushState无刷新改变页面URL)里提到了html5的一个新特性:可以注册“popstate”事件监听url的变化,我们可把前面的定时“监听”稍作改进,如果浏览器支持popstate,就使用popstate,如果不支持,在使用定时。本人测试表明,firefox、chrome、safari支持popstate事件,IE系、以及opera不支持。

———-End

Hello World

面向对象的javascript(三)


前两篇介绍了javascript面向对象的基本知识继承的实现,本篇主要介绍this关键字的使用
———–
5. 关于this
this在javascript里是一个比较神奇的东西,新手通常会被它搞到头大

1). 顶层javaScript代码中的this
在顶层javaScript代码中,this指代window对象
在嵌入浏览器中的javascript中,window即全局对象。全局对象只是一个对象,而不是类。既没有构造函数,也无法实例化一个新的全局对象。在顶层javaScript代码中,可以用关键字this引用全局对象。但通常不必用这种方式引用全局对象,因为全局对象是作用域链的头,这意味着所有非限定性的变量和函数名都会作为该对象的属性来查询。
下面几段代码中的this指代的均是window

ex1.
	var abc = 'sss';
	alert(abc);//"sss"
	alert(this.abc);//"sss"
	function fun1(){
		alert(this.abc);
	}
	fun1();//"sss"
	this.alert(123);
	alert(this.parseInt('234s4'));

2). 构造方法/类方法里的this
大部分时候,构造方法/类方法里直接使用this,指代的都是被实例化后的类对象,但是,如果其中有function/setTimeout,或者其他回调函数时,情况就有些不同了,如果想让this仍然指代你你所需要指代的对象,可以使用call/apply方法:

ex2.
	var O1 = function(){
		function O(){
			this.abc = 123;
			function f2(){
				alert(this.abc);
			}
			f2();//直接调用f2方法,this指代window
			f2.call(this);//通过call调用f2方法,this指代O1
		}
		function pf(){
			alert(this.abc);
		}
		O.prototype = {
			f1 : function(){
				pf();//直接调用pf方法,this指代window
				pf.call(this);//通过call调用pf方法,this指代O1
			}
		};
		return O;
	}();
	var o = new O1();
	o.f1();

3). Events的this
这个相对比较简单,在给一个DOM节点注册一个事件处理函数时,函数内的this指代的这个DOM节点:

ex3.
	document.getElementById('xxxx').onclick = function(){
		alert(this.id);
	};
	//使用jquery注册事件时,结果是一样的
	$('#xxxx').click(function(){
		alert(this.id);
		$(this).xxx()...//以this创建jquery对象
	});

4). 回调函数里的this

ex4:
	var abc = 'window';
	//O1
	var O1 = function(){
		function O(){
			this.abc = 'O1';
		}
		O.prototype = {
			f1 : function(){
				alert(this.abc);
			}
		};
		return O;
	}();
	//O2
	var O2 = function(){
		function O(){
			this.abc = 'O2';
		}
		O.prototype.callbackFun = function(fun){
			fun();
		}
		return O;
	}();
	//实例化O1和O2
	var o1 = new O1();
	var o2 = new O2();
	//猜猜看这里会alert什么.....window
	o2.callbackFun(o1.f1);//“window”
	//所以,在使用需要类环境的回调方法时,需要套一层function
	o2.callbackFun(function(){
		o1.f1();//“O1”
	});
	//当然,也可以通过call让this指向O2
	o2.callbackFun(function(){
		o1.f1.call(o2);//“O2”
		o1.f1.call(this);//“window”
	});
Hello World 他山石

[转]使用ajax和history.pushState无刷新改变页面URL

在访问现在很火的google plus时,细心的用户也许会发现页面之间的点击是通过ajax异步请求的,同时页面的URL发生了了改变。并且能够很好的支持浏览器的前进和后退。不禁让人想问,是什么有这么强大的功能呢?

HTML5里引用了新的API,就是history.pushState和history.replaceState,就是通过这个接口做到无刷新改变页面URL的。

与传统的AJAX的区别

传统的ajax有如下的问题:

虽然ajax可以无刷新改变页面内容,但无法改变页面URL

其次为了更好的可访问性,内容发生改变后,改变URL的hash。但是hash的方式不能很好的处理浏览器的前进、后退等问题

有的浏览器引入了onhashchange的接口,不支持的浏览器只能定时去判断hash是否改变

再有,ajax的使用对搜索引擎很不友好,往往蜘蛛爬到的区域是空的

为了解决传统ajax带来的问题,HTML5里引入了新的API,即:history.pushState, history.replaceState

可以通过pushState和replaceState接口操作浏览器历史,并且改变当前页面的URL。

pushState是将指定的URL添加到浏览器历史里,replaceState是将指定的URL替换当前的URL。

如何调用

var state = {
	title: title,
	url: options.url,
	otherkey: othervalue
};
window.history.pushState(state, document.title, url);

state对象除了要title和url之外,也可以添加其他的数据,比如:还想将一些发送ajax的配置给保存起来。

replaceState和pushState是相似的,不需要多做解释。

如何响应浏览器的前进、后退操作

window对象上提供了onpopstate事件,上面传递的state对象会成为event的子对象,这样就可以拿到存储的title和URL了。

window.addEventListener('popstate', function(e){
  if (history.state){
	var state = e.state;
    //do something(state.url, state.title);
  }
}, false);

这样就可以结合ajax和pushState完美的进行无刷新浏览了。

一些限制

1、无法跨域,这个是必然的。引用曾经在网上看到的一句经典的话:“如果javascript可以跨域的话,那他就可以逆天了!”

2、state对象虽然可以存储很多自定义的属性,但值不能是个对象。

对应后端的一些处理

这种模式下除了当前使用ajax可以无刷新浏览外,还要保证直接请求改变的URL后也可以正常浏览,所以后端要对这些处理下。

1、对结合pushState的ajax可以发送一个特殊的头,如: setRequestHeader(‘PJAX’, ‘true’)。

2、后端获取到有PJAX=true的header时,将页面中通用的部分都不输出。比如:PHP可以通过下面的判断

function is_pjax(){
	return array_key_exists('HTTP_X_PJAX', $_SERVER) && $_SERVER['HTTP_X_PJAX'] === 'true';
}

虽然接口上只有pushState、replaceState、onpopstate,但在使用的时候还是要做很多处理的。
————–
转自:http://www.52ladybug.com/?p=202

Hello World

面向对象的javascript(二)

上篇,本次主要将javascript的继承

—————
4. 继承
javascript本身没有类的机制,更不会有子类/父类的概念,但javascript是一个极自由的语言,既然可以用funciton模拟类的实现,肯定也可以通过某种方式来模拟继承

1) . call()
call方法(以及apple方法)用来调用对象O1的一个方法,以另一个对象 O2替换当前对象 O1,而对象的构造函数既然也是“方法”,那么,我们就可以利用它来用子类 O2调用父类 O1的构造方法,使 O2具有在 O1构造方式里为 O1添加的属性、方法,这样,O2就具有的O1的方法和属性:

ex1. 
	//O1 父类
	function O1(){
		this.a1 = 123;
	}
	//O2 子类
	function O2(){
		O1.call(this);
	}
	var o = new O2();
	alert(o.a1);//123

上面例子中的”O1.call(this)”,作用是:用O2里的this替代O1里的this,执行一遍O1(),这样,O2就有了属性a1
这种方法可以是O2继承O1构造函数类通过this.xx定义的属性/方法,但是不能继承O1 prototype添加属性/方法

2) prototype
什么是继承?
继承既是让子类拥有父类的属性和方法,回头再看一下prototype在function模拟Class时的作用:
“function在做为类定义的时候,创建类实例的过程(new的过程)要参照它的prototype对象,把prototype对象的所有属性/方法”
那么,我们可以这样在继承prototype

ex2. 
	//O1
	function O1(){
		this.a1 = 123;
	}
	O1.prototype = {
		f1 : function(){
			alert(this.a1);
		},
		constructor : O1
	};
	//O2
	function O2(){
		//…
	}
	//将O1的所有属性和方法赋到O2.prototype
	O2.prototype = new O1();
	O2.prototype.f2 = function(){...};
	O2.prototype.constructor = O2;
	var o = new O2();
	alert(o.a1);//123

这种方式基本可以实现继承的功能,但是,如大家所看到的,O1和O2的构造函数都不能有参数,在改进一下:
综合ex1.和ex2.,我们可以得到比较实用的继承方式,ex3:

ex3:
	//O1
	function O1(a){
		this.a1 = a;
	}
	O1.prototype = {
		f1 : function(){
			alert(this.a1);
		},
		constructor : O1
	};
	//O2
	function O2(a){
		O1.call(this);
	}
	//将O1的所有属性和方法赋到O2.prototype
	O2.prototype = new O1();
	O2.prototype.f2 = function(){...};
	O2.prototype.constructor = O2;

但是如前面所说,这种书写方式会使代码有些散,另外,在执行O2.prototype = new O1() 时,仍然会无参的执行一遍O1的构造函数,如果O1()有参数,且参数是必须的,就会可能会出现一些错误

3).原型式继承和寄生组合式继承

ex4:
	//原型式继承 
	//将对象o的塑像和方法交给类F的prototype,然后返回实例化F,使返回对象具有o的属性和方法
	function object_(o){
		function F(){}
		F.prototype = o;
		return new F();
	}
	//寄生式继承
	//利用原型式继承的object_方法,将给定对象的属性和方法交给clone,然后为clone添加方法f1
	function createAnother(original){
		var clone = object_(original);
		//在通过原型继承以后,在给clone添加方法,这种方式导致代码复用率很低
		clone.f1() = function(){};
		return clone;
	}
	//寄生组合式继承 使用寄生式继承父类的prototype对象到子类的prototype
	function inheritPrototype(superType, subType){
		var prototype = object_(superType.prototype);
		prototype.construction = subType;
		subType.prototype = prototype;
	}
	//寄生组合式继承仍然只继承prototype,如果要实现完整的继承,仍然需要结合call方法
	//下面是寄生组合式继承的示例
	//O1
	function O1(a){
		this.a1 = a;
	}
	O1.prototype = {
		f1 : function(){
			alert(this.a1);
		},
		constructor : O1
	};
	//O2
	function O2(a){
		O1.call(this);
	}
	//将O2的所有属性和方法赋到O2.prototype
	inheritPrototype(O1, O2);
	O2.prototype.f2 = function(){...};//为子类添加额外的属性/方法

前面ex3.提到的继承方式和寄生组合继承都是javascript比较实用的继承方法,前者虽然有缺陷切效率比较低,但因原理比较好理解,所以使用相当普遍。YUI的YAHOO.lang.extend()使用了寄生组合继承,从而让寄生组合继承首次出现在了一个被广泛使用的javascript类库中。

Hello World

javascript的location对象

属性
hash 锚点,即#及其后面的锚点
host 主机名称+端口号
hostname 主机名称
href url完整地址
pathname 路径
port 端口
protocol 协议
search 搜索条件,即?及其后的参数字串

方法
replace() 更改当前页面url
reload() 从缓存中重新加载页面内容

扩展阅读:
javascript 的history对象
history.back() 等同于按浏览器的后退按钮
history.forward() 等同于按浏览器的前进按钮
history.current 指当前的url(等同于location.href),在历史中的索引位置总为 0
history.go(-2)或 history.go(“任意.html”) 向前或向后移动,或查找字符串标明的最新url
——–
参考:http://blog.sina.com.cn/s/blog_41630ab301008rxg.html

Hello World

if语句的简写方式

今天看YUI压缩的js代码,其中有类似下面的一句看的云里雾里:

s>0&&(b=s,alert(1));

取查看对应的压缩前的代码才明白是什么已是:

if(s > 0){
	b = s;
	alert(1);
}

…一if语句能给搞成这样,YUI果然NB

Hello World

Linux 设定 系统时间

查看:
[root@localhost ~]# date
六 11月 29 21:34:40 CST 2008

设定:
[root@localhost ~]# date 112921242008.29
六 11月 29 21:24:29 CST 2008
格式:date 月日时分年.秒
date -s 11/29/08
date -s 11:29:29

把系统时间强制写入CMOS
[root@localhost ~]# hwclock -w

查看:
[root@localhost ~]# hwclock –show
2008年11月29日 星期六 01时34分43秒 -0.406003 seconds
设定:
[root@localhost ~]# hwclock –set –date=”11/29/2008 22:29:00″
[root@localhost ~]# hwclock
2008年11月29日 星期六 22时29分11秒 -0.321602 seconds
系统时间和硬件时间的同步:
[root@localhost ~]# hwclock –hctosys
[root@localhost ~]# hwclock –systohc
–hctosys set the system time from the hardware clock
–systohc set the hardware clock to the current system time
——–
参考:http://apps.hi.baidu.com/share/detail/31218645

Hello World

面向对象的javascript(一)

1. 为什么要面向对象

如果你只是要用javascript做个用户名校验,那么基于事件驱动的面向过程的编程方法已经足够了,再复杂一点,如果是一个有十几个字段的表单校验,或者你个滑动banner,用上面的方法也还可以;但是如果你要搞一个类似Gmail的东西,哪怕只有其功能的十分之一的的复杂前端应用,面向对象也是必须的了。否则,代码的复杂度将是难以想象的,即使勉强开发完成了,以后的维护也将是个噩梦。


本文将主要介绍javascript对象、类和继承的基础知识,最后讲述了使用“this”的一些经验。

2. 关于javascript对象

1). js对象,即为一组属性和方法的集合,可以动态的添加或删除属性/方法

ex:
	//通过对象直接量创建对象
	var o = {a:123, b:'abc', f:function(){...}};
	//添加属性
	o.c = [1,2,3];
	//添加方法
	o.g = function(){...};
	//删除属性/方法
	delete o.a;
	oc = undefinde;

以上,通过“.”访问的属性/方法,均可以通过‘[]’访问
比如我们可以这么调用jquery对象的hide()方法:
$(‘#xxx’)[‘hide’]();
我们甚至可以这么使用:
var xh = $(‘#xxx’)[‘hide’];
然后将xh作为参数传给其他方法,然后再需要的时候使用 xh() 来执行这个方法

2). 获取对象的类型
typeof
任何对象使用typeof操作符返回均是“object”(Date和数组的typeof也是“object”)
那么我们如何知道对象的类型哪?
constructor属性
每一个对象都有一个constructor属性用类记录当前对象的构造函数

ex:
	var a = [];
	var b = typeof a; //b = "object"
	var c = a.constructor === Array; //true  注意,这里的Array不是字符串

instanceof操作符
每个对象都会有一个内部的属性_proto_,这个属性对js开发人员不可见,只在虚拟机内部使用。每当创建一个对象的时候,这个对象的_proto_就会被赋值为这个对象的构造函数的prototype,这样对象的_proto_属性和构造函数的prototype引用相同的对象,并且一旦对象创建完成,_proto_属性就不会改变。 这样通过对象的_proto_属性,以及_proto_所引用的对象的_proto_属性,就构成了一个_proto_链,及鼎鼎大名的“原型链”。
如:o instanceof c;
在上面的语句执行过程中,虚拟机会把c.prototype和o的_proto_链上的节点逐个进行比较,如果找到相等的节点,则返回true,否则返回false。

ex:
     	var o = new C();//假设C继承自A
	o instanceof C;//true
	a instanceof A;//true
	a instanceof Object;//true

3). 对象的属性
每当javascript读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索首先从对象实例本身开始。如果在实例中找到了具有给定名字的属性,则返回该属性的值;如果没有找到,则继续搜索指针指向类原型的prototype属性,在prototype中查找具有给定名字的属性。如果在prototype中找到了这个属性,则返回该属性的值。虽然可以通过对象实例读取保存在原型中的值,但却不能通过对象实例重写prototype中的值。如果在实例中添加一个与prototype中属性同名的属性,则该属性会屏蔽原型中的那个属性。添加的同名属性只会阻止我们访问原型中的那个属性,但不会修改那个属性。即使将这个属性设置为null,也只会在实例中设置这个属性,而不会恢复其指向prototype的链接。不过,使用delete操作符则可以完全删除实例属性,从而让我们可以重新重新访问prototype中的属性。

3. 类
JavaScritpt没有专门的Class机制,但是我们可以function传创建构造函数,继而通过构造函数创建对象

ex1:
	function O1(){
		//添加属性
		this.a = 123;
		//添加方法
		this.f1 = function(){
			...
		};
	}
	var ot = new O1();
	alert(ot.a);//123

这里,我们就得到了O1的构造函数,另外,我们也可以利用prototype扩展类属性和方法

ex2:
	function O2(){
 
	}
	O2.prototype.a = 1234;
	O2.prototype.f1 = function(){
		alert(this.a);
	};
	var ot = new O2();
	ot.f1();//1234

前面已经提到,prototype是类原型的属性对象,O2的实例化对象ot,在访问ot.f1是,会首先从ot的属性查找f1的定义,如果找不到,就会到O2的prototype内查找。
在实际使用效果上,ex1和ex2基本是相同的,它们的区别是:每new一个O1,就同时创建一份属性和方法,内存中就会多一份O1的属性和方法;而通过prototype扩展的O2的属性和方法,无论O2被实例化几次,在内存中只会有一份,所以,我们推荐使用ex2.的方法来创建类。
但是,通过ex2.的方法创建类,代码有些散,另外,通常,我们希望某些类属性是在各个实现里是不同的

ex3:
	function O3(){
		this.a = 234;
	}
	O3.prototype = {
		f1 : function(){
			alert(this.a);
		},
		//使用这种方式完全覆盖了prototype,对象的constructor属性会变成Object,这一步,是将其修改为O3
		constructor : O3
	};
	var ot = new O3();
	ot.f1();//234

通过ex3.定义的类,在类方法里面通过this参数访问类属性/方法,但这些属性在类方法的外面,通过ot.xx都可以访问,那么,如何来定义私有变量和方法哪?
另外,这种ex3.的定义方式,构造函数和prototype仍然被分成了两部分,还可以进一步优化吗?

ex4:
	var O4 = function(){
		//构造函数
		funciton O(){
			//public
			this.a = 567;
		}
		//private
		var b = 234;
		function pf(){
			return b;
		}
		//public
		O.prototype = {
			f1 : function(){
				alert(b);
			},
			f2 : function(){
				return b;
			},
			constructor : O4
		};
		//返回类O给变量O4
		return O;
	}();//定义一个立即执行的方法
	var ot = new O4();
	ot.f1();//234

到这里,就和java书写class的方式差不多了吧,让我们来总结一下:
a. 在构造函数中添加类属性,在prototype添加类方法
b. 将类代码放在一个立即执行的function中,形成一个单独的命名空间,只对完暴露构造函数,可以在里面模拟private的属性和方法
c. 记得重新定义prototype.constructor,否则用到的时候可能会出错(其实大部分时候用不着它)
此外,我们还可以通过下面这种方式书写prototype来封装私有属性和方法

ex5:
	var O5 = function(){
		//构造函数
		funciton O(){
			//public
			this.a = 567;
		}
 
		//通过立即执行的function返回prototype对象	
		O.prototype = function(){
			//属性和方法
			var b = 234;
			var c = 2345;
			function f1(){
				//...
			}
			function f2(){
				//...
			}
			//通过return返回给prototype便是public,其他的private
			return {
				c : c,
				f1 : f1
			}
		}();
		return O;
	}();

如本节刚开时所述,“ JavaScritpt没有专门的Class机制”,我们只能使用构造函数和原型链来模拟类的实现,有众多的方法可以写出一个类,我们需要根据实际的需要来确定类的写法。


~~~未完待续