Пользователь
0,0
рейтинг
27 ноября 2010 в 00:52

Разработка → Разбираемся с prototype, __proto__, constructor и их цепочками в картинках

Есть javascript код:
  1. var A = function () {};
  2. A.prototype.b = 100;
  3. var a = new A();
  4. A.prototype.c = 101;
  5. a.c = -100;
  6. A.prototype = {};
  7. A.prototype.b = 536;
  8. /* 1 */ console.log(a.__proto__.constructor.prototype.b === 536);
  9. var b = new A();
  10. /* 2 */ console.log(a.__proto__.__proto__.constructor === a.__proto__.constructor.prototype.constructor);
  11. /* 3 */ console.log(b instanceof A);
  12. /* 4 */ console.log(!(a instanceof Object));
Вопрос. Что возвратят выражения 1-4 и почему?

Затрудняетесь ответить?
Тогда вам стоит пройти под кат ;-) (Далее 600 Кб больших изображений)


Итак, я думаю многие заинтересованные данной темой читали мануалы и умные книги по javascript, да и не раз, но в голове никак не могут отложиться основы псевдо-ОО (т.е. Prototype-based) части языка. В этой статье вы не найдете сухих фактов и мануалов, после прочтения просмотра станет все просто и понятно.

Что за схемы?
Справа на схеме текущий выполненный код, слева состояние объектов. Черные стрелки — ссылки на объект. Подписи над стрелками — имя свойства по ссылке. Серые стрелки — свои неявные свойства — ссылки на свойства прототипа. Красными отмечены глобальные javascript объекты. Синими переменные. Зелеными локальные объекты. Все console.log'и возвращают true.

Все изображения кликабильны

Можно не листать, а скачать исходники (png + bmml): http://narod.ru/disk/400270001/javascript_prototype.zip.html

Слайд 1





Слайд 2





Слайд 3





Слайд 4





Слайд 5





Исходники (png + bmml): http://narod.ru/disk/400270001/javascript_prototype.zip.html
Исходник кода: pastebin.com/wBchEpxq

Надеюсь, моя статья была полезна для вас, а схемы понятны :)

