Pull to refresh

Comments 31

Забавная идея. Вместо объекта в конструкторе можно использовать Object.create и тогда instanceof должен работать.

В ECMAScript 6 для приватных свойств можно использовать символы (уже доступно в Chrome, Firefox, io.js и node.js с версией от 0.12 включительно).
И что? В C# есть Reflection, в Java тоже есть что-то подобное, в Python есть __dict__, в C++ есть Звезда Пустоты. Во всех языках можно получить доступ к приватным полям окольными путями. Так чем же Object.getOwnPropertySymbols мешает приватным полям в Javascript?
instance_of и прочие штуки не будут работать, видимо. Какой смысл делать полноценные приватные свойства? От кого их скрывать? Если пользователь либы хочет стрелять в ногу, пусть стреляет. Но иногда это помогает поправить поведение, если автор библиотеки не учел каких-то случаев / не хочет что-то менять.
Да, действительно. Метод хороший, но для JS куда более эффективен и полезен подход «кишки наружу», как бы это ужасно ни было с точки зрения нормального ООП.
и отказывается от использования прототипов(создает методы для каждого экземпляра объекта заново)

Предложенный вами способ ведь точно так же создает методы для каждого экземпляра класса заново.
Я, к сожалению, не могу понять, что вы имеете в виду этим кодом. Вы избавились от bind(...)? Тем не менее вы создаете новую анонимную функцию для каждого инстанса.
С этим, конечно, не поспоришь.

Этот способ мне напоминает реализацию приватных свойств с помощью WeakMaps (пример). Только там нет возможной путаницы с this и self.
Что вы имеете ввиду? Что современные js-движки настолько глупы, что для каждого объекта будут по новой компилить одну и туже тяжеловесную функцию?
А как же способ спрятать приватные переменные в замыкании?
И как же их использовать в прицепленных к прототипу методах?
В вашем способе число создаваемых объектов будет вдвое больше, что скажется на объёме потребляемой памяти.
И вообще, зачем прятать приватные поля и методы? Они придуманы просто ради удобства и понимания кода. Просто используйте какую-нибудь нотацию приватных полей и всё.
Костя, лол :) Но работает через геттер — так-что не засчитывается :)
Интересно, долго еще из Javascript с его системой наследования на базе прототипов будут пытаться сделать True OOP язык? ;)
Это обычно пытаются сделать те, кто пришел в JS после многолетнего опыта с «True-ООП»-языками и уже мыслит в этой «True-ООП»-парадигме. С таким мышлением им приходится пытаться эмулировать поведение привычных им языков, хотя необходимости в этом нет.
Согласен с вами, однако уже и классы в ES6 добавили.
Нет. Те, кто приходят с True-ООП языков первым делом приходят в дикий восторг: «надо же, я могу в рантайме менять структуру всех объектов, офигеть!»
После чего эти люди начинают на каждое упоминание классов писать «не надо классов! вы не понимаете всей красоты прототипов!».
Через какое-то время до некоторых начинает доходить: «ну могу я структуру прототипа в рантайме поменять, ну что дальше?»
Не знаю кто вас минуснул, странно.
А так:

Восторг это дело случая. Кто слезает с PHP не особо удивляется, ведь аналог там есть.

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

А дальше смотря как принято в личном кодстайле и как в компании. Кто-то может добавить метод к классу (или изменить реализацию или бог его знает что ещё, возможностей и потребностей много), а кто-то связан по рукам и ногам правилом «не меняйте прототипы базовых классов».
Так же в зависимости от условий может быть по-разному реализован метод. И бывает так, что у тебя два варианта: встроить логику в метод или на основе логики создать тот или иной метод (например шаблонизатор может быть один и другой. Вы знаете на момент объявления метода какой есть шаблонизатор. Вы можете в теле проверять при каждом вызове или один раз создать метод с правильным вызовом)
Автор, вопрос в лоб: нужны мне, допустим, приватные и публичные свойства. И с теми и с другими должны уметь работать методы. Как быть?
Приватные пишите в self, публичные пишите в this:

    return {
        hello: funciton(){
            self.private_ = 123;
            this.public_ = 123;
        }
    };
Тогда к ним не обратиться из других функций или снова выходим на обычные замыкания
Нужно разобраться, зачем нужны скрытые свойства.

1. Для защиты от страшных хакеров, которые «взломают» мой объект.
2. Для того, чтобы использующий класс программист, видел только его интерфейс и ему не мозолили глаза способы реализации.

Для 2-го вполне хватает jsdoc'ов с private и IDE'шек с автокомплитом.
3. Для грамотного наследования без «леса» частных свойств и методов
4. Для того, чтобы после подключения библиотечного класса не лезли куда нельзя и не ломали что не надо.

Для 4-его есть культура программирования и установка не обращаться к метдам и свойствам, начинающихся с _ (подчёркивания)
Для 3 только если функцию создающую наследование допилить как-то. И пригодно только для JS, кофе лесом

Риторика
О необходимости вопрос равен вопросу применимости. Для маленьких проектов и скриптов по-настоящему пофиг. А для огромной монолитной системы с множественными наследованиями это уже актуально. Пишу на кофе, поэтому классы и наследование — стандартное явление.
Если не наследоваться, а использовать как либу, то можно и кишками наружу. А при наследовании (если в либе все приватные свойства не сидят в замыкании конструктора) никакие подчёркивания не спасут. Если, например, я для обозначения приватности свойства использовал в его имени подчёркивание как и автор либы. Не лезть же в либу проверять нет ли совпадений для каждого _x (а при минифицировании тут вообще нет гарантий защиты от совпадения имён). Использовать в конструкторе либы var вместо this для приватного свойства нельзя, так как нужен доступ к свойству из метода, добавленного в prototype.

function Lib() {
    this._private = 1;
}

Lib.prototype.getPrivate = function() {
    return this._private;
}

function MyClass() {
    this._private = 2;
}

MyClass.prototype = new Lib();

var myClass = new MyClass();

console.log("_private = " + myClass._private);    // 2
console.log("getPrivate = " + myClass.getPrivate());    // 2


function Lib() {
    var self = this;	// свойство доступно только из конструктора

    this._private = 1;	// свойство доступно и из конструктора и из методов, добавленных через prototype

    return {
        getPrivate: function() {
            return self.privateMethod();
        },
        // или
        getPrivateAlt: Lib.prototype.privateMethod.bind(this)
    }
}

Lib.prototype.privateMethod = function() {
    return this._private;
}

function MyClass() {
    this._private = 2;
}

MyClass.prototype = new Lib();

var myClass = new MyClass();

console.log("_private = " + myClass._private);    // 2
console.log("getPrivate = " + myClass.getPrivate());    // 1
console.log("getPrivateAlt = " + myClass.getPrivateAlt());    // 1
>>«Поскольку функция конструктор возвращает простой объект, не работает instanceof;»

Никто не мешает создаваемому объекту указать явно прототип Animal, вместо Object (создаем через Object.create, а не литерал). Тогда и instanceof будет работать корректно через цепочку прототипов и конструктор будет определяться верно у объекта.

Sign up to leave a comment.

Articles