原文地址:http://www.excelib.com/article/250/show
ECMAScript中object类型的对象有三种创建方式:使用初始化器(Initialiser)创建、使用function创建以及使用Object.create方法创建。
使用初始化器(Initialiser)创建
使用初始化器(Initialiser)创建object对象,也就是直接使用花括号来创建,这种方法在很多地方也叫“字面量”或者“对象字面量”,不过在标准中并不属于“字面量”,而是叫“初始化器(Initialiser)”。
使用初始化器创建对象时直接将属性写到花括号中就行了,属性名和属性值使用冒号“:”分开,不同属性之间使用逗号“,”分割(注意,最后一个属性后面没有逗号),属性的值可以是直接量也可以是object类型对象或者function类型对象,我们来看个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 | var obj = { msg: "obj msg" , //直接量属性 innerObj:{ //object类型对象属性 msg: "innerObj msg" }, logMsg: function () { //function类型对象属性 console.log( this .msg); } } console.log(obj.msg); //obj msg console.log(obj.innerObj.msg); //innerObj msg obj.logMsg(); //obj msg |
这个例子中定义了object类型的对象obj,他包括直接量msg、object类型对象innerObj和function类型对象logMsg三个属性,其中innerObj对象也是通过初始化器(花括号)来定义的。定义完对象之后又分别使用obj对象调用了他的三个属性。
object对象调用属性有两种方法:1、直接使用点操作符调用;2、使用方括号来调用。因为使用方括号没有使用点操作符方便,所以使用点操作符来调用的比较多,不过当属性名为一个变量时则需要使用方括号来调用,比如下面的例子
1 2 3 | var obj = {a:1,b:2,c:3}; var propName = "c" ; console.log(obj[propName]); //3 |
这里的属性名保存在propName变量中,这时就需要使用方括号来调用了。
使用function创建
使用function创建object实例对象我们在前面function中已经讲过了,是使用new关键字来创建的,而且创建出来的对象还可以使用function的prototype属性对象中的属性,具体的内容我们这里就不再重述了。
使用Object.create方法创建
还有一种创建object类型对象的方式,那就是使用Object.create来创建。Object是ECMAScript中内置的一个function类型的对象,create是Object对象的一个属性方法,其作用是根据传入的参数创建object类型的对象,create方法的调用语法为
Object.create(prototype, [ propertiesObject ])
这里的第一个参数prototype是创建出的对象所对应的prototype,也就是相当于使用function创建时function中的prototype属性对象,创建出来的object对象实例可以直接调用。
第二个参数propertiesObject为属性描述对象,是可选参数,属性描述对象是object对象类型,它里面的属性名会成为创建出来对象的属性名,属性值为属性的描述对象,其中包含属性的特性,属性的特性我们后面会详细讲解,这里大家只要知道其中的value就是属性值就可以了,我们来看个例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | var obj = Object.create( // prototype { type: "by create" }, // propertiesObject { color: { value: "red" , enumerable: true }, size: { value: "37" , enumerable: true } } ); console.log(obj.type); // by create console.log(obj.color); // red console.log(obj.size); // 37 console.log(Object.getOwnPropertyNames(obj)); // ["color", "size"] |
这里使用Object.create创建了一个obj对象,第一个参数prototype中有一个属性type,第二个参数propertiesObject有两个属性:color和size,创建出来的obj对象这三个属性都可以使用,不过自己其实只有两个属性,prototype中的type属性虽然obj可以调用,但是并不属于obj所有,使用Object.getOwnPropertyNames方法就可以获取到obj自己所拥有的属性。
另外,需要注意的一点是使用初始化器(花括号)和function创建出来的对象都可以调用Object的prototype属性对象中的属性,也就是说那两种方法创建出来的对象首先会拥有公共的prototype,然后如果是使用function创建的对象还可以调用function的prototype中的属性,而且即使function的prototype为null,创建出来的对象也可以调用Object的prototype中的属性,但是使用Object.create创建对象时如果第一个参数为null,那么他创建出来的对象就不可以调用Object的prototype中的属性了,我们看下面的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // 使用初始化器创建对象braceObj var braceObj = {} // 使用function创建对象functionObj function F(){} F.prototype = null ; var functionObj = new F(); // 使用create方法创建对象createObj var createObj = Object.create( null ); console.log(braceObj.toString()); //[object Object] console.log(functionObj.toString()); //[object Object] console.log(createObj.toString()); //抛出方法没找到异常 |
这里的toString方法是Object的prototype属性中的一个方法,如果创建出来的对象可以调用toString方法就说明可以调用Object的prototype属性对象中的方法,否则就是不可以调用。从这个例子中可以看出使用花括号和function创建的对象都可以调用,而且即使将function的prototype设置为null,创建出来的对象也可以调用,但使用Object.create创建出来的对象如果其prototype参数为null就不可以调用了。
多知道点
Object的prototype属性对象里面都有什么
Object的prototype属性对象在ECMAScript5.1和ECMAScript2015中都规定有constructor、toString ( )、toLocaleString ( )、valueOf ( )、hasOwnProperty (V) 、isPrototypeOf (V)和propertyIsEnumerable (V)七个属性,其中constructor会默认指向创建对象的function,其他六个是方法,我们分别来看一下。
toString:这是六个方法中最常使用的方法,他可以将对象转换为字符串,不同类型的对象可能会重新自己的toString方法,比如Array的toString方法会将其所包含的元素使用逗号连接起来组成字符串并返回、Date的toString方法会返回Date的时间字符串,普通object类型对象会返回[object Object];
toLocaleString:toLocaleString方法会使用本地化格式来生成字符串,特别是时间日期类型和数字类型;
valueOf:会返回原始值,比如Date类型对象是通过数字来保存的,所以当Date类型对象调用valueOf时就会获得相应的数字;
hasOwnProperty:判断是否包含指定属性,注意,这里判断的是对象本身是否包含指定的属性,不包括创建对象的function对象的prototype属性中的对象;
isPrototypeOf:判断是不是另一个对象所对应的prototype对象;
propertyIsEnumerable:判断某个属性是否可以枚举,关于属性的枚举我们到属性的特性一节再详细介绍。
下面我们来看例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | function log(msg){ console.log(msg); } var array = [1,3,5]; var date = new Date(); log(array.toString()); // 1,3,5 log(date.toString()); // Tue Jun 09 2015 10:48:10 GMT+0800 log(date.toLocaleString()); // 2015/6/9 上午10:48:10 log(date.valueOf()); // 1433818090599 从1970年到现在的毫秒数 var Obj = function (){ this .msg = "hello" ; this .say = function () { log(msg); } } var proto = {color: "red" }; Obj.prototype = proto; var obj = new Obj(); log(obj.constructor); // Object() log(obj.hasOwnProperty( "msg" )); // true log(obj.hasOwnProperty( "color" )); // false,color在Obj的prototype中,obj虽然可以调用但是不拥有 log(obj.propertyIsEnumerable( "msg" )); // true log(obj.isPrototypeOf(proto)); // false log(proto.isPrototypeOf(obj)); // true |
从这个例子中我们就可以理解Object的prototype属性对象中的七个属性的用法了,需要注意的是因为我们给Obj的prototype属性赋值为了proto对象,所以创建出来的obj对象调用constructor属性就不会返回我们的Obj对象而是返回Object对象了,我们可以通过对proto对象进行修改来修复这一问题,修复代码如下
1 2 3 4 5 6 | var proto = {color: "red" }; proto.constructor = Obj; Obj.prototype = proto; var obj = new Obj(); console.log(obj.constructor); // Obj |
这时就可以正确地输出constructor了。
上面是标准中规定的Object的prototype属性对象中的七个属性,但是不同的浏览器还会有一些自己的扩展,比如在FireFox中就扩展到了14个属性:constructor、toSource、toString、toLocaleString、valueOf、watch、unwatch、hasOwnProperty、isPrototypeOf、propertyIsEnumerable、__defineGetter__、__defineSetter__、__lookupGetter__和__lookupSetter__,不过新增的属性并不是通用属性,在别的浏览器中可能并没有定义,如果使用的话就可能会造成浏览器不兼容的问题,我们应该尽量少使用,如果非要用就要在使用前先判断浏览器是否支持。