Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   наследование в javascript (https://javascript.ru/forum/misc/23367-nasledovanie-v-javascript.html)

mat5978 21.11.2011 16:45

наследование в javascript
 
Добрый день!

Подскажите пожалуйста, почему следующий код так работает:

var todayTimeTable = new timeTable();
	function timeTable(){
		this.showHeader = function(){
			document.write("Расписание на сегодня<br />");
		}
	}
	
	timeTable.prototype = new Array;
	timeTable.prototype.showFirst = function(){
		document.write(this[0]);
	}
	
    // var todayTimeTable = new timeTable(); - если создать объект здесь,то все методы работают

	todayTimeTable.showHeader(); //Расписание на сегодня
	todayTimeTable.push("Информатика"); // ошибка todayTimeTable.push is not a function
	todayTimeTable.showFirst();


Точнее интересуют следующие вопросы:
почему объект в первой строке создается без проблем, хотя его "класс" описывается ниже?
почему в созданный объект не попадают методы, которые имеются в прототипе?

Если создать объект в коде ниже строк описывающих наследование, то объект будет содержать все методы.

Возможно, это простые вопросы, но я не могу самостоятельно найти на них ответы, помогите, пожалуйста, разобраться.

trikadin 21.11.2011 16:52

Прототип !== объект. Если вы сделали прототипом объекта массив, сам он от этого массивом не станет. Поэтому метод push и не работает.

mat5978 21.11.2011 17:23

Цитата:

Сообщение от trikadin (Сообщение 138148)
Прототип !== объект. Если вы сделали прототипом объекта массив, сам он от этого массивом не станет. Поэтому метод push и не работает.

Из этого следует, что объект всегда нужно создавать после указания прототипа?

DreamTheater 21.11.2011 17:38

А при чем тут наследование?

trikadin 21.11.2011 17:56

Цитата:

Сообщение от mat5978
Из этого следует, что объект всегда нужно создавать после указания прототипа?

Из этого следует, что не нужно прототип делать массивом. Массивом объект всё равно не станет)

Nekromancer 21.11.2011 18:20

Ну на самом деле во всех современных движках он станет почти массивом, так как особые Сеттеры, про которые говорили в соседней теме - пронаследуются. Правда в v8 например этот объекта не удастся использовать как массив для передачи параметров в метод apply. Это можно посмотреть в исходных кодах, выглядит примерно так:
function apply(object, array){
if(!Array.isArray(array) || !array instanceof Arguments) throw new TypeError('...');
// ...
}

Естественно там внутренние методы используются, хотя isArray тоже вернёт волс на самом деле. В то время как в SpiderMonkey вернёт тру, если не ошибаюсь. Там полностью наследуется поведение массива. То есть такой новый объект и есть массив.

trikadin 21.11.2011 18:54

Цитата:

Сообщение от Nekromancer
Ну на самом деле во всех современных движках он станет почти массивом

Сильно сомневаюсь, что это кроссбраузерно.

И делать объект массивом всё же не нужно, на мой взгляд. Зачем?)

Snipe 21.11.2011 20:00

Первый раз парсер пробегается по коду, запоминая function, не заглядывая во внутренности. Т.е. пробежавшись, он знает, что timeTable есть. Поэтому ошибки не возникает и присваивание происходит.

Я у себя попроверял.
Если прототип классу присваивается после создания объекта, объект остается без данных прототипа...

Спецификацию не читал, если кто читал - буду рад услышать комментарий по этому поводу.

function Animal(name) {
    this.name = name
    this.canWalk = true
}

function Rabbit(name) {
    this.name = name
}
big = new Rabbit('Chuk')
Rabbit.prototype = new Animal("скотинка");

small = new Rabbit('Gek')

alert(big.canWalk);
alert(small.canWalk);

Nekromancer 21.11.2011 21:01

trikadin,
Ну я и написал, что не кроссбраузерно, даже привёл пример с v8.
А нужно это было мне, для матриц в WebGL, можно выкрутиться там конечно по другому, на так было бы красивее :)

Nekromancer 21.11.2011 21:12

Snipe,
Ну видимо, тут дело в том, что для того, что бы расширять уже существующие объекты, нудно расширять прототип, а не заменять его. Заменяя прототип, вы фактически создаёте новый класс. Берём ваш пример и смотрим:
function Animal(name) {
    this.name = name
    this.canWalk = true
}

function Rabbit(name) {
    this.name = name
}
big = new Rabbit('Chuk')
Rabbit.prototype = new Animal("скотинка");

small = new Rabbit('Gek')
alert(big instanceof Rabbit)
alert(small instanceof Rabbit)


По хорошему конечно, наследование нужно организовывать приблезительно так:

var create = Object.create || (Object.create = function(proto){
	var constructor = function(){};
	constructor.prototype = proto;
	return new constructor;
}), inherit = function(childHandler, parent){
	var child = function(){
		parent.apply(this, arguments);
		childHandler.apply(this, arguments);
	};
	child.prototype = create(parent.prototype);
	child.prototype.__parent__ = parent;
	return child;
}
var A = function(){
	this.foo = 1;
},
B = inherit(function(){
	this.bar = 2;
}, A),
c = new B();
alert(c instanceof B);
alert(c instanceof A);


Часовой пояс GMT +3, время: 10:25.