javascript模式及javascript学习终极篇

 activeElement属性 焦点元素

代码检测工具http://www.jslint.com/#JSLINT_OPTIONS

 ECMAScript 5 http://www.cnblogs.com/aaa6818162/archive/2012/09/09/2677280.html

  javascript性能比较   http://www.cnblogs.com/aaa6818162/archive/2012/09/12/2681236.html

 javascript 杂谈之哪种写法你更喜欢? http://www.cnblogs.com/aaa6818162/archive/2012/06/04/2534835.html

分享15款很棒的 JavaScript 开发工具  http://www.cnblogs.com/aaa6818162/archive/2011/07/19/2110157.html

 

 

实例---------类的几种写法

 

//几种类的写法
如果想定义OMS.prdgird.DD 必须构造三次检查,每次检查都针对定义的一个对象或者属性。


var OMS = OMS || {};
//静态方法 如果存在一个命名空间,便不会重新创建它。
OMS.namespace = function (ns_string) {
    var parts = ns_string.split('.'),
         parent = OMS,
         i;

    if (parts[0] === "OMS") {
        parts = parts.slice(1);
    }
    for (i = 0; i < parts.length; i += 1) {
        if (typeof parent[parts[i]] === "undefined") {
            parent[parts[i]] = {};
        }
        parent = parent[parts[i]];
    }
    return parent;
};


OMS.namespace("OMS.prdgird");

//构造函数
OMS.prdgird = function (gridid) {
    this.girdid = gridid;
    var msg = "sss"; //私有属性
}
//原型方法
OMS.prdgird.prototype = {
    addRow: function () {
        alert("addRow" + this.girdid);
    },
    delRow: function () {
        alert("delRow" + this.girdid);
    }
}

OMS.namespace("OMS.prdgird.salemark");
OMS.prdgird.salemark = function () {

}
OMS.prdgird.salemark.prototype = {
    show: function () { alert("show"); }
}



//改进写法
OMS.namespace("OMS.paygird");
OMS.paygird = (function () {

    //构造函数
    var myclass = function () { };


    //静态方法
    myclass.staticMethod = function () {
        alert("staticMethod");
    }

    //普通方法
    myclass.prototype = {
        addRow: function () {
            alert("addRow");
        },
        delRow: function () {
            alert("delRow");
        }
    }

    return myclass;
} ());


//类的普通实现
var prdgird = new OMS.prdgird();
prdgird.girdid = "ffffffffffffff";
prdgird.addRow();

var salemark = new OMS.prdgird.salemark();
salemark.show();

var paygird = new OMS.paygird();
paygird.addRow();
OMS.paygird.staticMethod();

 

 继承的几种写法

 

/// <reference path="jquery-easyui-1.2.5/jquery-1.7.1.min.js" />


var OMS = OMS || {};
//静态方法
OMS.namespace = function (ns_string) {
    var parts = ns_string.split('.'),
         parent = OMS,
         i;

    if (parts[0] === "OMS") {
        parts = parts.slice(1);
    }
    for (i = 0; i < parts.length; i += 1) {
        if (typeof parent[parts[i]] === "undefined") {
            parent[parts[i]] = {};
        }
        parent = parent[parts[i]];
    }
    return parent;
};


//改进写法1
OMS.namespace("OMS.paygird");
OMS.paygird = (function () {

    //构造函数
    var myclass = function () {

        this.method = function () {
            alert("method");
        };
    };


    //静态方法
    myclass.staticMethod = function () {
        alert("staticMethod");
    }

    //普通方法
    myclass.prototype = {
        addRow: function () {
            alert("addRow");
        },
        delRow: function () {
            alert("delRow");
        }
    }

    return myclass;
} ());


//继承1
var inherit = (function () {
    var F = function () { };
    return function (C, P) {
        F.prototype = P.prototype;
        C.prototype = new F();
        C.uber = P.prototype;
        C.prototype.constructor = C;
    }
} ());
var child = function () { };
inherit(child, OMS.paygird); //继承 只继承prototype下的方法
new child().addRow(); //成功
new child().method(); //错误
child.staticMethod(); //错误


//继承2
var child = function () {
    OMS.paygird.call(this);//继承this下的方法
};
inherit(child, OMS.paygird); //继承 只继承prototype下的方法
new child().addRow(); //成功
new child().method(); //成功
child.staticMethod(); //错误

//继承3
var child = $.extend(new OMS.paygird(), {});
child.addRow(); //成功
child.method(); //成功
child.staticMethod();//失败

