function Person(){//首先定义一个用于创建对象实例的(构造)函数
this.name = 'linjisong';
this.age = 29;
}
var person = new Person();//调用(构造)函数创建对象实例
console.info(person.age);//29
try{
console.info(age);//为了演示忘记使用new的情况,这里先输出全局的age,由于未定义,抛出异常
}catch(e){
console.info(e);//ReferenceError
}
var person2 = Person();//忘记使用new的情况下,只是普通的函数调用,由于函数没有返回,这里person2就是undefined了
console.info(person2);//undefined
console.info(age);//29,没有使用new,内部的this指向了全局作用域,因为可以在全局访问age了
要避免这种问题,可以修改一下构造函数:
复制代码 代码如下:
function Person(){
if(this instanceof Person)
{
this.name = 'linjisong';
this.age = 29;
}else{
return new Person();
}
}
var person2 = Person();
console.info(person2.age);//29,可以访问person2的age了
console.info(age);//全局环境中没有age的定义了,抛出异常
这个构造函数首先判断this值是否为Person类型,如果不是,就在内部使用new调用,以确保返回的值一定是Person类型实例。这种方式使得重构构造函数成为了可能,也许Boolean()、Number()、String()在实现上就是使用了这种方式来区分是构造函数还是转换函数。如果你在调用Object()时省略new的话,结果也能返回对象,估计也是在后台做了类似处理,同样的情况还有本文后部分要讲的函数类型构造函数Function()。
(5)可能有人会问,既然有对象字面量,何必要用这么复杂的方式来创建对象实例呢,直接写对象字面量不就完了?用对象字面量创建对象实例,根本没有使用什么函数,看来,上面的“每一个对象实例都有一个用于创建这个实例的函数”的说法并不正确。
首先第一个问题,的确,可以使用对象字面量来创建函数,而且也非常简洁,这甚至也是我首先推荐的一种创建方式,但是用这种方式创建对象实例,只能创建单例的实例,对于需要创建多个相同类型的对象实例来说并不适用,然后第二个问题,用对象字面量创建对象,实际上并不是没有相应的构造函数,只是构造函数为Object(),使用对象字面量,后台可能不会去调用new Object(),但创建出的对象仍然有指向这个函数的属性,这可以从下面代码输出中得到验证:
复制代码 代码如下:
var person = {};
console.info(person.constructor===Object);//true
这里的constructor是每个实例对象都有的一个属性,用于保存创建这个对象实例的函数,这就是下面要讲的。
4、对象属性和方法
每一种数据类型都有各自的共性,比如Number类型值都有可以和另外一个Number类型值相加的特性,同样,对象类型的实例也有一些相同的特性,这些特性就体现在它们都包含下面的属性和方法(方法实际上也是一种属性,只是属性的值类型是函数的话,我们也称之为方法):
类别 属性/方法 说明
属性 constructor 指向用于创建当前对象的函数
方法 hasOwnProperty(propertyName) 检查给定的属性是否在当前对象实例中
propertyIsEnumerable(propertyName) 检查给定的属性是否能够是使用for-in语句来枚举
isPrototype(object) 检查传入的对象是否是另一个对象的原型
toLocalString() 返回对象的字符串表示,该字符串与执行环境的地区相对应
toString() 返回对象的字符串表示
valueOf() 返回对象的字符串、数值或布尔值表示,通常与toString()方法返回值相同
注:在《JavaScript高级程序设计(第3版)》第35页中的Constructor将首字母大写了,应该是一个印刷错误。
属性和方法的访问有两种方式:
(1)使用点号(.):如person.name。
(2)使用方括号([]):如person[name],使用这种方式,方括号内部可以是一个变量或者表达式,这使得可以访问名称包含特殊符号的属性和方法。
通过结合for-in和这里的hasOwnProperty (propertyName),我们就可以遍历对象实例自身的属性而不包括从原型链继承而来的属性了:
复制代码 代码如下:
for(var propertyName in object){
if(object.hasOwnPorperty(propertyName)){
//循环处理
}
}
您可能感兴趣的文章: