Search
Write a publication
Pull to refresh

Comments 22

я вот тоже не понял, зачем автор сюда тоже самое копипастит
Да вот же перевод хороший есть.

Числа — не объекты, а примитивы.

Проверяется вот так:
var a = 2; 
a.a = 3; 
console.log(a.a);


А вот так — объект:
var a = new Number(2);
a.a = 6;
console.log(+a, a.a);
JS – единственный популярный язык с прототипным наследованием


Это не так конечно. Python, Ruby, Lua и др. позволяют изменить класс объекта после создания.

Скажем в Python можно сказать

obj.__class__ = Bar


Просто то что в JS называется obj.__proto в Python называется obj.__class__
Нет, это не так. Отношение между объектом и его классом в Python куда сложнее, чем между объектом и его прототипом в Javascript. Достаточно вспомнить, что происходит с методами. Кроме того, на этом отношении не построить цепочку прототипов (свойства метакласса не видны на уровне объекта).

Ближайший аналог прототипов в Python — это наследование классов. Но на уровне объектов такого аналога нет.
Различия конечно есть, но в принципе все языки у которых для обращения к member fields нужно указывать this, self и т.д. используют ту или иную форму прототипирования (динамический субклассинг). Где-то больше в лоб как в JS, где-то более завуалировано.
Разница принципиальная.
В Javascript можно взять любой объект и одним движением сделать его прототипом для другого — второй будет неявно содержать все поля, определенные в первом. В Python так сделать нельзя.
взять любой объект и одним движением сделать его прототипом для другого

Нет, не любой, а только тот что отнаследован от Object.
Object.create(proto[, propertiesObject])

Throws a TypeError exception if the proto parameter isn't null or an object.


Просто в ES5 нет выделенного Class object. Роль классов выполняют объекты или функции (которые тоже instanceof Object). В ES6 уже есть Class (object, prototype of all classes).
Любой объект.

var proto = Object.create(null);
console.log(proto instanceof Object); // => false
var instance = Object.create(proto);
console.log(instance instanceof Object); // => false

function f(){}
console.log(f.isPrototypeOf(Object.create(f))); // => true

ES6 в этом плане абсолютно ничем не отличается от ES5.

console.log(Object.getPrototypeOf(function(){}) === Function.prototype); // => true
console.log(Object.getPrototypeOf(class {}) === Function.prototype); // => true

console.log(Object.getPrototypeOf((function(){}).prototype) === Object.prototype); // => true
console.log(Object.getPrototypeOf((class {}).prototype) === Object.prototype); // => true
Просто в ES5 нет выделенного Class object.
Вот именно это и отличает прототипное наследование от классического.

В ES6 уже есть Class (object, prototype of all classes).
Ничего подобного, в ES6 не добавили ничего кроме сахара. «Выделенный Class object», что бы вы под ним не понимали, к использованию не обязателен.
Вот именно это и отличает прототипное наследование от классического.


В т.н. динамических языках это вот
boo.foo();

исполняется в runtime как

var method = getObjectProperty(boo,"foo");
method.call( boo, method );


Разница лишь деталях имплементации этой getObjectProperty(). В JS используется __proto chain, в Python __class__ chain а в моём tiscript это prototype chain. Принцип один и тот же.

Не существует никакого __class__ chain, механизм поиска метода в Питоне гораздо сложнее.
Да? А Гвидо мне говорил что как раз всё именно так и просто. Врал поди.
Не знаю, где он это говорил, но поиск значения происходит таким образом:

1. Сначала происходит поиск в словаре объекта — если значение найдено, оно возвращается сразу же.
2. Поиск в словарях классов, в порядке прямого обхода графа базовых классов.
3. Если найденное на шаге 2 значение является дескриптором свойства — вызывается его геттер. Кстати, функция реализует интерфейс дескриптора — преобразование функции в bound method происходит именно в геттере.

