zoukankan      html  css  js  c++  java
  • Prototype源码浅析——Object部分(一)

    前些天小小的分析了一下Prototype的Function部分,今天开始Prototype的Object这一部分
    开始需要说明的一点是,Object这部分与先前的Function那一部分有点不一样,这次Object是直接扩展在Object上面的,而非Object.prototype,两者是有本质区别的,也就是本次Obeject的扩展相当于添加Object的一个静态变量(方法);

    extend(Object, {})
    Object.extend(Function.prototype,{})

    Object的方法比较多,有些是很基础的(比如类型判断),所以也就不想全部都分析了,只拣几个我觉得比较重要或者难以理解的说一下:

      extend(Object, {
    extend: extend,
    inspect: inspect,
    toJSON: NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON,
    toQueryString: toQueryString,
    toHTML: toHTML,
    keys: Object.keys || keys,
    values: values,
    clone: clone,
    isElement: isElement,
    isArray: isArray,
    isHash: isHash,
    isFunction: isFunction,
    isString: isString,
    isNumber: isNumber,
    isDate: isDate,
    isUndefined: isUndefined
    });

    第一个比较重要的是extend方法,这个方法很多书上面都有,而且基本都差不多,就是复制属性的一个方法。

    后面(包括Function.prototype)的属性添加大都是用这个方法来进行的。

    一个实例:

    现在有两个对象:

        var obj_1 = {
    name : 'xesam'
    };
    var obj_2 = {
    age : '24',
    name: 'xesam_1'
    };

    现在我想把这两个对象的属性合并到一个对象里面
    实现方法有两种:
    第一,新建一个空对象,然后把两者都拷贝进去(这个在Prototype里面对应的是clone方法,不过clone是需要一个对象就行)
    第二,把obj_2的属性拷贝到obj_1里面去
    其实上面两种方法其实没有必要分得那么清楚,因为对应的方法都是一样的。
    如果不考虑深层拷贝和重复属性,那么实现是很简单的,比如:

        (function(){
    return;
    var obj_1 = {
    name : 'xesam'
    };
    var obj_2 = {
    age : '24',
    name: 'xesam_1'
    };
    function extend(destination, source) {
    for (var property in source){
    destination[property] = source[property];
    }
    return destination;
    }
    extend(obj_1,obj_2);
    console.log(obj_1);//name变成xesam_1
    })();

    如果你去看一下Prototype的源码,你会发现这货还真是这么做的,相比jquery的实现,简直就是弱爆了。


    抛开Prototype的应用环境与这么做的目的不说,这种实现如果被用在平常的使用中,会碰到的问题就是,
    第一、如果有两个相同的属性怎么处理?
    第二、in操作在不同浏览器的实现中返回的结果可能并不一致

    按照上面的实现,source中的属性会覆盖destination中的同名属性。如果这并非我们本意,那么我们稍微改一下代码就可以:

        (function(){
    return;
    var obj_1 = {
    name : 'xesam'
    };
    var obj_2 = {
    age : '24',
    name: 'xesam_1'
    };
    function extend(destination, source) {
    for (var property in source){
    if(destination.hasOwnProperty[property]){
    destination[property] = source[property];
    }
    }
    return destination;
    }
    extend(obj_1,obj_2);
    console.log(obj_1);//name还是xesam
    })();

    因此我们可以再添加一个参数overwrite来实现更灵活的配置,顺便复习一下Function部分的wrap方法

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>

    </head>
    <body>
    <script type="text/javascript">
    Function.prototype.bind = function(context) {
    var __method = this, args = Array.prototype.slice.call(arguments, 1);
    return function() {
    var b = args.concat(Array.prototype.slice.call(arguments, 0));
    return __method.apply(context, b);
    }
    }
    Function.prototype.wrap =function(wrapper){
    var _this = this;
    return function(){
    var params = [_this.bind(this)].concat(Array.prototype.slice.call(arguments, 0));
    wrapper.apply(this, params);
    }
    }
    function extend(destination, source,overwrite) {
    for (var property in source){
    if(overwrite){
    destination[property] = source[property];
    }else if(destination.hasOwnProperty[property]){
    destination[property] = source[property];
    }
    }
    return destination;
    }
    Object.prototype.extend = extend.wrap(function(process,source,overwrite){
    if(overwrite || false){
    process(this,source,true);
    }else{
    process(this,source,false);
    }
    });
    (function(){
    var obj_1 = {
    name : 'xesam'
    };
    var obj_2 = {
    age : '24',
    name: 'xesam_1'
    };
    obj_1.extend(obj_2);//没有重写obj_1的name
    console.log(obj_1);
    })();
    (function(){
    var obj_1 = {
    name : 'xesam'
    };
    var obj_2 = {
    age : '24',
    name: 'xesam_1'
    };
    obj_1.extend(obj_2,true);//重写了obj_1的name
    console.log(obj_1);
    })();
    </script>
    </body>
    </html>

    【说明:这样的调用方法根本没有必要,纯粹是为了熟悉一下wrap方法而已】

    这里我们调用obj_1.extend(obj_2,true);的时候,会一并拷贝我们新添加的extend方法。

    因为extend是我们自定义的,所以都会被in操作枚举出来,下面的第二个问题就和这个自定义的属性有关。

    另外一个问题就是in操作在某些IE6下的实现问题。

    假设有下列情况,如果我们在某一source对象中重写了类似toString()这类原型中不可枚举的属性,那么在正常情况下,用in操作符是可以获取重写后的toString的(就像上例我们添加的extend一样),但是IE6在这种情况下是继续屏蔽toString的,所以取不到这个值
    看下面的例子:

        (function(){
    return;
    var obj_1 = {
    name : 'xesam'
    };
    var obj_2 = {
    age : '24',
    toString:function(){return ('my toString');}
    };
    function extend(destination, source) {
    for (var property in source){
    destination[property] = source[property];
    }
    return destination;
    }
    extend(obj_1,obj_2);
    alert(obj_1.toString());
    })();

    正常情况下,因该是弹出对话框“my toString”,但是在IE6由于obj_1并没有获得这个重写,还是调用了原来Object本身的toString方法,因此弹出对话框为“object Object”。

    因此如果想更通用的话,还得事先检测一下这个兼容性的问题,一个参考代码:

        (function(){
    var DontEnum = (function (){ //(1)先检测是否有屏蔽自定义属性的问题
    var o = {toString:''}
    for(var i in o){
    return true;
    }
    return false;
    })();
    var DontEnumArray = ['toString','valueOf'];//(2)这个数组还有补充的地方

    var obj_1 = {
    name : 'xesam'
    };
    var obj_2 = {
    age : '24',
    toString:function(){return ('my toString');}
    };

    function extend(destination, source) {
    if(!DontEnum){
    for(var j = 0,len = DontEnumArray.length; j < len; j++){
    if(source.hasOwnProperty(DontEnumArray[j])){
    destination[DontEnumArray[j]] = source[DontEnumArray[j]];
    }
    }
    }
    for (var property in source){
    destination[property] = source[property];
    }
    return destination;
    }
    extend(obj_1,obj_2);
    alert(obj_1.toString());
    })();

    【说明(1)(2):这段代码并不完善,因为还得确定IE6或者其他的浏览器到底屏蔽了哪些属性,需要一一测试】

    Object的静态方法先说这个,还有其他的事,后面的明天再继续。。。

    转载请注明来自小西山子【http://www.cnblogs.com/xesam/
    本文地址:http://www.cnblogs.com/xesam/archive/2011/12/21/2295336.html

  • 相关阅读:
    2019CSP-S总结(复赛)
    2019.11.10【NOIP提高组】模拟 A 组 总结
    2019.11.09【NOIP提高组】模拟 A 组 总结
    2019.11.08晚【NOIP提高组】模拟 A 组 总结
    2019.11.02【NOIP提高组】模拟 A 组 总结
    2019.10.25【NOIP提高组】模拟 A 组 总结
    2019.10.26【NOIP提高组】模拟 A 组 总结
    C++学习之模板特例化
    C++学习之可变参数的函数与模板
    C++学习之函数模板与类模板
  • 原文地址:https://www.cnblogs.com/xesam/p/2295336.html
Copyright © 2011-2022 走看看