javascript - 在 javascript 中创建和扩展对象会覆盖基础对象的变量

标签 javascript inheritance

我有一个基本的 Object.create 包装器用于我们的应用程序。基本上,该过程是在父对象上使用 Object.create,然后使用 .extend({}) 向其添加新功能。如果我们需要调用父类的方法,我们只需在方法覆盖中使用 ParentClass.myFunc.apply(this, arguments);。我遇到的问题是当我初始化一个对象并调用父对象的 init 函数时,它会覆盖父对象的属性。我怎样才能防止这种情况发生?

这是主要的 Object.create 包装器:

/**
 * Simple wrapper for Object.create and Object.extend
 * functionality.
 */
var My_Object = {
    /**
     * Simple extend function for inheritance
     * @param props An object of functions to place in the new object.
     * @returns {My_Object}
     */
    extend: function(props) {
        for(var prop in props)
            this[prop] = props[prop];

        return this;
    },

    /**
     * Basic function that checks if a function is native or user-created
     * @author Yong (http://stackoverflow.com/users/962254/yong)
     *
     * @param f The function to test if it is native
     * @returns {boolean}
     *
     * @see http://stackoverflow.com/questions/6598945/detect-if-function-is-native-to-browser
     */
    isFuncNative: function(f) {
        return !!f && (typeof f).toLowerCase() == 'function'
            && (f === Function.prototype
            || /^\s*function\s*(\b[a-z$_][a-z0-9$_]*\b)*\s*\((|([a-z$_][a-z0-9$_]*)(\s*,[a-z$_][a-z0-9$_]*)*)\)\s*{\s*\[native code\]\s*}\s*$/i.test(String(f)));
    },


    /**
     * Simple polyfill wrapper for native Object.create. Using a polyfill
     * instead of native incase for some reason consumer would have overwritten
     * it with unexpected usage.
     */
    create: function(obj) {
        // If the browser supports Object.create and hasn't been overwritten,
        // use the native version instead of the polyfill
        if(My_Object.isFuncNative(Object.create)) {
            // If extend hasn't been defined, add it
            if(!obj.hasOwnProperty('extend'))
                obj.extend = My_Object.extend;

            return Object.create(obj);
        }


        // Create empty function for polyfill
        function F(){}
        F.prototype = o;

        // If extend hasn't been defined, add it
        if(!F.prototype.extend)
            F.prototype.extend = My_Object.extend;

        return new F()
    }
};

然后我定义一个基础对象:

var SomeParentObject = {
    options: {
        a: 'a',
        b: 'b'
    },

    init: function(options) {
        this.options = $.extend(this.options, options || {});

        return this;
    }
};

有些 child 反对:

var ChildObject1 = My_Object.create(SomeParentObject).extend({
    init: function() {
        SomeParentObject.init.call(this, {b: 'c'});        

        return this;
    }
}).init();

var ChildObject2 = My_Object.create(SomeParentObject).extend({}).init();

现在期望的结果是永远不要修改SomeParentObject 的选项。我无法弄清楚到底是什么原因造成的,但我确定这是我在做的愚蠢的事情。如果您执行一些基本的 console.log,您会看到当 ChildObject2 有一些要覆盖的选项时,它会为 SomeParentObject 覆盖它,并且因此对于所有的 child 。

console.log('<<SomeParentObject.a, SomeParentObject.b>>');
console.log(SomeParentObject.options.a + ', ' + SomeParentObject.options.b);

console.log('<<ChildObject1.a, ChildeObject1.b>>');
console.log(ChildObject1.options.a + ', ' + ChildObject1.options.b);

console.log('<<ChildObject2.a, ChildeObject2.b>>');
console.log(ChildObject2.options.a + ', ' + ChildObject2.options.b);

哪些输出:

<<SomeParentObject.a, SomeParentObject.b>>
a, c
<<ChildObject1.a, ChildeObject1.b>>
a, c
<<ChildObject2.a, ChildeObject2.b>>
a, c 

应该输出的是这样的:

<<SomeParentObject.a, SomeParentObject.b>>
a, b
<<ChildObject1.a, ChildeObject1.b>>
a, c
<<ChildObject2.a, ChildeObject2.b>>
a, b 

最佳答案

如果您不喜欢 JavaScript 中原型(prototype)设计的工作方式以实现简单的继承和 OOP 方式,我建议您看一看:https://github.com/haroldiedema/joii

它基本上允许您执行以下(以及更多)操作:

// First (bottom level)
var Person = new Class(function() {
    this.name = "Unknown Person";
});

// Employee, extend on Person & apply the Role property.
var Employee = new Class({ extends: Person }, function() {
    this.name = 'Unknown Employee';
    this.role = 'Employee';

    this.getValue = function() {
        return "Hello World";
    }
});

// 3rd level, extend on Employee. Modify existing properties.
var Manager = new Class({ extends: Employee }, function() {

    // Overwrite the value of 'role'.
    this.role = this.role + ': Manager';

    // Class constructor to apply the given 'name' value.
    this.__construct = function(name) {
        this.name = name;
    }

    // Parent inheritance & override
    this.getValue = function() {
        return this.parent.getValue().toUpperCase();
    }
});

// And to use the final result:
var myManager = new Manager("John Smith");
console.log( myManager.name ); // John Smith
console.log( myManager.role ); // Manager

console.log( myManager.getValue() ); // HELLO WORLD

关于javascript - 在 javascript 中创建和扩展对象会覆盖基础对象的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21068234/

相关文章:

javascript - Websocket 在刷新时不连接

javascript - 子菜单不会在页面加载时自动添加类

javascript - 无法让 Google Analytics 自定义变量发挥作用

java - Java 中的构造函数覆盖

ruby - 将值传递给 Ruby 类

wpf - FrameworkElement 的 DataContext 属性不会沿元素树继承

javascript - 如何使用纯 javascript 查找单选按钮的值?

c# - 将基类列表转换为派生类列表 - 可能吗?

c++ - protected 构造函数使基类不可实例化

php - AJAX 联系表单在 IE 中不起作用