//继承4 最佳吧感觉借助jquery的extend
var child = $.extend(OMS.paygird, {});
new child().addRow()//成功
new child().method(); //成功
child.staticMethod();//成功

//继承5
var parent = new OMS.paygird(); 
var child = Object(parent);
child.addRow()//成功
child.method(); //成功
child.staticMethod(); //失败

////继承6 这个功能都实现了不知道好不好
var child = Object(OMS.paygird);
new child().addRow()//成功
new child().method(); //成功
child.staticMethod(); //成功

 

 

 

一、javascript基本技巧

1.尽量少用全局变量

 

2.变量释放时的副作用

隐藏全局变量与明确定义的全局变量有细微的不同,不同之处在于能否使用delete操作符撤销变量。

1)使用var创建的全局变量不能删除。

2)不使用var创建的隐含全局变量可以删除。

 

3.单一var模式

如下:

        function func() {
            var a = 1,
                b = 2,
                sum = a + b,
                i,
                j;
        }


 

 4.for循环

        function looper() {
            var i = 0,
                max,
                myarray = [];
            for (i = 0, max = myarray.length; i < max; i++) {

            }
        }

 

 5.for-in循环

// the object
var man = {
    hands: 2,
    legs: 2,
    heads: 1
};
// somewhere else in the code
// a method was added to all objects
if (typeof  Object.prototype.clone === "undefined") {
    Object.prototype.clone = function () {};
}

 

for (var i in man) {
    if (man.hasOwnProperty(i)) { // filter
        console.log(i, ":", man[i]);
    }
}
/*
result in the console
hands : 2
legs : 2
heads : 1
*/
// 2.
// antipattern:
// for-in loop without checking hasOwnProperty()
for (var i in man) {
    console.log(i, ":", man[i]);
}
/*
result in the console
hands : 2
legs : 2
heads : 1
clone: function()
*/

 

6.不要增加内置的原型

        if (typeof Object.prototype.myMethod !== "function") {
            Object.prototype.myMethod = function () {

            };
        }

 

7.避免使用隐式类型转换

在使用比较语句的时候使用===和!===操作

 

8.避免使用eval()

 

 二、构造函数

1.强者使用new的模式 避免忘记使用new所带来的问题

        function A() {
            var that = {};
            that.Method = function () {
            };
            return that;
        }

 

2.自调用构造函数

 

        function A() {
            if (!(this instanceof A)) {
                return new A();
            }

            //或 在ES5的严格模式中并不支持rguments.callee属性
            //if (!(this instanceof arguments.callee)) {
            //  return new arguments.callee();
            // }

            var that = {};
            that.Method = function () {
            };
            return that;
        }

 

3.

 

 

三、函数
1.回调模式

 


 //回调函数
        var obj = function () {
            this.name = "liww";
            obj.prototype.Mehthod = function () {
                alert(this.name);
            }
        }

        var findNodes = function (callback) {
            if (typeof callback === "function") {
                callback();
            }
        };
        var ser = new obj();
        findNodes(ser.Mehthod); //得不到name 因为this指向了findNodes

        ////////////////////////////////////////////////////////////////////////////////////////
        //正确的方式是传递回调函数并且传递回调函数所属的对象
        var findNodes = function (callback, callback_obj) {
            if (typeof callback === "function") {
                callback.call(callback_obj);
            }
        };
        var ser = new obj();
        findNodes(ser.Mehthod, ser);

        //////////////////////////////////////////////////////////////////////////////////////////

        //带动态参数的回调
        var obj = function () {
            this.name = "liww";
            obj.prototype.Mehthod = function (time1, time2) {
                alert(this.name + time1 + time2);
            }
        }

        var findNodes = function (callback, callback_obj, parameter) {
            if (typeof callback === "function") {
                callback.apply(callback_obj, parameter);
            }
        };
        var ser = new obj();
        findNodes(ser.Mehthod, ser, ["2222222", "333333"]); 
 

2.自定义函数

 


 var scareMe = function () {
        alert("Boo!");
        scareMe = function () {
            alert("Double boo!");
        };
    };

    scareMe(); // Boo!
    scareMe(); // Double boo!

    //适用于函数有些初始化工作并只执行一次的情况
    //缺点:当它重新定义本身的时候已经添加到原始函数的任何属性都会丢失
 

 

2.即时函数

 

(fuction(){

alert('watch out');}());

 

3.即时对象初始化

