ECMA262 Edition5 Object,Object的属性和方法,Object.prototype的方法.

ES5,为Object添加了一批方法.了解这些方法,可以更好的理解属性描述符的应用. 所以还是很有必要读一读的。另外,这些方法用起来还是蛮给力的.

暂时对于ES5,就只放出这些吧,希望对大家有所帮助.  此部分大量提到类似 [[getOwnProperty]]等部分可以参考 :http://www.cnblogs.com/_franky/articles/2143688.html


阅读帮助:

如果格式难以阅读,请您谅解,因为copy自evernote.排版很纠结. 您可以选择:

  1. 换一个足够宽的显示器

       2. 调高分辨率

       3. 缩小浏览器文字尺寸. 




15.2 Object对象.

  

     15.2.1 把Object构造器,当做一个函数来调用
     当 Object 当做一个函数,而不是作为一个构造器来调用,就会发生个类型转换操作.
     

     15.2.1.1 Object([value]);(作为函数调用,其实抛开宿主对象,行为和 new Object没啥区别)

     当 Object作为函数,以无参或以value作为参数调用时,就按下面的步骤进行操作:
     1. 如果 value是 null,或undefined 或没有传参,就如同以相同参数,去使用内置的Object构造器一样,创建并返回一个,new Object.
     2. 返回 ToObject(value).
 
 

     15.2.2 Object构造器

     当Object作为构造器,以无参或以value作为参数.被调用时,就按下面的步骤进行操作:
     1. 如果传递了参数,则
               a.  如果 Type(value) 是 Object,则
                    i.  如果 value是一个原生(native)ECMAScript对象,就甭创建新的对象了.直接返回value.
                   ii.  如果 value是一个宿主对象,那么其行为就是依赖于这个宿主对象相关的具体实现的.(就是说,返回啥.由宿主环境看着办了.)
               b.  如果 Type(value)是 String,则返回 ToObject(value).
               c.  如果 Type(value)是 Boolean,则返回 ToObject(value).
               d.  如果 Type(value)是 Number,则返回 ToObject(value).
     2. 优点:当参数没有传递参数value,或者它是null或undefined的情况下.
     3. 令obj 为一个新创建的ECMAScript 对象.(new Object)
     4. 设置obj的内部属性[[Prototype]]为内置对象 prototype.
     5. 设置obj的内部属性[[Class]]为'Object'.
     6. 设置obj的内部属性[[Extensible]]为 true.
     7. 把那些在8.12章节定义的内部方法,都添加给 obj.
     8. 返回obj.
 
 

属性:
 

     15.2.3 Object构造器的属性

     Object的内部属性[[Prototype]],是内置对象Function.prototype对象.
     还有一个  值为1的内部属性 length(函数对象的形参个数.), 剩下的就都是它滴对外开放滴属性了.
     
     

     15.2.3.1 Object.prototype

     Object.prototype的初始化值是内置对象 prototype.(参考15.2.4),这个属性的特性是这样滴:{[[Writable]]:false,[[Enumerable]]:false,[[Configurable]]:false}.
     
 
 
 

 


