Object.create()无法按预期工作

时间:2018-04-14 08:11:53

标签: javascript object

我已经在Stack Overflow上阅读了一些问题,但我无法找出问题所在。昨天用户Scott Marcus answered对我的问题给出了解释性答案,我使用Object.create()测试了解决方案,我认为这就是我想写对象的方式。

这是我做过的工作测试:



var Obj = {
        /**
         * @type {string}
         */
        name: '',

        uppercase: function () {
            this.name = this.name.toUpperCase();
            return true;
        },

        /**
         * setName
         * Set the `name` property.
         *
         * @param param
         */
        set setName (param) {
            this.name = param;
        },

        get getName () {
            return this.name;
        }
    };

    var a = Object.create(Obj);
    var b = Object.create(Obj);
    a.setName = "Will";
    b.setName = "Byers";
    
    console.log("Name in object a is: ".concat(a.getName));
    console.log("Name in object b is: ".concat(b.getName));




然后我在我的脚本上尝试了相同的解决方案但Object.create()这次没有创建两个单独的对象,我无法理解为什么。如果单击CLICK按钮,它会在控制台中打印两个应该不同的对象(对象b应该只包含 `{asd:" QWE"})但他们实际上是一样的。

任何人都可以解释我的错误吗?



//  Declaring my object
var Field = {
    /**
     * @type {Object}
     */
    collection: {},


    /**
     * collect
     * Push the | indexName: value | into collection object.
     *
     * @param {object} obj
     */
    collect: function (obj) {
        //console.log(obj);
        var indexNames = Object.keys(obj);
        var selectors = Object.values(obj);

        for (var i=0; i<indexNames.length; i++) {
            var el = document.querySelectorAll(selectors[i]);
            this.collection[indexNames[i]] = this.fldValue(el);
        }
    },

    /**
     * fldValue
     * Get the value of the injected object after having recognized its tagName and type.
     *
     * @param {object} HTMLObject
     * @returns {*}
     */
    fldValue: function (HTMLObject) {
        HTMLObject = HTMLObject[0];
        switch (HTMLObject.tagName) {
            case "INPUT":
                switch (HTMLObject.type) {
                    case "text":
                    case "password":
                    case "hidden":
                        return HTMLObject.value;

                    case "checkbox":
                        return HTMLObject.checked;

                    default:
                        throw "Unknown input type: ".concat(HTMLObject.type);
                }

            case "DIV":
            case "P":
            case "SPAN":
            case "H1":
            case "H2":
            case "H3":
            case "H4":
            case "H5":
            case "H6":
                return HTMLObject.textContent;

            default:
                throw "Unknown element tagName: ".concat(HTMLObject.tagName);
        }
    },

    /**
     *
     * @param {string} className
     * @returns {*}
     */
    reset: function (className) {
        var elements = document.getElementsByClassName(className);

        for (var i=0; i<elements.length; i++) {
            var el = elements[i];

            switch (el.tagName) {
                case "INPUT":
                    switch (el.type) {
                        case "text":
                        case "password":
                        case "hidden":
                            el.value = '';
                            break;

                        case "checkbox":
                            el.checked = false;
                            break;

                        default:
                            throw "Unknown input type: ".concat(el.type);
                    }
                    break;

                case "DIV":
                case "P":
                case "SPAN":
                case "H1":
                case "H2":
                case "H3":
                case "H4":
                case "H5":
                case "H6":
                    el.innerHTML = '';
                    break;

                default:
                    throw "Unknown element: ".concat(el.tagName);
            }
        }
    },

    get getCollection() {
        return this.collection;
    }
};


//  --------------------
//  Object instantiation
  var a = Object.create(Field);
  var b = Object.create(Field);
  
          document.getElementById('send')
            .addEventListener('click', function (ev) {
                a.collect({
                    name: '[name="name"]',
                    password: '.password',
                    title: '.title',
                    description: '.container',
                    note: '#paragraph',
                    chk_1: '[name="chk1"]',
                    chk_2: '[name="chk2"]'
                });

                b.collect({
                    asd: '.title'
                });
                
                // !! They should be different but they're actually the same object !!
                console.log(a.getCollection);
                console.log(b.getCollection);
            });

        document.getElementById('reset')
            .addEventListener('click', function (ev) {
                a.reset('reset');
            });
&#13;
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 class="title">QWE</h1>

<input type="text" class="name reset" name="name">
<input type="password" class="password" name="password">

<input type="checkbox" class="reset" name="chk1">
<input type="checkbox" name="chk2">

<div class="container reset">HEY</div>

<p id="paragraph">OPS</p>

<button id="send">CLICK</button>
<button id="reset">RESET</button>


<script src="Field.js"></script>
<script>

</script>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:3)

这是因为collection是一个对象,由Field引用,因此ab继承对该单个对象的引用并共享它。最初,在设置Field之后,你在内存中有这样的东西(省略了很多细节):

                                       +−−−−−−−−−−−−−−−−−−−−−+
Field−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−>|       (object)      |
                                       +−−−−−−−−−−−−−−−−−−−−−+    +−−−−−−−−−−+
                                       | collection          |−−−>| (object) |
                                       | collect             |−+  +−−−−−−−−−−+
                                       | ...                 | |
                                       +−−−−−−−−−−−−−−−−−−−−−+ |  +−−−−−−−−−−−−+
                                                               +−>| (function) |
                                                                  +−−−−−−−−−−−−+

然后

var a = Object.create(Field);
var b = Object.create(Field)
你有类似的东西:

                                       +−−−−−−−−−−−−−−−−−−−−−+                  
Field−−−−−−−−−−−−−−−−−−−−−−−−−−−−+−−+−>|       (object)      |                  
                                 |  |  +−−−−−−−−−−−−−−−−−−−−−+    +−−−−−−−−−−+  
                                 |  |  | collection          |−−−>| (object) |  
                                 |  |  | collect             |−+  +−−−−−−−−−−+  
                                 |  |  | ...                 | |                
                                 |  |  +−−−−−−−−−−−−−−−−−−−−−+ |  +−−−−−−−−−−−−+
              +−−−−−−−−−−−−−−−+  |  |                          +−>| (function) |
a−−−−−−−−−−−−>| (object)      |  |  |                             +−−−−−−−−−−−−+
              +−−−−−−−−−−−−−−−+  |  |
              | [[Prototype]] |−−+  |
              +−−−−−−−−−−−−−−−+     |
                                    |
              +−−−−−−−−−−−−−−−+     |
b−−−−−−−−−−−−>| (object)      |     |
              +−−−−−−−−−−−−−−−+     |
              | [[Prototype]] |−−−−−+
              +−−−−−−−−−−−−−−−+

请注意,ab会继承collection,这意味着它们会引用相同的集合对象。

相反,您需要ab每个人都拥有拥有 collection对象:

var a = Object.create(Field);
a.collection = {};
var b = Object.create(Field);
b.collection = {};

//  Declaring my object
var Field = {
    /**
     * @type {Object}
     */
    collection: {},


    /**
     * collect
     * Push the | indexName: value | into collection object.
     *
     * @param {object} obj
     */
    collect: function (obj) {
        //console.log(obj);
        var indexNames = Object.keys(obj);
        var selectors = Object.values(obj);

        for (var i=0; i<indexNames.length; i++) {
            var el = document.querySelectorAll(selectors[i]);
            this.collection[indexNames[i]] = this.fldValue(el);
        }
    },

    /**
     * fldValue
     * Get the value of the injected object after having recognized its tagName and type.
     *
     * @param {object} HTMLObject
     * @returns {*}
     */
    fldValue: function (HTMLObject) {
        HTMLObject = HTMLObject[0];
        switch (HTMLObject.tagName) {
            case "INPUT":
                switch (HTMLObject.type) {
                    case "text":
                    case "password":
                    case "hidden":
                        return HTMLObject.value;

                    case "checkbox":
                        return HTMLObject.checked;

                    default:
                        throw "Unknown input type: ".concat(HTMLObject.type);
                }

            case "DIV":
            case "P":
            case "SPAN":
            case "H1":
            case "H2":
            case "H3":
            case "H4":
            case "H5":
            case "H6":
                return HTMLObject.textContent;

            default:
                throw "Unknown element tagName: ".concat(HTMLObject.tagName);
        }
    },

    /**
     *
     * @param {string} className
     * @returns {*}
     */
    reset: function (className) {
        var elements = document.getElementsByClassName(className);

        for (var i=0; i<elements.length; i++) {
            var el = elements[i];

            switch (el.tagName) {
                case "INPUT":
                    switch (el.type) {
                        case "text":
                        case "password":
                        case "hidden":
                            el.value = '';
                            break;

                        case "checkbox":
                            el.checked = false;
                            break;

                        default:
                            throw "Unknown input type: ".concat(el.type);
                    }
                    break;

                case "DIV":
                case "P":
                case "SPAN":
                case "H1":
                case "H2":
                case "H3":
                case "H4":
                case "H5":
                case "H6":
                    el.innerHTML = '';
                    break;

                default:
                    throw "Unknown element: ".concat(el.tagName);
            }
        }
    },

    get getCollection() {
        return this.collection;
    }
};


//  --------------------
//  Object instantiation
  var a = Object.create(Field);
  a.collection = {};
  var b = Object.create(Field);
  b.collection = {};
  
          document.getElementById('send')
            .addEventListener('click', function (ev) {
                a.collect({
                    name: '[name="name"]',
                    password: '.password',
                    title: '.title',
                    description: '.container',
                    note: '#paragraph',
                    chk_1: '[name="chk1"]',
                    chk_2: '[name="chk2"]'
                });

                b.collect({
                    asd: '.title'
                });
                
                // !! They should be different but they're actually the same object !!
                console.log(a.getCollection);
                console.log(b.getCollection);
            });

        document.getElementById('reset')
            .addEventListener('click', function (ev) {
                a.reset('reset');
            });
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 class="title">QWE</h1>

<input type="text" class="name reset" name="name">
<input type="password" class="password" name="password">

<input type="checkbox" class="reset" name="chk1">
<input type="checkbox" name="chk2">

<div class="container reset">HEY</div>

<p id="paragraph">OPS</p>

<button id="send">CLICK</button>
<button id="reset">RESET</button>


<script src="Field.js"></script>
<script>

</script>

当然,每次创建Field时都必须编写每个实例的初始化逻辑,这就是为什么我们有构造函数/ class语法或构建器的原因。如果您不想使用new,请执行此功能。

function newField() {
    var f = Object.create(Field);
    f.collection = {};
    return f;
}

然后

a = newField();
b = newField();