({
// here you can define setting values
//
 a.k.a. configuration constants
maxwidth: 600,
maxheight: 400,
// you can also define utility methods
gimmeMax: function () {
return this.maxwidth + "x" + this.maxheight;
},
// initialize
init: function () {
console.log(this.gimmeMax());
// more init tasks...
}
}).init();

 

4.函数属性--备忘模式

        var myFunc = function (param) {
            if (!myFunc.cache[param]) {
                var result = {};
                // ... expensive operation ...
                myFunc.cache[param] = result;
            }
            return myFunc.cache[param];
        };
        // cache storage
        myFunc.cache = {};

5.配置对象--即传人参数序列化成一个json

         var conf = {
            username: "batman",
            first: "Bruce",
            last: "Wayne"
        };
        addPerson(conf);

6.curry化函数[方法的参数动态]

         function schonfinkelize(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);
            };
        }

 

        // a normal function
        function add(a, b, c, d, e) {
            return a + b + c + d + e;
        }
        // works with any number of arguments
        schonfinkelize(add, 1, 2, 3)(5, 5); // 16
        // two-step currying
        var addOne = schonfinkelize(add, 1);
        addOne(10, 10, 10, 10); // 41
        var addSix = schonfinkeliz

 

 

四、对象创建模式

 1.命名空间

通用命名空间函数

 


var MYAPP = MYAPP || {};
MYAPP.namespace = function (ns_string) {
    var parts = ns_string.split('.'),
        parent = MYAPP,
        i;
    // strip redundant leading global
    if (parts[0] === "MYAPP") {
        parts = parts.slice(1);
    }
    for (i = 0; i < parts.length; i += 1) {
        // create a property if it doesn't exist
        if (typeof parent[parts[i]] === "undefined") {
            parent[parts[i]] = {};
        }

        parent = parent[parts[i]];
    }
    return parent;
};

 // assign returned value to a local var
var module2 = MYAPP.namespace('MYAPP.modules.module2');
module2 === MYAPP.modules.module2; // true
//
 skip initial `MYAPP`
MYAPP.namespace('modules.module51');
// long namespace
MYAPP.namespace('once.upon.a.time.there.was.this.long.nested.property');

 

 2私有属性

私有成员

特权方法:是指那些可以访问私有成员的公共方法。

 

3.揭示模式:将私有方法揭示为公共方法

var myarray;
(function () {
    var astr = "[object Array]",
        toString = Object.prototype.toString;
    function isArray(a) {
        return toString.call(a) === astr;
    }
    function indexOf(haystack, needle) {
        var i = 0,
            max = haystack.length;
        for (; i < max; i += 1) {
            if (haystack[i] === needle) {
                return i;
            }
        }
        return −1;
    }

    myarray = {
        isArray: isArray,
        indexOf: indexOf,
        inArray: indexOf
    };
}());

 

4.模块模式

MYAPP.namespace('MYAPP.utilities.array');
MYAPP.utilities.array = (function () {
        // dependencies
    var uobj  = MYAPP.utilities.object,
        ulang = MYAPP.utilities.lang,
        // private properties
        array_string = "[object Array]",
        ops = Object.prototype.toString;
        // private methods
        // ...
        // end var
    // optionally one-time init procedures
    // ...
    // public API
    return {
        inArray: function (needle, haystack) {
            for (var i = 0, max = haystack.length; i < max; i += 1) {
                if (haystack[i] === needle) 

                    return true;
                }
            }
        },
        isArray: function (a) {
            return ops.call(a) === array_string;
        }
        // ... more methods and properties
    };
}());

 

5.揭示模块模式

MYAPP.utilities.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;
        };
        // end var
    // revealing public API
    return {
        isArray: isArray,
        indexOf: inArray
    };
}());

 

6。创建构造函数的模块

MYAPP.namespace('MYAPP.utilities.Array');
MYAPP.utilities.Array = (function () {
        // dependencies
    var uobj  = MYAPP.utilities.object,
        ulang = MYAPP.utilities.lang,
        // private properties and methods...
        Constr;
        // end var
    // optionally one-time init procedures
    // ...
    // public API -- constructor
    Constr = function (o) {
        this.elements = this.toArray(o);
    };
    // public API -- prototype
    Constr.prototype = {
        constructor: MYAPP.utilities.Array,
        version: "2.0",
        toArray: function (obj) {
            for (var i = 0, a = [], len = obj.length; i < len; i += 1) {
                a[i] = obj[i];
            }
            return a;
        }
    };
    // return the constructor
    // to be assigned to the new namespace
    return Constr;
}());

 

