JavaScript对象和基元类型有什么区别? [英] What is the difference between JavaScript object and primitive types?

查看:97
本文介绍了JavaScript对象和基元类型有什么区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Stoyan Stefanov在他出色的书面向对象的JavaScript中说:


任何不属于其中一个的值上面列出的五种原始类型是一个对象。


对于五种原始类型,他的意思是数字字符串布尔值未定义。但是在谷歌Chrome控制台中,数字似乎根本不是原始类型(与 C 基本类型相比,如 int ) 。看起来原语号码有方法:

  var a = 2.2; 
console.log(a.toFixed()); //记录2

因此我假设我可以使用数字作为对象,所以我试图给它分配一个属性:

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

我不明白这种行为。如果number有一个方法,它应该表现得像对象,不应该吗?它甚至有一个原型:

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

那么这背后的魔法是什么? JavaScript如何处理对象与原始类型?我宁愿不使用 primitive 这个词,而是用简单对象替换它。正如我所看到的那些是无法用新属性扩展的对象,但它们是通过构造函数构造的,并且还具有可以像普通对象一样扩展的原型。

解决方案


[...] 看起来像原始数字有方法




原语实际上并没有自己的属性。它被强制转换为一个对象,以便能够访问它的属性。强制对象在被调用的方法*之外是不可访问的(在严格模式下甚至在方法内)*。因此,引用的变量总是原始的。



考虑这个简单的例子:

  Number.prototype.myTypeInAMethod = function(){
console.log(typeof this.valueOf())//number=>基元包裹在一个对象中。
返回此类型;
}

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

side note:在ES5s严格模式下,这个将是一个基元,类型将是数字



变量 num 是一个原语,您可以为其赋值。

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

如果您改为创建一个数字(或字符串)通过其对象构造函数,它的类型确实是一个对象。
通过添加属性进行快速检查表明它实际上可以被分配。

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






< blockquote>

那么这背后的魔力是什么? JavaScript如何处理对象与原始类型?


此过程在ES5§8.7.1 GetValue



对象:




  • 如果类型(V)不是参考,则返回 V

  • 让base成为调用 GetBase(V)的结果。

  • If IsUnresolvableReference(V),抛出 ReferenceError 异常。

  • 如果 IsPropertyReference(V ),然后

    • 如果 HasPrimitiveBase(V) false ,然后让获取成为 base 的[[Get]]内部方法,否则让 get 成为特殊的[[Get]]内部下面定义的方法。

    • 使用 base 作为 this 返回调用 get 内部方法的结果值,并为参数传递 GetReferencedName(V)


  • El se, base 必须是环境记录。

    • 返回调用 GetBindingValue 的结果(参见 10.2.1 base 传递 GetReferencedName(V)的具体方法 IsStrictReference(V)作为参数。




对于基元:


以下[[Get]]内部方法由当V是属性引用 [1] 且具有
原始基值时,GetValue。使用base作为其值并使用属性P作为其参数调用它。
采取以下步骤:





  • O 成为 ToObject(base)

  • desc 成为调用内部[[GetProperty]]的结果 O 的方法,属性名称为 P

  • 如果 desc 未定义,返回未定义

  • 如果 IsDataDescriptor(desc) true ,返回 desc 。[[Value]]。

  • 否则, IsAccessorDescriptor(desc)必须 true 所以,让 getter desc 。[[Get]]。

  • 如果 getter 未定义,返回未定义

  • 返回调用 getter 提供 base 作为 this 值并且不提供任何参数。




注意在上述方法之外无法访问步骤1中可能创建的对象。实现可能会选择避免实际创建对象。使用此内部方法的此类实际属性访问可以具有可见效果的唯一情况是它调用访问器函数时。



[1] IsPropertyReference(V)。如果基值是对象或 HasPrimitiveBase(V) true ,则返回 true ;否则返回 false


Stoyan Stefanov in his excellent book 'Object-Oriented JavaScript' says:

Any value that doesn't belong to one of the five primitive types listed above is an object.

With five primitive types he means Number, String, Boolean, Undefined and Null. However in Google Chrome console it seems like number is not primitive type at all (compared to C primitive types like int). It looks like the primitive number has methods:

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

Thus I assumed that I can work with number as with an object, so I tried to assign a property to it:

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

I don't understand that behavior. If number has a method, it should behave like object, shouldn't it? It even has a prototype:

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

So what is the magic behind this? How JavaScript treats objects versus primitive types? I would rather not use the word primitive and substitute it with simple objects. As I see it those are objects which can't be extended with new properties, however they are constructed through their constructor and also have prototype which can be extended like with normal objects.

解决方案

[...] It looks like the primitive number has methods

The primitive, does not actually has its own properties. It gets coerced to an object in order to be able to access "its" properties. The coerced object is not accessable outside the called Method *(In strict mode even not inside the method)*. As such, the referenced variable is always a primitive.

Consider this simple example:

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

side note: In ES5s strict mode,this would be a primitive and the type would be number

Since the variable num is a primitive, you can not assign values to it.

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

If you instead create a number (or string) via its object constructor, its type indeed is an object. A quick check by adding a property shows it can actually be assigned.

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


So what is the magic behind this? How JavaScript treats objects versus primitive types?

This process is described in ES5 §8.7.1 GetValue

For an object:

  • If Type(V) is not Reference, return V.
  • Let base be the result of calling GetBase(V).
  • If IsUnresolvableReference(V), throw a ReferenceError exception.
  • If IsPropertyReference(V), then
    • If HasPrimitiveBase(V) is false, then let get be the [[Get]] internal method of base, otherwise let get be the special [[Get]] internal method defined below.
    • Return the result of calling the get internal method using base as its this value, and passing GetReferencedName(V) for the argument.
  • Else, base must be an environment record.
    • Return the result of calling the GetBindingValue (see 10.2.1) concrete method of base passing GetReferencedName(V) and IsStrictReference(V) as arguments.

For a primitive:

The following [[Get]] internal method is used by GetValue when V is a property reference[1] with a primitive base value. It is called using base as its this value and with property P as its argument. The following steps are taken:

  • Let O be ToObject(base).
  • Let desc be the result of calling the [[GetProperty]] internal method of O with property name P.
  • If desc is undefined, return undefined.
  • If IsDataDescriptor(desc) is true, return desc.[[Value]].
  • Otherwise, IsAccessorDescriptor(desc) must be true so, let getter be desc.[[Get]].
  • If getter is undefined, return undefined.
  • Return the result calling the [[Call]] internal method of getter providing base as the this value and providing no arguments.

NOTE The object that may be created in step 1 is not accessible outside of the above method. An implementation might choose to avoid the actual creation of the object. The only situation where such an actual property access that uses this internal method can have visible effect is when it invokes an accessor function.

[1] IsPropertyReference(V). Returns true if either the base value is an object or HasPrimitiveBase(V) is true; otherwise returns false.

这篇关于JavaScript对象和基元类型有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