2014-02-21 7 views
9

Стоян Стефанов в своей замечательной книге "объектно-ориентированный JavaScript говорит:В чем разница между объектом JavaScript и примитивными типами?

Любое значение, которое не принадлежит к одному из пяти типов примитивов, перечисленных выше, является объектом.

С пяти примитивных типов он означает Number, String, Boolean, Undefined и Null. Однако в консоли Google Chrome кажется, что число вообще не является примитивным типом (по сравнению с C примитивными типами, такими как int). Похоже, что число примитивного имеет методы:

var a = 2.2; 
console.log(a.toFixed()); // logs "2" 

Таким образом, я полагал, что я могу работать с номером, как с объектом, так что я пытался присвоить свойство к нему:

var a = 2; 
a.foo = 'bar'; 
console.log(a.foo); // logs undefined 

I не понимаю этого поведения. Если номер имеет метод, он должен вести себя как объект, не так ли? Он даже имеет прототип:

Number.prototype.foo = 'bar'; 
var a = 2; 
console.log(a.foo); // logs 'bar' 

Так что это магия за этим? Как JavaScript обрабатывает объекты по сравнению с примитивными типами? Я бы предпочел не использовать слово примитивный и заменить его простых объектов. Как я вижу, это объекты, которые не могут быть расширены новыми свойствами, однако они построены через их конструктор, а также имеют прототип, который может быть расширен как обычный объект.

+1

Это не определено, потому что вы не создали свой собственный пользовательский метод «foo». Когда вы сделали (number.prototype.), Все в порядке. Это не'магическое «просто классовое поведение». (доступно для всех типов). Поэтому я не уверен, как ответить на ваш вопрос: «Какая у него магия?» : L) –

+0

Если все что-то осталось неясным, просто поместите комментарий или отредактируйте вопрос, я постараюсь соответствующим образом обновить ответ :) – C5H8NNaO4

ответ

9

[...] Это выглядит примитив номер имеет методы

Примитивный, на самом деле не имеет свои собственные свойства. Он получает принуждение к объекту, чтобы иметь возможность доступа к его «свойствам». Когерентный объект недоступен вне вызываемого метода * (в строгом режиме даже не внутри метода) *. Таким образом, ссылочная переменная всегда является примитивной.

Рассмотрим простой пример:

Number.prototype.myTypeInAMethod = function() { 
    console.log (typeof this.valueOf()) //"number" => The primitive is wrapped in an object. 
    return typeof this; 
} 

var num = 123; 
typeof num; //number 
num.myTypeInAMethod() //object 

сторона Примечание: В ES5s строгом режиме, this бы примитивный и тип был бы номер

Поскольку переменная num является примитивным, вам может не присваивать ему значения.

num.foo = "bar"; 
num.foo //undefined 

Если вы вместо того, чтобы создать ряд (или строка) через его конструктора объекта, его тип действительно является объектом. Быстрая проверка путем добавления свойства показывает, что он действительно может быть назначен.

var objNum = new Number(123); 
typeof objNum ; //"object" 
objNum.foo = "bar"; 
objNum.foo //"bar" 

Так что магия за этим? Как JavaScript обрабатывает объекты по сравнению с примитивными типами?

Этот процесс описан в ES5 §8.7.1GetValue

Для объекта:

  • Если Type(V) не Ссылочная, возвращение V.
  • Пусть основание будет результатом вызова GetBase(V).
  • If IsUnresolvableReference(V), throw a СсылкаError исключение.
  • Если IsPropertyReference(V), то
    • Если HasPrimitiveBase(V) является ложным, то пусть получить быть [[Get]] внутренний метод базы, в противном случае пусть получить быть специальный [[Get]] внутренний метод, определенный ниже.
    • Возвращает результат вызова получить внутренний метод с использованием базы в качестве этого значения, и передавая GetReferencedName(V) для аргумента.
  • Else, основа должна быть запись об окружающей среде.
    • Возвращает результат вызова GetBindingValue (см 10.2.1) конкретный способ базы проходящей GetReferencedName(V) и IsStrictReference(V) в качестве аргументов.

Для примитива:

В следующем [[Get]] внутренний метод используется GetValue, когда V является ссылкой свойства[1] с базовое значение примитива. Он вызывается с использованием базы в качестве ее значения и с свойством P в качестве аргумента. принимаются следующие шаги:

  • Пусть O быть ToObject(base).
  • Пусть убывание быть результатом вызова внутреннего метода [[GetProperty]] для O с именем свойства P.
  • Если убывания является неопределенными, вернуть неопределенной.
  • Если IsDataDescriptor(desc) is true, return desc. [[Value]].
  • В противном случае, IsAccessorDescriptor(desc) должен быть верно так, пусть геттер быть убывание. [[Get]].
  • Если геттер является неопределенными, вернуть неопределенную.
  • Вернуть результат вызова метода [[Call]] внутренний метод газопоглотитель обеспечивая базу в качестве значения этогои не предоставляет никаких аргументов.

Примечание Объект, который может быть создан на шаге 1 не доступен снаружи указанного выше способа. Реализация может решить избежать фактического создания объекта. Единственная ситуация, когда такой фактический доступ к ресурсу, который использует этот внутренний метод, может иметь видимый эффект, когда он вызывает функцию доступа.

[1] IsPropertyReference(V). Возвращает true, если базовое значение является объектом или HasPrimitiveBase(V) is true; в противном случае возвращается false.

+0

Мы проверяем 'typeof' на 'метод', который мы ему дали - что правильно как «объект», но тип «str» все еще является строкой. «Тип» не принудительно/изменен. –

+0

@RobSedgwick Спасибо :) Я попытался немного изменить формулировку, чтобы было более ясно, что примитив остается примитивным. Вы можете перефразировать ответ, если у вас есть лучшая формулировка, поскольку английский не является моим родным языком. – C5H8NNaO4

+1

Я думаю, что ответ велик. Я добавил этот комментарий, поскольку он выглядит путаным между «числом» ** значением ** (который является типом «числа») и классом «номер» (объект), который имеет методы. Как показывает ваш ответ, мы можем использовать строковое значение и строку string 'new String ("string")'. –

Смежные вопросы