5.1 创建object类型对象的三种方式
ES中object类型的对象大致有三种创建方式:直接使用花括号创建、使用function创建以及使用Object.create方法创建。
5.1.1 直接使用花括号创建
使用花括号创建对象时直接将属性写到花括号中就可以了,属性名和属性值使用冒号(:)分割,不同属性之间使用逗号(, )分割(注意,最后一个属性后面没有逗号),属性的值可以是直接量,也可以是object类型对象或者function类型对象。我们来看下面的例子。
var obj = { v:6, //直接量属性 innerObj:{ //object类型对象属性 v:7 }, logV: function () { //function类型对象属性 console.log(this.v); } } console.log(obj.v); //6 console.log(obj.innerObj.v); //7 obj.logV (); //6
这个例子中定义了object类型的对象obj,它包括直接量v、object类型对象innerObj以及function类型对象logV三种属性,其中innerObj对象也是通过花括号来定义的。使用花括号定义完对象之后又分别使用obj对象调用了它的三个属性。
object对象调用属性有两种方法:直接使用点操作符调用;使用方括号调用。因为使用方括号没有使用点操作符方便,所以一般使用点操作符调用的比较多,不过当属性名为一个变量时则只能使用方括号来调用,例如下面的例子。
var obj = {a:1, b:2, c:3}; var propName = "c"; console.log(obj[propName]); //3
这个例子中,属性名保存在propName变量中,这时就只能使用方括号来调用了。
5.1.2 使用function创建
关于使用function创建object实例对象,我们在4.4节中已经讲过了,是使用new关键字来创建的,而且创建出来的对象还可以使用function的prototype属性对象中的属性。具体的内容这里就不再重述了。
5.1.3 使用Object.create方法创建
还有一种创建object类型对象的方式,那就是使用Object.create来创建。Object是ES中内置的一个function类型的对象,create是Object对象的一个属性方法,其作用是根据传入的参数创建object类型的对象。create方法的调用语法如下。
Object.create(prototype, [ propertiesObject ])
其中,第一个参数prototype是创建的对象所对应的prototype,相当于使用function创建时function中的prototype属性对象,创建出来的object对象实例可以直接调用。
第二个参数propertiesObject为属性描述对象,是可选参数,用于描述所创建对象的自身属性。属性描述对象是object类型对象,它里面的属性名会成为所创建对象的属性名,属性值为属性的描述对象,其中包含属性的特性(属性的特性我们后面会详细讲解,这里大家只要知道其中的value就是属性值就可以了)。我们来看下面的例子。
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对象来说,这三个属性都可以使用,但其自身其实只有两个属性。虽然obj可以调用prototype中的type属性,但是并不属于obj,使用Object.getOwnPropertyNames方法就可以获取obj自己所拥有的属性。
另外,需要注意的一点是,使用花括号和function创建的对象都可以调用Object的prototype属性对象中的属性。即这两种方法创建出来的对象首先会拥有公共的prototype,然后使用function创建的对象还可以调用function的prototype中的属性,而且即使function的prototype为null,创建的对象也可以调用Object的prototype中的属性。但是,使用Object. create创建对象时,如果第一个参数为null,那么它所创建的对象将不可以调用Object的prototype中的属性。我们来看下面的例子。
//使用花括号创建对象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创建的对象都可以调用tostring方法,而且即使将function的prototype设置为null,创建出来的对象也可以调用,但使用Object.create创建出来的对象,如果其prototype参数为null就不可以调用了。
多知道点
Object的prototype属性对象里面都有什么
Object的prototype属性对象在ES5.1和ES2015中都规定了constructor、toString ( )、toLocaleString ( )、valueOf ( )、hasOwnProperty (V) 、isPrototypeOf (V)和propertyIsEnumerable (V)7个属性,其中,constructor会默认指向创建对象的function,其他6个是方法,分别介绍如下。
▯ toString:这是6个方法中最常使用的方法。它可以将对象转换为字符串,不同类型的对象可能会重写自己的toString方法。例如,Array的toString方法会将其所包含的元素使用逗号连接起来组成字符串并返回、Date的toString方法会返回Date的时间字符串等,普通object类型对象会返回[object Object]。
▯ toLocaleString:会使用本地化格式来生成字符串,对于时间日期类型和数字类型的用处较大。
▯ valueOf:会返回原始值。例如,因为Date类型对象是通过数字来保存的,所以当Date类型对象调用valueOf时就会获得相应的数字。
▯ hasOwnProperty:判断是否包含指定属性。注意,这里判断的是对象自身是否包含指定的属性,不包括创建对象的function对象的prototype中的属性。
▯ isPrototypeOf:判断某个对象是否是另一个对象所对应的prototype对象。
▯ propertyIsEnumerable:判断某个属性是否可以枚举。关于属性的枚举我们到属性的特性一节再详细介绍。
例如下面的例子。
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 092015 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属性对象中7个属性的用法了。需要注意的是,因为将Obj的prototype属性赋值为proto对象,所以创建的obj对象在调用constructor属性时就不会返回Obj对象而是返回Object对象。可以通过对proto对象进行修改来修复这一问题,代码如下。
var proto = {color: "red"}; proto.constructor = Obj; Obj.prototype = proto; var obj = new Obj(); console.log(obj.constructor); //Obj
这时就可以正确地输出constructor了。
上面所介绍的是标准中所规定的Object的prototype属性对象中的7个属性,但是不同的浏览器还会有一些自己的扩展。例如,在Firefox中就扩展到14个属性:constructor、toSource、toString、toLocaleString、valueOf、watch、unwatch、hasOwnProperty、isPrototypeOf、propertyIsEnumerable、_ _defineGetter_ _、__defineSetter_ _、_ _lookupGetter_ _和_ _lookupSetter_ _。但是,新增的属性并不是通用属性,其他浏览器中可能并没有定义,如果使用则很可能造成浏览器不兼容的问题,因此应该尽量少使用。如果非要用,那么最好在使用前先判断浏览器是否支持。