1.获取对象 obj 的所有属性(自有属性和继承属性),保存到数组 lst 中
//获取对象obj的所有属性(自有属性和继承属性),保存到数组lst 中 var lst = []; function getAllAttrs(obj){ var arr = Object.getOwnPropertyNames(obj); for(r in arr){ lst.push(arr[r]); } if(obj.__proto__ !== null){ obj = obj.__proto__; getAllAttrs(obj); } } getAllAttrs(obj); console.log(lst);
2.实现一个完整的复数类
//实现一个完整的复数类: Complex //定义构造函数 function Complex(real, imaginary){ if(isNaN(real) || isNaN(imaginary)) throw TypeError(); this.r = real; this.i = imaginary; }; // 定义非静态方法 Complex.prototype.add = function(that){ return new Complex(this.r+that.r,this.i+that.i); }; Complex.prototype.mui = function(that){ return new Complex(this.r*that.r-this.i*that.i,this.r*that.r+this.i*that.i); }; //取模运算 Complex.prototype.mag = function(){ return Math.sqrt(this.r*this.r+this.i*this.i); }; Complex.prototype.neg = function(){ return new Complex(-this.r,-this.i); }; Complex.prototype.toString = function(){ return "{"+this.r+", "+this.i+"}"; }; Complex.prototype.equals = function(that){ return that != null && that.constructor === Complex && this.r === that.r && this.i === that.i; }; //定义类静态属性 Complex.ZERO = new Complex(0,0); Complex.ONE = new Complex(1,0); Complex.I = new Complex(0,1); //定义类静态方法 Complex.parse = function(s){ try{ var m = Complex._format.exec(s); return new Complex(parseFloat(m[1]),parseFloat(m[2])); }catch(x){ throw new TypeError("Can't parse "+s+" as a complex number."); } }; //静态类属性 Complex._format = /^{([^,]+),([^}]+)}$/; //使用 var c = new Complex(2,3); var d = new Complex(c.i,c.r); console.log(c.add(d).toString()); // {5, 5} console.log(Complex.parse(c.toString())); // Complex {r: 2, i: 3} console.log(Complex.parse(c.toString()).add(c.neg()).equals(Complex.ZERO)); // true
3.判断鸭辩型
//判断鸭辩型 //如果 o 实现了除第一个参数之外的参数所表示的同名方法, 则返回true function quacks3(o){ for(var i=1;i<arguments.length;++i){//遍历o之后的所有参数 var arg = arguments[i]; switch(typeof arg){ case 'string': // 参数为string直接用名字检查 if(typeof o[arg] !== "function") return false; continue; case 'function': // 参数为函数, 视为构造函数, 检查函数的原型对象上的方法 arg = arg.prototype; //进入下一个case case 'object': for(var m in arg){ //遍历对象的每个属性 if(typeof arg[m] !== 'function') //跳过不是方法的属性 continue; if(typeof o[m] !== 'function') return false; } } } return true; } //说明: 只检测函数名,而不用管细节, 不是强制的API,因此满足鸭辩型的本质, 灵活 //限制: 不能用于内置类, 因为for/in不能遍历不可枚举的方法. 在ES5中可以使用Object.getOwnPropertyNames() function quacks5(o){ for(var i=1;i<arguments.length;++i){ var arg = arguments[i]; switch(typeof arg){ case 'string': if(typeof o[arg] !== 'function') return false; continue; case 'function': arg = arg.prototype; case 'object': var props = Object.getOwnPropertyNames(arg.__proto__); var props2 = Object.getOwnPropertyNames(arg); for(var prop in props2){ props.push(props2[prop]); } for(var m in props){ if(props[m] !== 'function') continue; if(o[m] !== 'function') return false; } } } return true; };
4.合并多个对象属性
// 将变长参数sources对象的可枚举(for/in)属性合并到target中,并返回target // target 的值是被修改的, 深拷贝(递归合并) // 合并从左到右进行, 同名属性保持和左边一样(除非属性是空对象) function myextend(target /*...sources*/){ if(!arguments.length) return undefined; if(arguments.length === 1) return target; for(var i=1;i<arguments.length;++i){ var source = arguments[i]; for(var prop in source){ if(target.hasOwnProperty(prop) && target[prop] !== undefined && target[prop] != {}) // 目标对象上该属性存在且属性值不为undefined(可以为null)且不为空对象 continue; if(typeof source[prop] === 'object'){ target[prop] = {}; target[prop] = myextend({},source[prop]); }else{ target[prop] = source[prop]; } } } return target; }
测试:
// 结果在chrome console中查看 var target = { t1:1, t2:{ t1:1, t2:{ t1:1, t2:"t2" } } }; var source1 = { s1:2, s2:{ s1:2, s2:{ s1:2, s2:"s2" } } }; var source2 = { r1:3, r2:{ r1:3, s2:{ r1:3, r2:"s2" } } }; var t = myextend(target,source1,source2); console.log(t);
5.为对象添加一个id属性
(function(){ Object.defineProperty(Object.prototype,"objectId",{ get: idGetter, enumerable: false, configurable: false }); function idGetter(){ if(!(idprop in this)){ if(!Object.isExtensible(this)) throw Error("Can't define id for nonextensible objects"); Object.defineProperty(this,idprop,{ value: nextid++, writable: false, enumerable: false, configurable: false }); return this[idprop]; } } var idprop = "|***objectId*|"; var nextid = 1; })(); var obj = {}; console.log(obj.objectId); // 1
6.让函数既可以当成构造函数,也可以当成工厂方法调用
// 既可以当成构造函数用, 也可以当成工厂方法来用 function Range(from, to){ var props = { from:{value:from,enumerable:true,writable:false,configurable:false}, to:{value:to,enumerable:true,writable:false,configurable:false} }; if(this instanceof Range){ // 如果作为构造函数来调用的话 Object.defineProperties(this,props); }else{ // 否则当成作为工厂方法来调用 return Object.create(Range.prototype,props); } }
持续更新中...
参考
1. <<JavaScript权威指南: 第6版>>