静态方法:(所有静态方法,都是ES5新增的东东.)


 

     15.2.3.2 Object.getPrototypeOf(O)(获取参数对象的内部属性 [[Prototype]])

     当以O作为参数调用 getPrototypeOf方法时,就按下面的步骤进行操作:
     1. 如果  Type(O) 不是Object,(或者O是null,原文疏漏了.因为Type(null)也是 Object后面几个方法亦如此.不再解释.) 则抛出一个 TypeError异常.
     2. 返回 O的内部属性[[Prototype]].
 
 

     15.2.3.3 Object.getOwnPropertyDescriptor(O, P)

     (获取指定对象的,属性描述符的ECMAScript对象.就像这样子:{value:123,writable:true,enumerable:false,configurable:true})
     当以O, P,作为参数,调用getOwnPropertyDescriptor方法时,就按下面的步骤进行操作:
     1. 如果 Type(O) 不是Object, 或者O是null, 则抛出一个TypeError异常.
     2. 令 name 为 ToString(P).的结果.
     3. 令 desc为以 name为参数,调用O的内部方法[[GetOwnProperty]]的执行结果.
     4. 返回调用 FromPropertyDescriptor(desc)的执行结果(一个可以描述属性特性集的ECMAScript 对象.参见 8.10.4)
 
 

     15.2.3.4 Object.getOwnPropertyNames(O)(获取指定对象的所有自身独占属性名,包括不可枚举的.并返回一个数组.)

     当以O作为参数调用getOwnPropertyNames方法时,就按下面的步骤进行操作:
     1. 如果  Type(O) 不是Object, 或者是null,就抛出一个TypeError异常.
     2. 令 array 为 借助表达式 new Array()创建的一个新对象, Array就是那个叫做Array的内置构造器(说实话,翻译的时候很有压力.废话连篇.但为了精准,避免歧义.也是木有办法.).
     3. 令 n 为0.
     4. 迭代每一个O独占(自身)属性 为P.(此迭代是,无视该属性是否可枚举的.只要有O自身有的属性.就要枚举出来)
               a.  令 name 为 P的字符串值.
               b.  以ToString(n),属性描述符{[[Value]]:name,[[Writable]]:true,[[Enumerable]]:true,[[Configurable]]:true},false作为参数,调用 array的内部方法[[DefineOwnProperty]].
               c.  n自增1.
     5. 返回 array.
     
     注意 如果 O 是一个String的实例,处理到第四步的时候.还要包含那些在 15.5.5.2章节中定义的那些隐式属性(注1).也就是O的[[PrimitiveValue]]字符串,所对应的字符串们.(还有length.)
 
 
 

     15.2.3.5  Object.create(O [, Properties])(创建一个对象,并把该对象的[[Prototype]]设置为O.同时可以一次性添加n多属性)

     create方法根据指定的 prototype去创建一个新对象. 当create方法被调用时,就按下面的步骤进行操作:
     1. 如果 Type(O) 不是Object,则抛出一个TypeError异常.
     2. 令 obj 为 new Object(),(不直译了。原文就是这个意思.太罗嗦.)
     3. 把 obj的内部属性[[Prototype]]设置为 O.
     4. 如果传递了参数 Properties,并且值不是 undefined, 就像调用内置方法 Object.defineProperties那样把指定的属性添加给obj.
     5. 返回 obj.
 
 

     15.2.3.6 Object.defineProperty(O, P, Attributes)(为制定对象,根据指定特性集,添加或设置一个属性)

     defineProperty方法,是用于为一个对象添加或修改一个自身属性独占属性的.当它被调用,就按照下面的步骤进行操作:
     1. 如果 Type(O)不是Object,或者O是null,则抛出一个TypeError 异常.
     2. 令 name 为ToString(P)的值.
     3. 令 desc 为 以 Attributes为参数,调用 ToPropertyDescriptor 的运算结果.(obj 转 属性描述符)
     4. 以name,desc,true 为参数,调用 O的内部方法[[DefineOwnProperty]].
     5. 返回O.
 
 

     15.2.3.7 Object.defineProperties(O, Properties)

     (可以理解成,Properties是一个包含一系列属性名的对象,这些属性名的值都是特性集对象.然后批量的进行defineProperty操作.)
     defineProperties方法,是用于批量的,为一个对象,添加或修改某些自身独占属性的.当它被调用,就按照下面的步骤进行操作:
     1. 如果 Type(O)不是Object,或者O是null,则抛出一个TypeError 异常.
     2. 令 props 为 ToObject(Properties).
     3. 令 names 为一个包含 props所有可以枚举的自身独占属性名的 内部 list对象(参考8.8章节).
     4. 令 descritpors 为一个空的内部 list对象.
     5. 按照 names list的顺序去迭代每一个  names中的元素,作为P.
               a.  令 descObj 为,以P为参数,调用 props的内部方法 [[Get]]的返回值.
               b.  令 desc 为,以 descObj为参数,调用 ToPropertyDescriptor的执行结果.(把obj转属性描述符)
               c.  把 desc添加到 descriptors上.
     6. 按 descriptors list的顺序去迭代每一个 desc元素,
               a.  以P,desc,true 作为参数,调用O的内部方法[[DefineOwnProperty]].
     7. 返回 O.
 
     
 

     15.2.3.8 Object.seal(O)

     (把指定对象,设置为密封状态,即使对象不可扩展.且所有自身独占属性,都不可删除,而且,类似seal,freeze等方法.操作特性时,是无视其属性原始的Configurable的.无论如何都有权限)
     当seal被调用,就按照下面的步骤进行操作:
     1. 如果 Type(O)不是Object,或者O是null,则抛出一个 TypeError异常.
     2. 迭代每一个O的自身独占属性名.属性名作为P的值(Object的这些批量操作属性特性的方法,所指的迭代,都是不考虑其是否是可枚举的.语义上来说,这样才是合理的)
               a.  令 desc 为 以P为参数,调用O的内部方法[[GetOwnProperty]]的执行结果.
               b.  如果 desc.[[Configurable]] 是true,把 desc.[[Configurable]]设置成,false.
               c.  以 P,desc,true 作为参数,调用O的内部方法[[DefineOwnProperty]].\
     3. 把 O 的内部属性[[Extensible]]设置为false.
     4. 返回 O.
 
 
 

     15.2.3.9 Object.freeze(O)

     (把指定对象,设置为冻结状态,即使对象不可扩展.且所有自身独占属性,都不可删除的同时,如果任何一个属性是数据属性,则将该属性的[[Writable]]特性设置为false.)
     当freeze方法被调用,就按下面的步骤进行操作:
     1. 如果 Type(O)不是Object,或O是null,则抛出一个TypeError异常.
     2. 迭代O的每一个属性,属性名作为P的值.
               a.  令desc 为以P为参数,调用O的内部方法[[GetOwnProperty]]的执行结果.
               b.  如果 isDataDescriptor(desc)是true,则(注2)
                    i.  如果 desc.[[Writable]]是true,则把 desc.[[Writable]] 设置为false.
               c.  如果 desc.[[Configurable]] 是true, 则把 desc.[[Configurable]] 设置为false.
               d. 以 P,desc,true 为参数调用 O的内部方法[[DefineOwnProperty]].
     3. 把O的内部属性[[Extensible]]设置为false.
     4. 返回O.
 
     
 
 

     15.2.3.10 Object.preventExtensions(O)(就干一件事,把指定对象的内部属性[[Extensible]]设置为false,使指定对象为不可扩展状态.)

     当 preventExtensions方法被调用,就按下面的步骤进行操作:
     1. 如果 Type(O)不是Object,或O是null,则抛出一个TypeError异常.
     2. 把O的内部属性[[Extensible]]设置为false.
 
 
 

     15.2.3.11 Object.isSealed(O)(判断某对象是不是密封的,如果一个对象是冻结的,那么它也一定是密封滴.)

     当以O为参数,调用isSealed方法时,就按下面的步骤进行操作:
     1. 如果 Type(O)不是Object,或O是null,则抛出一个TypeError异常.
     2. 迭代O的每一个自身独占属性,名为P.
               a.  令desc为以P为参数,调用O的内部方法[[GetOwnProperty]]的执行结果.
               b.  如果desc.[[Configurable]] 为true,则 返回false.
     3. 如果O的内部属性[[Extensible]]为 false.,则返回true.
     4. 其他情况 返回false.
 
 
 

     15.2.3.12 Object.isFrozen(O)(判断某对象是不是冻结状态,即所有自身属性不可编辑,所有数据属性都只读,且该对象不可扩展.)(注3)

     当以O为参数,调用isFrozen方法时,就按下面的步骤进行操作:
     1. 如果 Type(O)不是Object,或O是null,则抛出一个TypeError异常.
     2. 迭代O的每一个自身独占属性,名为P.
               a.  令desc为以P为参数,调用O的内部方法[[GetOwnProperty]]的执行结果.
               b.  如果isDataDescriptor(desc)是true,则
                    i.  如果 desc.[[Writable]]是true,则返回false.
               C.  如果 desc.[[Configurable]]是true,则返回false.
     3. 如果O的内部属性[[Extensible]]为 false.,则返回true.
     4. 其他情况 返回false.
 
 
 

     15.2.3.13 Object.isExtensible(O)(检查指定对象是否是可扩展滴.).(注4)

     当以O为参数,调用isExtensible时,就按下面的步骤进行操作:
     1. 如果Type(O)不是Object,或O是null,则抛出一个TypeError异常.
     2. 返回O的内部属性[[Extensible]]的值.
 
 
 

     15.2.3.14 Object.keys(O).(获取一个以指定对象,可枚举属性名作为元素值的数组对象.)

     当以O为参数,调用keys时,就按下面的步骤进行操作:
     1. 如果Type(O)不是Object,或O是null,则抛出一个TypeError异常.
     2. 令n为O的所有可枚举的自身独占属性的数量.
     3. 令array 为new Array(n)的返回值.
     4. 令index 为0.
     5. 迭代O的每一个可枚举属性,P作为其属性名.
               a.  把ToString(index),属性描述符{[[Value]]:P,[[Writable]]:true,[[Enumerable]]:true,[[Configurable]]:true},以及false作为参数,调用 arr的内部方法[[DefineOwnProperty]].
               b.  index 自增1.
     6. 返回array.
 
     
 
 

 动态方法:

 
 

     15.2.4.2 Object.prototype.toString()(ES3)

     当,toString方法被调用,则按照下面的步骤进行操作:
     1. 令 O为,以this的值作为参数.去调用ToObject(注5)方法的执行结果.
     2. 令class为O的内部属性[[Class]]的值.
     3. 返回 '[Object ', class, ']'三个字符串进行连接的结果. 
 
 
 
     

     15.2.4.3 Object.prototype.toLocaleString()(这个方法存基本没神马用处.更多是为了展望未来么?目前实现,最终还是去调用对象自身原型链上最前面的那个实现.ES3)

     当toLocaleString被调用时,就按下面的步骤进行操作:
     1. 令 O为,以this值为参数.调用ToObject的执行结果.
     2. 令 toString 为以'toString'为参数,调用O的内部方法[[Get]]的执行结果.
     3. 如果 isCallable(toString)是false,则抛出一个 TypeError异常.
     4. 返回 以O作为this的值,无参调用 toString的内部方法[[Call]]的执行结果.
 
     注意点1 : 此方法主要是为所有对象提供一个通用的本地化的序列化方法的接口.尽管并不是所有的对象都需要用这玩意.另外,Array,Number,和Date,都实现了自己的toLocaleString方法.
     注意点2 : 此方法的第一个参数,已经被预留与,在将来的某个ES版本中定义.所以建议在实现这个方法时,把参数一的位置预留出来(好吧ES3就这样说的,到现在依然还要预留下去.).
 
 
 
 

     15.2.4.4 Object.prototype.valueOf() (基本可以认为就是返回 this. ES3)

     当 valueOf方法被调用时,就按下面的步骤进行操作:
     1. 令 O为 this值为参数,调用ToObject的执行结果.
     2. 如果 O是一个 new Object(host object)(参见15.2.2.1章节)的返回对象(注6),则 
               a.  要么直接返回O,要么就返回那个依赖实现的,以构造器方式调用 Object时,所传递的那个对象.(假设new (hostObject) 返回 O,则 {}.valueOf.call(O),则返回 hostObject)
     3. 返回 O.
     
     
 
 

     15.2.4.5 Object.hasOwnProperty(V)(验证,指定对象是有有一个名为V的自身独占的属性.ES3)

     当以V作为参数调用 HasOwnProperty时,就按下面的步骤进行操作:
     1. 令 P为 ToString(V)的执行结果.
     2. 令 O 为 以this值为参数,调用 ToObject的执行结果.
     3. 令 desc 为 以P为参数,调用O的内部方法[[GetOwnProperty]]的执行结果.
     4. 如果desc 是undefined,则返回 false.
     5. 返回true.
 
     注意1 : 和8.12.6章节的[[HasProperty]]不同.此方法不会去原型链上查找.
     注意2 : 步骤1和2的顺序,是为了确保优先在步骤1抛出相关异常的前提下,仍保证在此标准之前的版本所定义的那样.在this的值是undefined,或null时,仍然继续抛出异常.(注7)
     
 
 
 

     15.2.4.6 Object.prototype.isPrototypeOf(V)(验证this 是不是V的原型,this是不是在V的原型链上. ES3)

     当以V为参数,调用isPrototypeOf方法时,就按下面的步骤进行操作:
     1. 如果 V 不是对象,则返回false.(参考 Type(V) != Object && V !== null )
     2. 令O为以this值为参数调用ToObject的执行结果.
     3. 重复步骤:
               a. 设置V的值为 V的内部属性[[Prototype]]的值.(注,此时V = V.[[Prototype]])
               b. 如果V是null, 返回false.
               c. 如果O和V引用相同的对象,返回true.
 
     注意 步骤1和步骤2的顺序,是为了提前在V不是对象的情况.然后在保证像之前版本定义的那样,在this的值是undefined或null时的行为.(注8)
 
 
 
 

     15.2.4.7 Object.prototype.propertyIsEnumerable(V)(验证指定对象的指定属性,是否是可枚举的,ES3)

     当以V为参数,调用propertyIsEnumerable方法时,就按下面的步骤进行操作:
     1. 令 P 为ToString(V)的执行结果.
     2. 领 O为 以this为参数,调用ToObject的执行结果.
     3. 令 desc为,以P为参数,调用O的内部方法[[GetOwnProperty]]的执行结果.
     4. 如果desc是undefined 则返回false.
     5. 返回 desc.[[Enumerable]]的值.
 
     注意1: 此方法,不考虑原型链.
     注意2:  步骤1和2的顺序,是为了确保优先在步骤1抛出相关异常的前提下,仍保证在此标准之前的版本所定义的那样.在this的值是undefined,或null时,仍然继续抛出异常(不解释.同注7)
 
 
 
 
 
 

 

注1:  'franky'[0].本质就是访问 new String('franky')的名为'0'的属性.(另外new String对象,还有一个属性叫length.) 所以.getOwnPropertyNames,也要枚举出他们. 唯一要注意的是 getOwnPropertyNames,要求参数1是对象.所以你需要人肉包装箱一下. 哦不得不提一下的是. IE8居然没有对new String()实现索引器.而只对Primitive Strng实现了. 不得不说是坑爹行为啊.当然这和ES5无关.

 
 

注2:  也就是说,只有某属性是一个数据属性,才会把该属性设置为只读,否则还是要以访问器 setter 为优先. 参考下面的代码:

     
var _name = 'franky',
    obj = Object.create(
        Object.prototype,
        {
            name : {
                set : function (name) {
                    _name = name;
                },
                get : function () {
                    return _name;
                }
            }
        }
    );

Object.freeze(obj);
obj.name = 'wait';
alert(obj.name); //成功的打印 'wait'.
 
 
 
 
 

注3: 所谓所有数据属性都只读.是指.不理会访问器属性的状态.参考下面的代码:

 
var _name = 'franky'
var obj = {
   
};
Object.defineProperty(obj, 'name', {set : function (val) {_name = val;} , get : function () {return _name;}});
Object.freeze(obj);
obj.name = 'wait';
Object.isFrozen(obj); // true
 
 
 
 
     