Еще в какой-то момент вызываются особые слоты (они же магические __методы__), которые могут переопределить этот алгоритм. Лично я уже не помню, куда их тут надо вставить.

В этом списке только переход между объектом и его классом выполняется по __class__ — этого слишком мало, чтобы назвать алгоритм "__class__ chain". Тем более, что в случае множественного наследования цепочки вообще не получается.
То что ты вот привел выше есть фактически вольный перевод соотв. раздела JavaScript/ES5 спецификации www.ecma-international.org/ecma-262/5.1/#sec-8.12.3

А понятия «много» и «мало» и их относительность освещены в классике достаточно.
Javascript Garden хорошая работа, но мне кажется, что лучше все-таки напрячься и прочесть JavaScript: The Definitive Guide издательства O’Reilly Media. Во всяком случае, тогда можно будет узнать такие мелочи, как «почему delete удаляет не все свойства» или «чем 'x=1' отличается от 'var x=1' в нестрогом режиме работы JS»
Тут собраны советы по тому, как избежать распространённых ошибок и малозаметных багов, а также проблем с быстродействием и неправильного стиля программирования.


Я вижу только плохие примеры.
Зачем писать специальные примеры, в которых все плохо? Лучше же сделать примеры, где хорошо.

Объекты — хорошо. Пример показывает что все в JS есть объектами.

Удаление свойств — НЕ используйте delete, вообще никогда! Изменение структуры объекта, после его определения очень сильно бьет по производительности и V8 такие места не оптимизирует.

Зарезервированные слова — хорошо. Можно даже привычку выработать, всегда заключать в кавычки.

Прототипы
Bar.prototype = new Foo(); // Не делайте такого! Не плодите лишние объекты, когда у вас прототип уже и так объявлен!
Bar.prototype = Object.create(Foo.prototype); // Так правильно


Проход по объекту
Этот код о-о-очень медленный. Вообще забудьте что у JS есть оператор in.
for(var i in foo) {
    if (foo.hasOwnProperty(i)) {
        console.log(i);
    }
}


Используйте его аналоги .keys(), .forEach() та хоть for(;;), только не for in.
Эмм… Вы что-то перегибаете.

НЕ используйте delete, вообще никогда!

delete это такое же изменение структуры объекта, как и добавление нового свойства в него. Да, это изменение внутреннего класса объекта, да, это плохо для структур / инстансов. Но в словарях без этого никуда. Да, Google в своём SoundScript предлагает использовать в качестве словарей исключительно Map. Вот только это пока не реально.

Этот код о-о-очень медленный. Вообще забудьте что у JS есть оператор in.

Ну, знаете… Во-первых, случаи, когда нужно обходить объект с перечислимыми свойствами в прототипе редки, чаще нужно обойти именно словарь и проверка hasOwnProperty в этом случае вообще не нужна, а в такой форме даже вредна. Что касается «о-о-очень медленный» — то только в случае с перечислимыми свойствами в прототипе, с плоскими объектами for-in незначительно отстаёт только в V8, в остальных быстрее, чем Object.keys. Про оператор in даже комментировать желания нет.
delete это такое же изменение структуры объекта, как и добавление нового свойства в него.


Да, я с вами согласен. Поэтому если есть возможность задекларировать структуру объекта заранее, лучше это сделать и не изменять ее больше. Любое изменение структуры или типа данных в рантайме плохо сказываться на скорости работы. Хоть язык и с динамической типизацией, это еще не дает добро добавлять и удалять атрибуты с объектов или менять Number на String, когда переменная уже объявлена как Number и тому подобное.

Что касается «о-о-очень медленный» — то только в случае с перечислимыми свойствами в прототипе

На своем опыте удостоверился в том, что зачастую так и бывает. Разработчики итерируют полноценные объекты со своими цепочками и т.д. Поэтому ваше уточнение про плоские объекты имеет место быть.
Это называется «обезьяньими заплатками»

Обычно это никто не переводит. Monkey patching, он и в Африке monkey patching.
Sign up to leave a comment.

Articles