7.沙箱模式

 提供了一个可用于模块运行的环境,且不会对其他模块和个人沙箱造成任何影响。

 function Sandbox() {
        // turning arguments into an array
    var args = Array.prototype.slice.call(arguments),
        // the last argument is the callback
        callback = args.pop(),
        // modules can be passed as an array or as individual parameters
        modules = (args[0] && typeof args[0] === "string") ? args : args[0],
        i;
    // make sure the function is called
    // as a constructor
    if (!(this instanceof Sandbox)) {
        return new Sandbox(modules, callback);
    }
    // add properties to `this` as needed:
    this.a = 1;
    this.b = 2;
    // now add modules to the core `this` object
    // no modules or "*" both mean "use all modules"
    if (!modules || modules === '*') {
        modules = [];
        for (i in Sandbox.modules) {
            if (Sandbox.modules.hasOwnProperty(i)) {
                modules.push(i);
            }
        }
    }
    // initialize the required modules
    for (i = 0; i < modules.length; i += 1) {
        Sandbox.modules[modules[i]](this);
    }
    // call the callback
    callback(this);
}
// any prototype properties as needed
Sandbox.prototype = {
    name: "My Application",
    version: "1.0",
    getName: function () {
        return this.name;
    }
};

 

8.公有静态成员

// constructor
var Gadget = function (price) {
    this.price = price;
};
// 静态方法
Gadget.isShiny = function () {
    // this always works

    var msg = "you bet";
    if (this instanceof Gadget) {
        // this only works if called non-statically
        msg += ", it costs $" + this.price + '!';
    }
    return msg;
};
// 向该原型中添加一个普通方法
Gadget.prototype.isShiny = function () {
    return Gadget.isShiny.call(this);
};
Testing a static method call:
Gadget.isShiny(); // "you bet"
Testing an instance, nonstatic call:
var a = new Gadget('499.99');
a.isShiny(); // "you bet, it costs $499.99!"

 

9.私有静态成员

// 构造函数
var Gadget = (function () {
    // static variable/property
    var counter = 0,
        NewGadget;
    // this will become the
    // new constructor implementation
    NewGadget = function () {
        counter += 1;
    };
    // a privileged method
    NewGadget.prototype.getLastId = function () {
        return counter;
    };
    // overwrite the constructor
    return NewGadget;
}()); // execute immediately
Testing the new implementation:
var iphone = new Gadget();
iphone.getLastId(); // 1
var ipod = new Gadget();
ipod.getLastId();   // 2
var ipad = new Gadget();
ipad.getLastId();   // 3

 

10.对象常量

 

11.链模式

可以使你能够一个接一个的调用对象的方法,而无需将前一个操作返回的值赋给变量,并且无需将你的调用分割成多行。 
var obj = {
    value: 1,
    increment: function () {
        this.value += 1;
        return this;
    },
    add: function (v) {
        this.value += v;
        return this;
    },
    shout: function () {
        alert(this.value);
    }
};
// chain method calls
obj.increment().add(3).shout(); // 5
//
 as opposed to calling them one by one
obj.increment();
obj.add(3);
obj.shout(); // 5
 

 

 实例


 1 var OMS = OMS || {};
 2 OMS.namespace = function (ns_string) {
 3     var parts = ns_string.split('.'),
 4         parent = OMS,
 5         i;
 6 
 7     if (parts[0] === "OMS") {
 8         parts = parts.slice(1);
 9     }
10     for (i = 0; i < parts.length; i += 1) {
11         if (typeof parent[parts[i]] === "undefined") {
12             parent[parts[i]] = {};
13         }
14         parent = parent[parts[i]];
15     }
16     return parent;
17 };
18 
19 OMS.namespace("gird");
20 
21 OMS.gird = function () {
22     var girdId = "datagrid";
23     var toolbarId = "toolbar";
24     this.init = function (girdId, toolbarId) {
25         girdId = girdId;
26         toolbarId = toolbarId;
27     };
28 
29     this.search = function () {
30         var jsonSearch = utility.paramsToJson($("#" + toolbarId + " input,select").fieldSerialize());
31         $("#" + girdId).datagrid("getPager").pagination("options").pageNumber = 1;
32         $("#" + girdId).datagrid('options').queryParams = jsonSearch;
33         $("#" + girdId).datagrid('reload');
34     };
35 
36     this.refurbish = function () {
37         $("#" + toolbarId + " input").clearFields();
38         $("#" + toolbarId + " select").each(
39         function () {
40             $(this).get(0).selectedIndex = 0;
41         }
42         );
43         $("#" + girdId).datagrid("getPager").pagination("options").pageNumber = 1;
44         $("#" + girdId).datagrid('options').queryParams = {};
45         $("#" + girdId).datagrid('reload');
46     };
47 }
 

 