注4: 对于[[Extensible]]为false的对象来说, v8引擎实现有一个有趣的bug.虽然这个也许不能称之为bug.参考下面的代码:

 
var obj = {},
    v;
Object.preventExtensions(obj);//Safari5,暂时没有实现这个接口.
v = obj.name = 123;
v;// chrome: undefined.

 undefined. 这里 v8引擎严重有问题. 按照赋值语句的运算规则.obj.name = 123整个语句的返回值应该是 = 右边赋值表达式的返回值 ,也就是123. 那么此处v的值应该是123.
          此处firefox4+,ie9的实现是正确的
          这个问题的根源,根据v8的源码猜测:

         C++ code:
         if (!map()->is_extensible()) {
      if (strict_mode == kNonStrictMode) {
        return isolate->heap()->undefined_value();
      } else {
        Handle<Object> number = isolate->factory()->NewNumberFromUint(index);
        Handle<String> name = isolate->factory()->NumberToString(number);
        Handle<Object> args[1] = { name };
        Handle<Object> error =
            isolate->factory()->NewTypeError("object_not_extensible",
                                             HandleVector(args, 1));
        return isolate->Throw(*error);
 }

很明确,在非严格模式下,这里就是返回undefined.但为什么局部的赋值语句的返回值,没有遵守ES的赋值语句的执行过程.而是对中间的表达式进行了求值.并当做返回值呢?这显然是不合理的.
 
 
 
 

注5:  逻辑运算 ToObject的作用就是,如果允许,则把目标转换成一个object.并返回. 规则很简单. 如果是 undefined,或null.抛出异常,如果是一个object,则不发生转换.如果是类型是String,Number,Boolea. 则调用其对应的构造器,创建一个包装对象.  但实际上.Object.prototype.toString 是无法通过类似于 'abc'.toString()来调用的. 其toString方法都被重写了. 比如String.prototype.toString. 所以我们需要这样来调用. {}.toString.call('')或 Object.prototype.toString.call(''). 此处对于ES3来说,ToObject这一步骤在ES3中并没有明文说明.但是浏览器实现的行为,也都是与ES5所描述的,是相同的.这个很好理解了.否则浏览器实现起来就会有问题. 至少一个 'abc' 是不存在 [[Class]]内部属性的,因为他不是一个对象.

 
 
 

注6: 这里比较纠结.因为new Object(host object)的结果是依赖实现的.就是说返回啥,ES没有定义.完全看宿主环境实现.但绝大多数实现(我所知道的,测试过的)都是, 这个host object自身. 那么我们在一般情况下,都可以理解为,如果 O 是一个宿主对象.

 
 
 

注7: 第二点,是指对于早期版本,比如ES3来说 1和2的步骤是反过来的.但是我个人根本没有看出,更改顺序有什么意义. 对于toString(V)的过程.抛出异常的可能性微乎其微.所以我觉得老版本的顺序更加合理.而对于老版本来说,this的值是不可能为null 或 undefined.的,所以不可能有相关的异常出现.但就实现上来说.Safari似乎有些问题:

'use strict';
alert({}.hasOwnProperty.call(null,'a'));

//无论是否在严格模式. Chrome,IE9,FF4+ 都抛出异常. 而Safari5一律返回false.这是不合理的. 这个问题产生的原因,大概和Safari5不支持严格模式有关.所以其总是保证this有一个值有关. 参考:

'use strict';
function () {return this;}(); //Safari5 中this 仍然指向 global
 
 
 
 
 

注8: 这里又尼玛没有明确一个问题,就是当this是 null或undefined时的行为. 参考下面的代码:

 
'use strict';  //开启严格模式
alert({}.isPrototypeOf.call(undefined,undefined));

非严格模式,总是会保证一个执行环境相关联的this的值是一个对象. 比如指向global, 但是严格模式中,this的值就可能是null 或 undefined.那么ToObject(undefined),是一定要抛出异常的.
根据注7的部分实现. 发现Firefox在这里的处理,不符合预期. 你应该抛出异常啊伙计...Safari不抛我可以理解.你又在搞什么啊,混蛋?.
 
 
 
 
 
 
 
 
posted @ 2011-08-22 18:52  Franky  阅读(2665)  评论(2编辑  收藏  举报