1.json转字符串

介绍

复制代码 代码如下:

本文介绍的四种代码复用模式都是最佳实践,推荐大家在编程的过程中使用。

function json2str(o) {
    var arr = [];
    var fmt = function (s) {
        if (typeof s == ‘object’ && s != null) return json2str(s);
        return /^(string|number)$/.test(typeof s) ? “‘” + s + “‘” : s;
    };
    for (var i in o) arr.push(“‘” + i + “‘:” + fmt(o[i]));
    return ‘{‘ + arr.join(‘,’) + ‘}’;
}

模式1:原型继承

2.时间戳转为Date

原型继承是让父对象作为子对象的原型,从而达到继承的目的:

复制代码 代码如下:

复制代码 代码如下:

function fromUnixTime(timeStamp) {
    if (!timeStamp || timeStamp < 1000 || timeStamp == ‘ ‘) return
“”;
    var theDate = new Date(parseInt(timeStamp) * 1000);
    return theDate;
}

function object(o) {
    function F() {
    }

3.Data-format

    F.prototype = o;
    return new F();
}

复制代码 代码如下:

// 要继承的父对象
var parent = {
    name: “Papa”
};

// 作者: meizz 
// 对Date的扩展,将 Date 转化为指定格式的String  
// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2
个占位符,  
// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3
位的数字)  
// 例子:  
// (new Date()).Format(“yyyy-MM-dd hh:mm:ss.S”) ==> 2012-12-02
08:12:04.423  
// (new Date()).Format(“yyyy-M-d h:m:s.S”)      ==> 2012-12-02
8:12:4.18  
Date.prototype.Format = function(fmt) { 
    var o = {
        “M+”: this.getMonth() + 1,                 //月份  
        “d+”: this.getDate(),                    //日  
        “h+”: this.getHours(),                   //小时  
        “m+”: this.getMinutes(),                 //分  
        “s+”: this.getSeconds(),                 //秒  
        “q+”: Math.floor((this.getMonth() + 3) / 3), //季度  
        “S”: this.getMilliseconds()             //毫秒  
    };
    if (/(y+)/.test(fmt))
        fmt = fmt.replace(RegExp.$1, (this.getFullYear() + “”).substr(4

// 新对象
var child = object(parent);

  • RegExp.$1.length));
        for (var k in o)
            if (new RegExp(“(” + k + “)”).test(fmt))
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ?
    (o[k]) : ((“00” + o[k]).substr((“” + o[k]).length)));
        return fmt;
    };

// 测试
console.log(child.name); // “Papa”

4.日期上增加n天

// 父构造函数
function Person() {
    // an “own” property
    this.name = “Adam”;
}
// 给原型添加新属性
Person.prototype.getName = function () {
    return this.name;
};
// 创建新person
var papa = new Person();
// 继承
var kid = object(papa);
console.log(kid.getName()); // “Adam”

复制代码 代码如下:

// 父构造函数
function Person() {
    // an “own” property
    this.name = “Adam”;
}
// 给原型添加新属性
Person.prototype.getName = function () {
    return this.name;
};
// 继承
var kid = object(Person.prototype);
console.log(typeof kid.getName); // “function”,因为是在原型里定义的
console.log(typeof kid.name); // “undefined”, 因为只继承了原型

function addDay(number) {
        return fromUnixTime(new Date().getTime() / 1000 + 24 * 60 * 60
* number);
}

同时,ECMAScript5也提供了类似的一个方法叫做Object.create用于继承对象,用法如下:

  1. 使用 iframe 时,父窗体与子窗体之间的相互调用

复制代码 代码如下:

复制代码 代码如下:

/* 使用新版的ECMAScript 5提供的功能 */
var child = Object.create(parent);

// 父窗体调用子窗体内的函数 
window.frames[‘ifm_id’].valueChange(“id_101”); 
// 子窗体调用父窗体的函数 
parent.refreshTree(“nodeId_202”); 

var child = Object.create(parent, {
    age: { value: 2} // ECMA5 descriptor
});
console.log(child.hasOwnProperty(“age”)); // true

  1. 弹出窗体与返回值

而且,也可以更细粒度地在第二个参数上定义属性:

复制代码 代码如下:

复制代码 代码如下:

