2013-06-23 6 views
0

У меня есть объект вроде этого:создать объект, который расширяет другой

var source = (function(undefined) { 
    var o; 
    function s(o) { 
     if(!o || typeof o === 'object') { 
      o = o || {}; 
      o.a = typeof o.a === 'string' ? o.a : 'A'; 
      o.b = typeof o.b === 'string' ? o.b : 'B'; 
      this.o = o; 
     } 
    } 
    s.prototype.v = function() { 
     // some function 
    }; 
    s.prototype.x = function() { 
     // some function 
    }; 
    return s; 
})(); 

я хочу использовать другой подобный продлить первый.

var extender = (function(undefined) { 
    var o; 
    function e(o) { 
     if(!o || typeof o === 'object') { 
      o = o || {}; 
      o.c = typeof o.c === 'number' ? o.c : 3; 
      o.d = typeof o.d === 'number' ? o.d : 4; 
      this.o = o; 
     } 
    } 
    e.prototype.y = function(m) { 
     // some function 
    }; 
    e.prototype.z = function(m) { 
     // some function 
    }; 
    return e; 
})(); 

Я могу добавить this.s = new source(o); функции и с некоторыми изменениями в мой второй объект может связать все в первый, но я думал, что может быть лучше.

+0

Почему бы вам не назвать свою переменную 'undefined'? Это одна из самых злых вещей, которые вы можете сделать в Javascript. – Antimony

+3

@ Anthony: No; он создает локальную переменную 'undefined', если кто-то еще устанавливает' window.undefined'. jQuery делает это. – SLaks

+0

Зачем это проблема? И wtf почему должен кто-то установить window.undefined? –

ответ

1

Чтобы объединить фрагменты из двух других ответов на правильное решение, вы, вероятно, хотите

var extender = (function(undefined) { 
    // var o; - That's useless, `o` is a parameter of the constructor 
    function e(o) { 
     source.call(this, o); // invoke the `source` constructor on this instance 
     o = this.o; // and get the created `o` object 
     // …to extend it: 
     o.c = typeof o.c === 'number' ? o.c : 3; 
     o.d = typeof o.d === 'number' ? o.d : 4; 
    } 

    // make the prototype a new object inheriting `v` and `x`: 
    e.prototype = Object.create(source.prototype); 
    // then extend it 
    e.prototype.y = function(m) { 
     … 
    }; 
    e.prototype.z = function(m) { 
     … 
    }; 
    return e; 
})(); 

См документы для Object.create и call.

+0

Э-э, я этого не сделал. Прошу прокомментировать это :-) – Bergi

+0

@tntu: Нет, это не так. Он создавал бы целый * экземпляр * и вызывал конструктор - но без каких-либо параметров (что не имело бы смысла). Вам нужно только наследование, создавая объекты экземпляра (в конструкторе), которые совместно используются всеми объектами 'extender', могут создавать серьезные проблемы. – Bergi

+0

Тогда оба будут указывать на один и тот же объект, и вы создадите 'y' и' z' в 'source.prototype' в основном. Нет ничего плохого в использовании [общей и старой прокладки для объекта Object.create] (http://stackoverflow.com/q/10141086), чтобы она работала гладко в старых браузерах. – Bergi

1

Вы можете использовать: -

Object.create(o);//where o is object to inherit from 

Для кросс-браузер: -

if (typeof Object.create !== "function") 
      Object.create = function(o) { 
       function F() {} 
       F.prototype = o; 
       return new F(); 
}; 
+0

Есть ли 'else'? – transilvlad

+0

Нет. Object.create - это новая функция объекта для создания нового объекта из переданного ему объекта. Современные браузеры поддерживают это. «If» - для браузеров, не имеющих такой поддержки. – pvnarula

+0

Есть ли решение для всех браузеров? Кроме того, мне нужно задействовать исходный объект изнутри основной функции второй. Мне нужно иметь возможность передать параметр инициализации в расширитель и от ti к источнику. – transilvlad

0

Проверьте следующие две строки:

e.prototype = source.prototype;

source.call(this, o);

Это решение.

Конечно, я должен был внести некоторые изменения в конфигурацию, чтобы обеспечить их работу.

var source = (function(undefined) { 
    function s(o) { 
     // config 
     this.o = {}; 
     if(!o || typeof o === 'object') { 
      o = o || {}; 
      this.o.a = typeof o.a === 'string' ? o.a : 'A'; 
      this.o.b = typeof o.b === 'string' ? o.b : 'B'; 
     } 
    } 
    s.prototype.x = function(m) { 
     console.log(m); 
    }; 
    return s; 
})(); 
var extender = (function(undefined) { 
    function e(o) { 
     // instanciate parent 
     source.call(this, o); 
     // child config 
     if(!o || typeof o === 'object') { 
      o = o || {}; 
      e = this.o; 
      e.c = typeof o.c === 'number' ? o.c : 1; 
      e.d = typeof o.d === 'number' ? o.d : 2; 
     } 
    } 
    // inherit 
    e.prototype = source.prototype; 
    // extend 
    e.prototype.y = function(m) { 
     console.log(m); 
    }; 
    return e; 
})(); 
var e = new extender({d:3}); 
console.log(e); 
+0

Я не думаю, что 'source.call (o)' является решением. Вы заметили, что он создает свойство 'o' (с подпрограммами' a' и 'b') в параметре' o', который вы передали, вместо объекта результата ('this' внутри конструктора' e')? – Bergi

+0

Также обратите внимание, что вы не должны использовать 'new' '(http://stackoverflow.com/q/12592913/1048572) для создания прототипа объекта. В вашем случае вы даже можете получить [проблемы с вложенными объектами] (http://stackoverflow.com/q/10131052) – Bergi

+0

Попробуйте записать 'source.prototype.y' и удивляться :-) – Bergi