五、代码复用模式

 jQuery框架提供的拷贝功能非常强大,支持简单对象的深拷贝与浅拷贝。但是,它还不是类级的继承,因为它的拷贝只作用于简单对象(如{name:'zcj',age:28})。

1.类式继承模式--默认模式

function inherit(C, P) {
    C.prototype = new P();
}

var kid = new Child();
kid.say(); // "Adam"

 

缺点:同时继承了两个对象的属性,即添加到this的属性以及原型属性

       它并不支持将参数传递到子构造函数中,而子构造函数然后又将参数传递到父构造函数中。

var s = new Child('Seth');
s.say(); // "Adam"

 

2.类式继承模式--借用构造函数

// 父构造函数

function Parent(name) {
    this.name = name || 'Adam';
}
// 向原型添加功能

Parent.prototype.say = function () {
    return this.name;
};
// 子构造函数

function Child(name) {
    Parent.apply(this, arguments);
}
var kid = new Child("Patrick");//kid获得了自身的属性name 但是却从未继承say方法
kid.name; // "Patrick"  
typeof kid.say; // "undefined"

 

这种方式的缺点:只能继承在父构造函数中添加到this的属性。prototype不会被继承。

在高级面向对象语言中,类的存储是很优美的,对类的每个实例来说,其不同的部分就是用于描述其状态的属性,而它们的行为(即方法)都是相同的,所以在运行期只会为每个类实例的属性分配存储空间,方法则是每个类实例所共享的,是不占用存储空间的。

优点:在于可以获得父对象自身成员的真实副本,并且也不会存在子对象意外覆盖父对象属性的风险。

 

3. 类式继承模式--借用和设置原型

// 父构造函数

function Parent(name) {
    this.name = name || 'Adam';
}
// 添加原型方法

Parent.prototype.say = function () {
    return this.name;
Figure 6-5. A CatWings object inspected in Firebug
Classical Pattern #3—Rent and Set Prototype | 123
};
// 子构造函数
function Child(name) {
    Parent.apply(this, arguments);
}
Child.prototype = new Parent();
var kid = new Child("Patrick");
kid.name; // "Patrick"
kid.say(); // "Patrick"
delete kid.name;
kid.say(); // "Adam"

优点:可以继承父对象中的一切东西,同时安全的修改自身的属性。

缺点:父构造函数被调用两次,因此这导致了其效率低下的问题。最后自身的属性会被继承两次。

 

4. 类式继承模式--共享原型

前提 任何值得继承的东西都得放置在原型中实现。所以仅将子对象的原型与父对象的原型设置为相同即可。

function inherit(C, P) {
    C.prototype = P.prototype;
}

 

5.类式继承模式--临时构造函数

 通过断开父对象与子对象的原型之间的直接链接关系,从而解决了共享同一个原型带来的问题。

function inherit(C, P) {
    var F = function () {};
    F.prototype = P.prototype;
    C.prototype = new F();
}

这种模式中,父构造函数添加到this中的任何成员都不会被继承。

 

5.适用于项目中的最佳方法----圣杯模式

 

function inherit(C, P) {
    var F = function () {};
    F.prototype = P.prototype;
    C.prototype = new F();
    C.uber = P.prototype;
    C.prototype.constructor = C;
}

 

var inherit = (function () {
    var F = function () {};
    return function (C, P) {
        F.prototype = P.prototype;
        C.prototype = new F();
        C.uber = P.prototype;
        C.prototype.constructor = C;
    }
}());

 

6.Klass

var klass = function (Parent, props) {
    var Child, F, i;
    // 1.构造函数
    Child = function () {
        if (Child.uber && Child.uber.hasOwnProperty("__construct")) {
            Child.uber.__construct.apply(this, arguments);
        }
        if (Child.prototype.hasOwnProperty("__construct")) {
            Child.prototype.__construct.apply(this, arguments);
        }
    };
    // 2.继承
    Parent = Parent || Object;
Klass | 129
    F = function () {};
    F.prototype = Parent.prototype;
    Child.prototype = new F();
    Child.uber = Parent.prototype;
    Child.prototype.constructor = Child;
    // 3.添加方法
    for (i in props) {
        if (props.hasOwnProperty(i)) {
            Child.prototype[i] = props[i];
        }
    }
    // return the "class"
    return Child;
};