// 弹出窗体 
var url = “”; 
win=window.showModalDialog(url,window,”dialogLeft:400;dialogTop:200;dialogWidth:560px;dialogHeight:380px;scroll:yes;menubar:no;toolbar:no;status:no;”); 
// 在弹出窗体中设置返回值 
var result = new Array(); 
result[0] = “id_101”; 
result[1] = “name_202”; 
window.returnValue = result; 
window.close(); 

// 首先,定义一个新对象man
var man = Object.create(null);

  1. javascript
    作用域[只有全局作用域和函数作用域,javascript没有块作用域]

// 接着,创建包含属性的配置设置
// 属性设置为可写,可枚举,可配置
var config = {
    writable: true,
    enumerable: true,
    configurable: true
};

复制代码 代码如下:

// 通常使用Object.defineProperty()来添加新属性(ECMAScript5支持)
// 现在,为了方便,我们自定义一个封装函数
var defineProp = function (obj, key, value) {
    config.value = value;
    Object.defineProperty(obj, key, config);
}

// 1. 全局作用域 
var id = “global variable”;    // 1.1 在函数外部定义的变量 
function showMsg(){     
    message = “global message”;// 1.2 未定义而直接赋值的变量 
                               //     在第一次使用时被定义为全局变量 

// 2. 函数作用域 
function doCheck(){ 
    var data = “function data”;// 2.1 在函数内部定义的变量 

defineProp(man, ‘car’, ‘Delorean’);
defineProp(man, ‘dob’, ‘1981’);
defineProp(man, ‘beard’, false);

  1. javascript 继承机制

所以,继承就这么可以做了:

复制代码 代码如下:

复制代码 代码如下:

// 1. 对象冒充继承 
function Person(strName){ 
    // private fields 
    var name = strName; 
    // public methods 
    this.getName = function(){ 
        return name; 
    };     

function Student(strName,strSchool){ 
    // 定义父类的属性及方法     
    this.parent = Person; 
    this.parent(strName); 
    delete this.parent;        // 删除临时变量 parent 
    // 定义新属性及方法     
    // private fields 
    var school = strSchool; 
    // public methods 
    this.getSchool = function(){ 
        return school; 
    };      

// 2. Funtion 对象的 call(..) 或 apply(..) 继承 
//    call 和 apply 的区别在于: 
//      call  的第二个参数为可变参数; 
//      apply 的第二个参数为 Array; 
function Animal(strName,intAge){ 
    // private fields 
    var name = strName; 
    var age = intAge; 
    // public methods 
    this.getName = function(){ 
        return name; 
    };  
    this.getAge = function(){ 
        return age; 
    }; 

function Cat(strName,intAge,strColor){ 
    // 定义父类的属性及方法     
    Animal.call(this,strName,intAge); 
    // Animal.apply(this,new Array(strName,intAge)); 
    // 定义新属性及方法     
    // private fields 
    var color = strColor; 
    // public methods 
    this.getInfo = function(){ 
        return “name:” + this.getName() + “\n” 
             + “age:” + this.getAge() + “\n” 
             + “color:” + color; 
    }; 

// 3. prototype 继承 
//    prototype 声明的属性及方法被所有对象共享 
//    prototype 只有在读属性的时候会用到 
Function.prototype.extend = function(superClass){ 
    // 此处的 F 是为了避免子类访问父类中的属性 this.xxx 
    function F(){}; 
永利开户送38元体验金,    F.prototype = superClass.prototype; 
    // 父类构造函数 
    this.superConstructor = superClass; 
    this.superClass = superClass.prototype; 
    this.prototype = new F(); 
    this.prototype.constructor = this; 
}; 
Function.prototype.mixin = function(props){     
    for (var p in props){         
        this.prototype[p] = props[p];         
    } 
}; 
function Box(){} 
Box.prototype = {     
    getText : function(){ 
        return this.text; 
    }, 
    setText : function(text){ 
        this.text = text; 
    } 
}; 
function CheckBox(){} 
CheckBox.extend(Box); 
CheckBox.mixin({ 
    isChecked : function(){ 
        return this.checked; 
    }, 
    setChecked : function(checked){ 
        this.checked = checked; 
    } 
}); 

var driver = Object.create( man );
defineProp (driver, ‘topSpeed’, ‘100mph’);
driver.topSpeed // 100mph

  1. call , apply & bind

但是有个地方需要注意,就是Object.create(null)创建的对象的原型为undefined,也就是没有toString和valueOf方法,所以alert(man);的时候会出错,但alert(man.car);是没问题的。

复制代码 代码如下:

模式2:复制所有属性进行继承

// thisArg 表示在 fun 内部时 this 所指示的对象 
// call & apply 将立即执行 fun 并返回结果 
var result = fun.call(thisArg,arg1,…); 
var result = fun.apply(thisArg,[argsArray]); 
// thisArg 表示在 fun 内部时 this 所指示的对象 
// bind 返回的是一个匿名函数 
var tmpfun = fun.bind(thisArg); 
var result = tmpfun(arg1,…); 

这种方式的继承就是将父对象里所有的属性都复制到子对象上,一般子对象可以使用父对象的数据。

复制代码 代码如下:

先来看一个浅拷贝的例子:

<script type=”text/javascript”> 
/**
 * 扩展 Function 的功能
 */ 
Function.prototype.bind = function(obj){ 
    var method = this; 
    var tmpfun = function(){ 
        return method.apply(obj,arguments); 
    }; 
    return tmpfun; 

function Parent(){ 
    this.name = “parent”; 

function Child(){ 
    this.name = “child”; 
    this.getName = function(time){ 
        return time + ” ” + this.name; 
    }; 

var parent = new Parent(); 
var child = new Child(); 
alert(child.getName(1));                // show 1 child 
alert(child.getName.call(parent,2));    // show 2 parent [call & apply
会立即执行] 
var tmpfun = child.getName.bind(parent);// bind 不会立即执行 
alert(tmpfun(3));                       // show 3 parent 
</script> 

复制代码 代码如下:

  1. js “==” Operator

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

复制代码 代码如下:

var dad = { name: “Adam” };
var kid = extend(dad);
console.log(kid.name); // “Adam”

转换规则 
   如果一个操作数是 Boolean 值,则比较之前将其转成数字:false -> 0,
true -> 1; 
  
如果一个操作数是数字,另一操作数是字符串,则比较之前将字符串转成数字; 
  
如果一个操作数是对象,另一操作数是数字或字符串,则比较之前会将对象转为基本类型, 
       引擎会先尝试调用 valueOf(),如果 valueOf() 没有 override
或返回一个对象, 
       则引擎会尝试调用 toString(),如果 toString() 没有 override
或返回一个对象,则抛出异常; 
   如果是两个对象进行比较,则判断它们是否引用同一对象; 
   如果一个操作数是 NaN, == 将返回 false, != 将返回 true; 
   null 和 undefined 与其它值比较将返回 false, 
       但 null == null, undefined == undefined, null == undefined; 
   参与比较时 null 和 undefined 不能转为其它值;   

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

您可能感兴趣的文章:

  • 超实用的JavaScript代码段
    附使用方法
  • Node.js实用代码段之正确拼接Buffer
  • Node.js实用代码段之获取Buffer对象字节长度
  • 超实用的JavaScript表单代码段
  • JavaScript实现倒计时代码段Item1(非常实用)
  • js常用代码段整理
  • js常用代码段收集
  • 一段非常简单的让图片自动切换js代码
  • 一段超强的javascript代码解密方法
  • 极力推荐10个短小实用的JavaScript代码段

代码的最后一行,你可以发现dad和kid的reads是一样的,也就是他们使用的是同一个引用,这也就是浅拷贝带来的问题。

我们再来看一下深拷贝:

复制代码 代码如下:

/* 深拷贝 */
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);
console.log(kid.counts.toString()); // “1,2,3,4”
console.log(dad.counts.toString()); // “1,2,3”

console.log(dad.reads === kid.reads); // false
kid.reads.paper = false;

深拷贝以后,两个值就不相等了,bingo!

模式3:混合(mix-in)

混入就是将一个对象的一个或多个(或全部)属性(或方法)复制到另外一个对象,我们举一个例子:

复制代码 代码如下:

function mix() {
    var arg, prop, child = {};
    for (arg = 0; arg < arguments.length; arg += 1) {
        for (prop in arguments[arg]) {
            if (arguments[arg].hasOwnProperty(prop)) {
                child[prop] = arguments[arg][prop];
            }
        }
    }
    return child;
}

var cake = mix(
                { eggs: 2, large: true },
                { butter: 1, salted: true },
                { flour: ‘3 cups’ },
                { sugar: ‘sure!’ }
                );

console.dir(cake);

mix函数将所传入的所有参数的子属性都复制到child对象里,以便产生一个新对象。

那如何我们只想混入部分属性呢?该个如何做?其实我们可以使用多余的参数来定义需要混入的属性,例如mix(child,parent,method1,method2)这样就可以只将parent里的method1和method2混入到child里。上代码:

复制代码 代码如下:

// Car
var Car = function (settings) {
    this.model = settings.model || ‘no model provided’;
    this.colour = settings.colour || ‘no colour provided’;
};

// Mixin
var Mixin = function () { };
Mixin.prototype = {
    driveForward: function () {
        console.log(‘drive forward’);
    },
    driveBackward: function () {
        console.log(‘drive backward’);
    }
};

//
定义的2个参数分别是被混入的对象(reciving)和从哪里混入的对象(giving)
function augment(receivingObj, givingObj) {
    // 如果提供了指定的方法名称的话,也就是参数多余3个
    if (arguments[2]) {
        for (var i = 2, len = arguments.length; i < len; i++) {
            receivingObj.prototype[arguments[i]] =
givingObj.prototype[arguments[i]];
        }
    }
    // 如果不指定第3个参数,或者更多参数,就混入所有的方法
    else {
        for (var methodName in givingObj.prototype) {
            //
检查receiving对象内部不包含要混入的名字,如何包含就不混入了
            if (!receivingObj.prototype[methodName]) {
                receivingObj.prototype[methodName] =
givingObj.prototype[methodName];
            }
        }
    }
}

// 给Car混入属性,但是值混入’driveForward’ 和 ‘driveBackward’*/
augment(Car, Mixin, ‘driveForward’, ‘driveBackward’);

// 创建新对象Car
var vehicle = new Car({ model: ‘Ford Escort’, colour: ‘blue’ });

// 测试是否成功得到混入的方法
vehicle.driveForward();
vehicle.driveBackward();

该方法使用起来就比较灵活了。

模式4:借用方法

一个对象借用另外一个对象的一个或两个方法,而这两个对象之间不会有什么直接联系。不用多解释,直接用代码解释吧:

复制代码 代码如下:

var one = {
    name: ‘object’,
    say: function (greet) {
        return greet + ‘, ‘ + this.name;
    }
};

// 测试
console.log(one.say(‘hi’)); // “hi, object”

var two = {
    name: ‘another object’
};

console.log(one.say.apply(two, [‘hello’])); // “hello, another object”

// 将say赋值给一个变量,this将指向到全局变量
var say = one.say;
console.log(say(‘hoho’)); // “hoho, undefined”

// 传入一个回调函数callback
var yetanother = {
    name: ‘Yet another object’,
    method: function (callback) {
        return callback(‘Hola’);
    }
};
console.log(yetanother.method(one.say)); // “Holla, undefined”

function bind(o, m) {
    return function () {
        return m.apply(o, [].slice.call(arguments));
    };
}

var twosay = bind(two, one.say);
console.log(twosay(‘yo’)); // “yo, another object”

// ECMAScript
5给Function.prototype添加了一个bind()方法,以便很容易使用apply()和call()。

if (typeof Function.prototype.bind === ‘undefined’) {
    Function.prototype.bind = function (thisArg) {
        var fn = this,
slice = Array.prototype.slice,
args = slice.call(arguments, 1);
        return function () {
            return fn.apply(thisArg,
args.concat(slice.call(arguments)));
        };
    };
}

var twosay2 = one.say.bind(two);
console.log(twosay2(‘Bonjour’)); // “Bonjour, another object”

var twosay3 = one.say.bind(two, ‘Enchanté’);
console.log(twosay3()); // “Enchanté, another object”

总结

就不用总结了吧。

您可能感兴趣的文章:

  • 深入理解JavaScript系列(45):代码复用模式(避免篇)详解
  • 简单谈谈javascript代码复用模式
  • JavaScript代码复用模式详解
  • JavaScript代码复用模式实例分析

相关文章