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
实例---------类的几种写法
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();
继承的几种写法
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
max 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.
//最近实践
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 、代码风格也比较紧凑
最佳实践
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类型的属性和方法如下:
- 构造函数:Object()
- hasOwnProperty(PropertyName):检查给定的属性是否在当前的对象实例中,注:PropertyName必须以字符串给定
- isPrototypeOf(object):检查传递的对象,是否是另一个对象的原型。注:这里牵扯到原型和原型链,所以以后具体在讲,目前大家先知道有这么个方法
- propertyIsEnumerable(PropertyName):检查给定的属性是否能用for-in 语句来枚举。注:PropertyName必须以字符串给定
- toLocaleString():返回的字符串与执行环境的地区对应
- toString():返回字符串
- 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:访问属性推荐使用点表示法,除非没办法用点表示法的时候选择用方括号访问