7.原型继承

 

方式1:自身属性和构造函数原型的属性都将被继承

// 父构造函数 
function Person() {
    // an "own" property
    this.name = "Adam";
}
// 添加到原型的属性

Person.prototype.getName = function () {
    return this.name;
};
// 创建一个新的person类对象

var papa = new Person();
// 继承

var kid = object(papa);
// 测试自身属性和原型
kid.getName(); // "Adam

 

方式2:仅继承现有构造函数的原型对象

// 父构造函数
function Person() {
    // an "own" property
    this.name = "Adam";
}
// 添加到原型的属性

Person.prototype.getName = function () {
    return this.name;
};
// 继承
var kid = object(Person.prototype);
typeof kid.getName; // "function", because it was in the prototype
typeof kid.name; // "undefined", because only the prototype was inherited

 

8.通过复制属性实现继承

function extend(parent, child) {
    var i;
    child = child || {};
    for (i in parent) {
        if (parent.hasOwnProperty(i)) {
            child[i] = parent[i];
        }
    }
    return child;
}

 

//浅复制

var dad = {
    counts: [1, 2, 3],
    reads: {paper: true}
};
var kid = extend(dad);
kid.counts.push(4);
dad.counts.toString(); // "1,2,3,4"
dad.reads === kid.reads; // true

 

//深复制

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 dad = {
    counts: [1, 2, 3],
    reads: {paper: true}
};
var kid = extendDeep(dad);
kid.counts.push(4);
kid.counts.toString(); // "1,2,3,4"
dad.counts.toString(); // "1,2,3"
dad.reads === kid.reads; // false
kid.reads.paper = false;

 

5.

 

 

六、设计模式

1.单例模式

var Universe;
(function () {
var instance;
Universe = function Universe() {
if (instance) {
return instance;
}
instance = this;
// all the functionality
this.start_time = 0;
this.bang = "Big";
};
}());

 

2.

 

 

7.类的几种写法

 

    //最近实践

       var Parent = function () {
            this.name = name || 'Adam';
        }

        Parent.prototype = {
            say: function () {
                alert("111");
            },
            hello: function () {
                alert("hello");
            }
        };

 

 

1)构造函数法
/*
 * Person类:定义一个人,有个属性name,和一个getName方法 
 * @param {String} name 
 
*/
function Person(name) { 
    this.name = name; 
    this.getName = function() { 
        return this.name; 
    } 
}  

var p1 = new Person("Jack"); 
var p2 = new Person("Tom"); 
console.log(p1 instanceof Person);//true 
console.log(p2 instanceof Person);//true 
这种方式的优点是:可以根据参数来构造不同的对象实例 ,缺点是构造时每个实例对象都会生成getName方法版本,造成了内存的浪费 。

 2、原型方式
  var Person = function (name) {
            Person.prototype.name = name
            Person.prototype.getName = function () { return this.name; }
        }

        var p1 = new Person("111");
        var p2 = new Person("222");
        alert(p1.getName()); //222 
        alert(p2.getName()); //222 
 

可以看出输出的都是222,原型方式的缺点就是不能通过参数来构造对象实例 (一般每个对象的属性是不相同的) ,优点是所有对象实例都共享getName方法(相对于构造函数方式),没有造成内存浪费 。 

 

3、构造函数+原型
        var Person = function (name) {
            this.name = name;

            if (Person._init == undefined) {
                alert("我只执行一次!");
                Person.prototype.getName = function () {
                    return this.name;
                }
                Person._init = 1;
            }
        }

        var p1 = new Person("Andy"); //第一次new会弹出'我只执行一次!' 
        var p2 = new Person("Lily"); //以后new的对象不会再执行了
        p1.getName(); //Andy
        p2.getName(); //Lily
a 、可以通过传参构造对象实例
b 、对象实例都共享同一份方法不造成内存浪费
c 、代码风格也比较紧凑

 

 

8、继承的几种写法

最佳实践

var inherit = (function () {
    var F = function () {};
    return function (C, P) {
        F.prototype = P.prototype;
        C.prototype = new F();
        C.uber = P.prototype;
        C.prototype.constructor = C;
    }
}());

拷贝组合继承

