JavaScript 代码小片段

  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版>>

 

posted @ 2015-12-19 16:41  roger9567  阅读(183)  评论(0编辑  收藏  举报