【www.gdgbn.com--php常用代码】

是指在程序运行前,无需检查对象类型,只要检查对象是否支持特性和方法即可。可以在绑定前对对象执行大量操作而不受任何惩罚。
上面代码出现的“预声明”现象,我们大可用“晚绑定”机制来解释。在函数的作用域中,所有变量都是“晚绑定”的。 即声明是顶级的。所以上面的代码和下面的一致:
复制代码 代码如下:

var a = "global";
(function () {
var a;
alert(a);
a = "local";
})();

在alert(a)之前只对a作了声明而没有赋值。所以结果可想而知。


  rt:本文要说的是,在网页特效里,我所知道的几种定义类和对象的方式:
  【直接量方式】
  使用直接量构建对象是最基础的方式,但也有很多弊端。
复制代码 代码如下:

var obj = new object;
obj.name = "sun";
obj.showname = function() {
alert("this.name");
}

我们构建了一个对象obj,它有一个属性name,一个方法showname。但是如果我们要再构建一个类似的对象呢?难道还要再重复一遍?
no!,我们可以用一个返回特定类型对象的工厂函数来实现。就像工厂一样,流水线的输出我们要的特定类型结果。
  【工厂方式】
复制代码 代码如下:

function createobj(name) {
var tempobj = new object;
tempobj.name = name;
tempobj.showname = function () {
alert(this.name);
};
return tempobj;
}
var obj1 = createobj("obj_one");
var obj2 = createobj("obj_two");

 

  这种工厂函数很多人是不把他当做构建对象的一种形式的。一部分原因是语义:即它并不像使用了运算符new来构建的那么正规。还有一个更大的原因,是因为这个工厂每次产出一个对象都会创建一个新函数showname(),即每个对象拥有不同的版本,但实际上他们共享的是同一个函数。
有些人把showname在工厂函数外定义,然后通过属性指向该方法,可以避开这个问题:
复制代码 代码如下:

 

function showname () {
alert(this.name);
}
function createobj(name) {
var tempobj = new object;
tempobj.name = name;
tempobj.showname = showname;
return tempobj;
}
var obj1 = createobj("obj_one");
var obj2 = createobj("obj_two");

可惜的是,这种方式让showname()这个函数看起来不像对象的一个方法。
  【构造函数方式】
这种方式是为了解决上面工厂函数的第一个问题,即没有new运算符的问题。可是第二个问题它依然不能解决。我们来看看。
复制代码 代码如下:

function obj(name) {
this.name = name;
this.showname = function () {
alert(this.name);
}
}
var obj1 = new obj("obj_one");
var obj2 = new obj("obj_two");

它的好处是不用在构造函数内新建一个对象了,因为new运算符执行的时候会自动创建一个对象,并且只有通过this才能访问这个对象。所以我们可以直接通过this来对这个对象进行赋值。而且不用再return,因为this指向默认为构造函数的返回值。
同时,用了new关键字来创建我们想要的对象是不是感觉更“正式”了。
可惜,它仍然不能解决会重复生成方法函数的问题,这个情况和工厂函数一样。

  【原型方式】
这种方式对比以上方式,有个很大的优势,就是它解决了方法函数会被生成多次的问题。它利用了对象的prototype属性。我们依赖原型可以重写对象实例。
复制代码 代码如下:

var obj = function () {}
obj.prototype.name = "me";
obj.prototype.showname = function () {
alert(this.name);
}
var obj1 = new obj();
var obj2 = new obj();

 

  我们依赖原型对构造函数进行重写,无论是属性还是方法都是通过原型引用的方式给新建的对象,因此都只会被创建一次。可惜的是,这种方式存在两个致命的问题:
1。没办法在构建对象的时候就写入想要的属性,因为原型在构造函数作用域外边,没办法通过传递参数的方式在对象创建的时候就写入属性值。只能在对象创建完毕后对值进行重写。
2。致命问题在于当属性指向对象时,这个对象会被多个实例所共享。考虑下面的代码:
复制代码 代码如下:

 

var obj = function () {}
obj.prototype.name = "me";
obj.prototype.flag = new array("a", "b");
obj.prototype.showname = function () {
alert(this.name);
}
var obj1 = new obj();
var obj2 = new obj();
obj1.flag.push("c");
alert(obj1.flag); // a,b,c
alert(obj2.flag); //a,b,c

是的,当flag属性指向对象时,那么实例obj1和obj2都共享它,哪怕我们仅仅改变了obj1的flag属性,但是它的改变在实例obj2中任然可见。
面对这个问题,让我们不得不想是否应该把【构造函数方式】和【原型方式】结合起来,让他们互补。。。

  【构造函数和原型混合方式】
我们让属性用构造函数方式创建,方法用原型方式创建即可:
复制代码 代码如下:

var obj = function (name) {
this.name = name;
this.flag = new array("a", "b");
}
obj.prototype = {
showname : function () {
alert(this.name);
}
}
var obj1 = new obj();
var obj2 = new obj();
obj1.flag.push("c");
alert(obj1.flag); // a,b,c
alert(obj2.flag); //a,b

 

  这种方式有效地结合了原型和构造函数的优势,是目前用的最多,也是副作用最少的方式。
不过,有些追求完美的家伙还不满足,因为在视觉上还没达到他们的要求,因为通过原型来创建方法的过程在视觉上还是会让人觉得它不太像实例的方法(尤其对于传统oop语言的开发者来说。)
所以,我们可以让原型活动起来,让他也加入到构造函数里面去,好让这个构造函数在视觉上更为统一。而这一系列的过程只需用一个判断即可完成。
复制代码 代码如下:

 

var obj = function (name) {
this.name = name;
this.flag = new array("a", "b");
if (typeof obj._init == "undefined") {
obj.prototype = {
showname : function () {
alert(this.name);
}
};
obj._init = true;
}
}

如上,用_init作为一个标志来判断是否已经给原型创建了方法。如果是那么就不再执行。这样其实在本质上是没有任何变化的,方法仍是通过原型创建,唯一的区别在于这个构造函数看起来“江山统一”了。

本文来源:http://www.gdgbn.com/jiaocheng/27873/