PS Свойство __proto__ является устаревшим начиная с JavaScript 1.8.1 вместо него стоит использовать Object.getPrototypeOf(object), однако, как писал crash Крокфорд просит не использовать getPrototypeOf если что," если делаете все верно он вам не нужен"
Mikhail Davydov @azproduction
карма
448,5
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (50)

  • –16
    Мсье знает толк в извращениях.
    Сначала запутался немного в стрелках но в итоге разобрался, хоть в пятницу вечером это и не просто.

    • +25
      Достали уже со своим мисье
      • +1
        достали уже со своим «достали мсье»!
        • +2
          Девушки не ссортесь
  • +5
    «The world's most misunderstood programming language has become the world's most popular programming language.»
  • 0
    Материал очень вовремя для меня, спасибо!
    Но беглый взгляд на эти «картинки» вгоняет в глубочаюшую дипрессию.
    Поэтому, пока в избраное — разбираться буду завтра.
    Еще раз спасибо!
  • 0
    крокфорд просит не использовать getPrototypeOf если что," если делаете все верно он вам не нужен"
  • +10
    Надеюсь, моя статья была полезна для вас, а схемы понятны :)
    Честно признаться, нет.
    Ужасное представление информации графически, простите.
    Посмотрите как представлена структура прототипов, скажем, у Закаcа в «Professional JavaScript».
    • +2
      согласен. картинки конечно тру. но ожидалось, что будет еще их перевод.
      • 0
        Думал сделать даже анимацию, чтобы можно было проследить цепочки, но статья была бы уже для совсем другой аудитории. Кода и схем вполне достаточно.
      • 0
        по мне, лучше потратить время на изучение анг. языка, тем более, что тех. анг. прост, чем каждый раз ломать себе мозг о подобные схемы
  • НЛО прилетело и опубликовало эту надпись здесь
    • –2
      Согласен, зря, но никакое другое слово не подходило по контексту. Квази-ОО?
      • +3
        Прототипное ОО. Именно так все и говорят. Кстати, классовое и прототипное — не единственные вариант ООП.
        • +1
          Что в javascript Прототипное ОО мне известно, но в контексте предложения оно вставало не красиво. Добавлю пояснения, дабы не смущать остальных читающих.
  • +6
    Честно говоря, без поясняющего текста или без полного понимания происходящего понять работу прототипного наследования по вашим картинкам не представляется возможным.
    • 0
      Это есть в любой книге по javascript «повышенного уровня». Я вас уверяю, что в любом описании из книг сложнее разобраться, чем в моих схемах. Одно другому, конечно, не помешает, но зачем копипастить, раз все читали и даже имеют книги под рукой.
      • +1
        Как человек, видевший книжки своими глазами, скажу, что в них все объяснено достаточно доходчиво. Можно даже посмотреть статьи на js.ru, и там тоже понятно.
        • 0
          а адрес точно указан (js.ru)?
          • 0
            Нет, я сократил. Имелся ввиду сайт javascript.ru
  • +1
    Мне больше интересно что значит «псевдо-ОО»
  • +6
    Требую больше Comic Sans!
  • +6
    image
  • +2
    Да… Если бы С++ был спроектирован так же как JavaScript… даже представить страшно.
    • +1
      Ну Вы знаете… при разборе некоторых конструкций, в которых намешаны макросы/темплейты/области условных компиляций реально очень легко потерять голову :)

      Причем даже совершенно стандартные классы. Вот первый пример, который пришел ко мне в голову — Многие ли с++-шники знают на память во что «разворачивается» сигнатура операции "<<" у потока для string которую очень многие используются?
      Т.е. то, что операция "<<" вот в этом всем привычном виде:
      cout << string("test");
      

      «разворачивается» в:
      std::basic_ostream<char, std::char_traits<char> >& std::operator<< <char, std::char_traits<char>, 
         std::allocator<char> >(std::basic_ostream<char, std::char_traits<char> >&,
         std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
      


      Так что я бы не стал вот так сразу говорить, что в С++ намного проще конструкции бывают даже со стандартными типами.

      А про JS… не забывайте, что JS скорее похож на функциональный язык, чем на объектный. По этому и нужны грабли с прототипами для эмуляции ОО. В С++ наоборот — все просто с объектами-классами, зато довольно тяжело с лямбдами, каррированием и т.д. (да, можно и есть довольно красивые имплементации, но если заглянуть внутрь… страшно)

      • 0
        Согласитесь, что ОО модель JS заставляет пользоваться чистым JS только при особых требованиях к задаче, типа производительности, в остальных случаях только фреймворки позволяют получить результат, даже в простейших случаях. И только гуру могут объяснить, почему работает так как работает, а не иначе. Вроде всё просто — десяток страниц в спецификации всё подробно описывают, а на практике всё равно непонятно.
        • 0
          Ну почему-же? Привет использования «чистого js» — приложения, написанные для node.js. Да, там тоже используются дополнительные библиотеки, но они скорее утилитарные (доступ к бд, работа с сетью и т.д.), но не «расширающие» язык (как, например, jQuery). Сам же node.js не добавляет какие либо дополнительные «фичи» в язык js.

          А чтоб стало понятно, нужно просто немного пересмотреть на то, что является функция, а что объект. В JS эти понятия довольно сильно отличаются от тех, какие приняты в ООП-языках.

          И когда разберешься становится совсем весело использовать эти отличия!

          На самом деле кроме «цепочек» действительно очень важно понять отличие «функции» от «объекта».

          Вот кстати, интересные факты, о которых интересно подумать почему так:
          (function(){}).__proto__ — это функция
          (function(){}).__proto__.__proto__ — объект,
          и объект или не объект (function(){}).__proto__.__proto__.__proto__ (на самом деле объект, но необычный :))

          • 0
            (function(){}).__proto__ ссылкается на прототип конструктора (Function)
            (function(){}).__proto__.__proto__ ссылается на прототип конструктора (Function), который ссылается на прототип конструктора (Object)
            (function(){}).__proto__.__proto__.__proto__ ссылается на прототип конструктора (Function), который ссылается на прототип конструктора (Object), прототипа конструктора у Object нет поэтому последний прото ни на что не ссылается (null) это даже не undefined
            • 0
              почти… только в конце немного не так — прототип конструктора у Object-а есть, но он, как Вы верно заметили, равен null.

              Не забывайте, что в JS (в отличии от Java/.NET) null — это объект, который показывает, что значение есть, но пустое. А отсутствие показывает undefined (в контексте значения, а не как переменная undefined, которая может иметь другое значение — вот такой JS загадочный :))
              • 0
                На самом деле null — это никакой не объект. null это просто null. Так же как undefined это просто undefined. :)

                {}.blah // undefined
                null.blah // Exception!
                • –3
                  для раздумий:
                  typeof(null) --> object
                  undefined = true
                  typeof(undefined) --> boolean
                  

                  :)
                  • +1
                    Ваш поучающий тон неуместен. :)

                    typeof нагло врёт в двух случаях: про null и про function. В JS существует 6 типов:
                    1. undefined
                    2. null
                    3. number
                    4. string
                    5. boolean
                    6. object

                    null — это такой тип, который как и undefined имеет только одно значение: null. object — это другой тип. Ну и function это просто специальный объект.

                    То что глобальное свойство undefined можно переписать ничего не меняет (кстати в ES5 это исправили и последняя версия Safari не позволяет переписать undefined).
                    • 0
                      а что же такое тогда NaN?
                      • 0
                        NaN — это одно из значений типа number.
                • +1
                  The undefined value is a primitive value used when a variable has not been assigned a value
                  undefined — пустое значение
                  The null value is a primitive value that represents the null, empty, or non-existent reference
                  null — пустая ссылка, ссылка на спец объект, который бросается эксепшенами, когда обращаются к его свойствам/методам
                  typeof undefined
                  undefined = !undefined; // счастливой отладки ;-)
                  именно поэтому с undefined нельзя сравнивать и undefined нельзя присваивать лучше использовать null ибо null нельзя переписать.
                  ps typeof это не функция
  • 0
    Такие схемы наверное рисовали многие в процессе изучения JS. Я тоже рисовал :)

    Но это все примерно то же самое что для функции f=x/2 чертить табличку значений (x=2, y=1; x=3, y=1.5; ...) Проще говоря — перечислять частные случаи. Намного проще понять саму функцию, чем изучать табличку.

    Прототипное наследование JS описывается буквально 3-4 фразами (ну может 5-6), включая даже описание наследования от встроенных конструкторов (Object, Function, Array и т.д.). И не надо никаких стрелочек )

    • +1
      Можете здесь написать? (серьезно)
      • +5
        Да пожалуйста :)

        1. Любой объект имеет ссылку на объект-прототип (в редких случаях эта ссылка может указывать на null).
        2. При доступе к свойству объекта на чтение или на вызов (для методов), если оно не найдено в самом объекте, то ищется в объекте-прототипе, и далее по цепочке.
        3. Функция — тоже объект. Числа и строки не являются объектами, но конвертируются в них автоматически в момент вызова методов ('test'.charAt(0) == new String('test').charAt(0))
        4. Любой объект явно или неявно создается с помощью конструкции new и функции-конструктора ([1,2,3] == new Array(1,2,3))
        5. Любая функция имеет свойство prototype, которое как раз и содержит ссылку на объект, используемый в качестве прототипа при создании новых объектов (см. пункт 4). Таким образом — любая функция является конструктором.
        6. Object, Function, Array, RegExp, String, Number и т.д. — это функции.
        7. У любого объекта в начале цепочки прототипов стоит Object.prototype (кроме случаев когда у объекта вообще нет прототипа). У самого Object.prototype ссылка на объект-прототип равна null.

        Это основные тезисы. Предполагается, что если это понятно, то все остальное вообще вопросов не вызывает, либо можно разобраться самостоятельно.

        Можно еще разжевать что любая функция как объект имеет в качестве прототипа Function.prototype, но это и так понятно исходя из пунктов 4 и 6.

        P.S. К сожалению, в спецификации JS нет названия для свойства объекта, которое ссылается на прототип (__proto__ в некоторых реализациях), и приходится так и писать — «ссылка на прототип», да еще и начинающим легко спутать со свойством prototype, которая есть у функции. Если бы не эта проблема с терминологией, можно было бы более кратко и емко формулировать мысль.
        • 0
          Абсолютно согласен. По поводу P.S., вот тут-то схемы и помогут. Из моей небольшой практики проведения мастер-классов *простые* схемы очень помогают объяснить эту разницу между [[Prototype]] и prototype.
        • 0
          Спасибо
  • +3
    Написали бы ответы под катом, для самопроверки…
    А то заходишь и облом — куча громоздких картинок а самого интересного нет.
    • +1
      Не проверял, но ихмо:
      1. true
      2. true
      3. true
      4. false
  • +1
    Если делаете презентацию — пользуйтесь PowerPoint, OpenOffice Impress или Google Docs. А не картинки.
    • 0
      Пользуйтесь TeX тчк
      • 0
        Лучше iTex (http://habrahabr.ru/blogs/latex/104568/ )
  • +3
    скоро на хабре будет перевод на русский dmitrysoshnikov.com/ecmascript/javascript-the-core/ который многое пояснит чего тут не понятно.
    • +1
      Ложка меда в бочке дегтя! Спасибо!
  • 0
    Лучшее, что я видел на русском про ООП в JavaScript пару лет назад: dl.dropbox.com/u/3566235/js.zip (сайт автора давно умер, в архиве офлайн копия со схемами и примерами).
  • 0
    Уже столько времени прошло с момента публикации этой статьи, но всё равно она помогает людям (ну или мне :) ), посидел, поразбирался и вроде всё дошло. Спасибо.
    • 0
      Информация вечна ;) Незачто.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.