function extend(subC, baseC) { 
    for (var ptototypeName in baseC.prototype) { 
        if (typeof(subC.prototype[ptototypeName]) === 'undefined') { 
            subC.prototype[ptototypeName] = baseC.prototype[ptototypeName]; //原型属性的拷贝 
        } 
    } 
    subC.prototype.constructor = subC; //增强 

var BaseClass = function() { 
    this.className = "Base"; 
}; 
BaseClass.prototype = { 
    showName: function() { 
        alert(this.className); 
    } 
}; 
var SubClass = function() { 
    BaseClass.call(this); //只执行一次父类构造函数 
    this.classDesc = "SubClass"; 
}; 
SubClass.prototype = { 
    showDesc: function() { 
        alert(this.classDesc); 
    } 
}; 
extend(SubClass, BaseClass); //不破坏子类原型链的位置二

 

/*!
 * jQuery源码分析-extend函数
 * jQuery版本:1.4.2
 * 
 * ----------------------------------------------------------
 * 函数介绍
 * jQuery.extend与jQuery.fn.extend指向同一个函数对象
 * jQuery.extend是jQuery的属性函数(静态方法)
 * jQuery.fn.extend是jQuery函数所构造对象的属性函数(对象方法)
 *
 * ----------------------------------------------------------
 * 使用说明
 * extend函数根据参数和调用者实现功能如下:
 * 1.对象合并:
 * 对象合并不区分调用者,jQuery.extend与jQuery.fn.extend完全一致
 * 也就是说对jQuery对象本身及jQuery所构造的对象没有影响
 * 对象合并根据参数区分,参数中必须包括两个或两个以上对象
 * 如:$.extend({Object}, {Object}) 或 $.extend({Boolean},{Object}, {Object})
 * 对象合并返回最终合并后的对象,支持深度拷贝
 * 
 * 2.为jQuery对象本身增加方法:
 * 这种方式从调用者和参数进行区分
 * 形式为 $.extend({Object})
 * 这种方式等同于 jQuery.{Fnction Name}
 * 
 * 3.原型继承:
 * 原型继承方式可以为jQuery所构造的对象增加方法
 * 这种方式也通过调用者和参数进行区分
 * 形式为 $.fn.extend({Object})
 * 这种方式实际上是将{Object}追加到jQuery.prototype,实现原型继承
 * 
 * ----------------------------------------------------------
 * 
 
*/
 
// jQuery.fn = jQuery.prototype
//
 jQuery.fn.extend = jQuery.prototype.extend
jQuery.extend = jQuery.fn.extend = function(){

    //目标对象
    var target = arguments[0] || {},    
    
    //循环变量,它会在循环时指向需要复制的第一个对象的位置,默认为1
    //如果需要进行深度复制,则它指向的位置为2
    i = 1,    
    
    //实参长度
    length = arguments.length,    
    
    //是否进行深度拷贝
    //深度拷贝情况下,会对对象更深层次的属性对象进行合并和覆盖
    deep = false,    
    
    //用于在复制时记录参数对象
    options,    
    
    //用于在复制时记录对象属性名
    name,    
    
    //用于在复制时记录目标对象的属性值
    src,    
    
    //用于在复制时记录参数对象的属性值
    copy;
    
    //只有当第一个实参为true时,即需要进行深度拷贝时,执行以下分支
    if (typeof target === "boolean") {
        //deep = true,进行深度拷贝
        deep = target;
        
        //进行深度拷贝时目标对象为第二个实参,如果没有则默认为空对象
        target = arguments[1] || {};
        
        //因为有了deep深度复制参数,因此i指向的位置为第二个参数
        i = 2;
    }
    
    //当目标对象不是一个Object且不是一个Function时(函数也是对象,因此使用jQuery.isFunction进行检查)
    if (typeof target !== "object" && !jQuery.isFunction(target)) {
        
        //设置目标为空对象
        target = {};
    }
    
    //如果当前参数中只包含一个{Object}
    //如 $.extend({Object}) 或 $.extend({Boolean}, {Object})
    //则将该对象中的属性拷贝到当前jQuery对象或实例中
    //此情况下deep深度复制仍然有效
    if (length === i) {
        
        //target = this;这句代码是整个extend函数的核心
        //在这里目标对象被更改,这里的this指向调用者
        //在 $.extend()方式中表示jQuery对象本身
        //在 $.fn.extend()方式中表示jQuery函数所构造的对象(即jQuery类的实例)
        target = this;
        
        //自减1,便于在后面的拷贝循环中,可以指向需要复制的对象
        --i;
    }
    
    //循环实参,循环从第1个参数开始,如果是深度复制,则从第2个参数开始
    for (; i < length; i++) {
        
        //当前参数不为null,undefined,0,false,空字符串时
        //options表示当前参数对象
        if ((options = arguments[i]) != null) {
            
            //遍历当前参数对象的属性,属性名记录到name
            for (name in options) {
                
                //src用于记录目标对象中的当前属性值
                src = target[name];
                
                //copy用于记录参数对象中的当前属性值
                copy = options[name];
                
                //存在目标对象本身的引用,构成死循环,结束此次遍历
                if (target === copy) {
                    continue;
                }
                
                //如果需要进行深度拷贝,且copy类型为对象或数组
                if (deep && copy && (jQuery.isPlainObject(copy) || jQuery.isArray(copy))) {
                
                    //如果src类型为对象或数组,则clone记录src
                    //否则colne记录与copy类型一致的空值(空数组或空对象)
                    var clone = src && (jQuery.isPlainObject(src) || jQuery.isArray(src)) ? src : jQuery.isArray(copy) ? [] : {};
                    
                    //对copy迭代深度复制
                    target[name] = jQuery.extend(deep, clone, copy);
                    
                    //如果不需要进行深度拷贝
                } else if (copy !== undefined) {
                    
                    //直接将copy复制给目标对象
                    target[name] = copy;
                }
            }
        }
    }
    
    //返回处理后的目标对象
    return target;
};


/**
 * jQuery框架本身对extend函数的使用非常频繁
 * 典型示例为jQuery.ajax
 * 
 
*/

//使用extend对jQuery对象本身进行扩展,只给了一个参数对象
//
该对象中的属性将被追加到jQuery对象中
jQuery.extend({
 
    //jQuery.ajax
    //$.ajax
 
    //这里的origSettings参数是自定义的ajax配置
    //jQuery对象本身有一个ajaxSettings属性,是默认的ajax配置
    ajax: function(origSettings){ 
 
        //这里使用extend对ajax配置项进行合并
        //第一个参数表示进行深度拷贝
        //首先将第3个参数jQuery.ajaxSettings(即jQuery默认ajax配置)复制到第2个参数(一个空对象)
        //然后将第4个参数(自定义配置)复制到配置对象(覆盖默认配置)
        //这里的s就得到了最终的ajax配置项
        var s = jQuery.extend(true, {}, jQuery.ajaxSettings, origSettings);
  
        //其它相关代码...(省略)
    }
}); 

 

 

附录:

Object类型

Object类型用于创建自定义对象(实例),

var cat= new Object();//推荐
cat.name="sunny";
cat.legs=
4;

 

 

Object类型的属性和方法如下:

  1. 构造函数:Object()
  2. hasOwnProperty(PropertyName):检查给的属性是否在当前的对象实例中,注:PropertyName必须以字符串给定
  3. isPrototypeOf(object):检查传递的对象,是否是另一个对象的原型。注:这里牵扯到原型和原型链,所以以后具体在讲,目前大家先知道有这么个方法
  4. propertyIsEnumerable(PropertyName):检查给定的属性是否能用for-in 语句来枚举。注:PropertyName必须以字符串给定
  5. toLocaleString():返回的字符串与执行环境的地区对应
  6. toString():返回字符串
  7. valueOf():返回对象的字符串、数值或布尔值表示
    
    
    复制代码
    var cat={
           name:"sunny",
           legs:4
    };
    
    alert('cat.hasOwnProperty("name"):'+cat.hasOwnProperty("name")+"\r\n"+
    'cat.hasOwnProperty("age"):'+cat.hasOwnProperty("age")+"\r\n"+
    'cat.propertyIsEnumerable("name"):'+cat.propertyIsEnumerable("name")+"\r\n"+
    'cat.toLocaleString():'+cat.toLocaleString()+"\r\n"+
    'cat.toString():'+cat.toString()+"\r\n"+
    'cat.toLocaleString():'+cat.toLocaleString()+"\r\n"+
    'cat.valueOf():'+cat.valueOf());

 

对象属性的访问方法

     1. 点表示法  cat.name

     2. 方括号表示法:cat["name"]

      注1:方括号访问的优点是:

 A. 可以通过变量来访问属性    

var  pName="name";
alert(cat[pName]);

B. 如果属性名中包含会导致语法错误的字符,或者属性名使用的是关键字或保留字,也可以用方括号表示法。

  cat["lovely brother"]="Tom"; 属性名中包含空格所以不能使用点表示法访问它

注2:访问属性推荐使用点表示法,除非没办法用点表示法的时候选择用方括号访问

posted @ 2012-08-19 13:47  awp110  阅读(447)  评论(0编辑  收藏  举报