1、虽然Object的构造函数和对象字面量都可以用来创建单个对象,但这些方式有个明显的缺点,使用同一个接口创建很多对象,会产生大量重复的代码。为了解决这个问题,人们开始使用工厂模式。
function createPerson(name,age){ var o=new Object(); //内部创建对象 o.name=name; o.age=age; return o; //每调用一次,会返回一个新的o; } var person1=createPerson("nicole",24); //直接调用函数,没有使用new操作符。 var person2=createPerson("iwen",35);
解决了代码重复的问题,但是没有类的概念,创造出的多个实例无法识别所属对象。
2、构造函数模式。 构造函数类似与JS原生的Array,Object,Number等。为开发人员自行定义,具有属性&方法。
function Person(name,age){ this.name=name; //没有new一个Object,但实际上已自动new了 this.age=age; this.sayName=function(){ alert(this.name); } //没有return对象,但实际上也自动返回了,this代表每次新生成的实例对象。 } var person1=new Person("nicole",24); //使用new Person() var person2=new Person("iwen",35);
在调用部分,var person1=new Person("nicole",24); 经历了以下4个步骤:
(1)创建一个新对象
(2)将构造函数的作用域赋给新对象(this指向新对象)
(3)执行构造函数中的代码(为新对象添加属性)
(4)返回新对象
以上两个实例person1&person2分别保存着Person的不同实例,这两个对象都有一个constructor属性(不可枚举,enumerable=false),该属性指向Person
console.log(person1.constructor==Person) //true console.log(person2.constructor==Person); //true console.log(person2.constructor==person1.constructor); //true
对象的constructor属性最初是用来标识对象类型的,但是提到检测对象类型,还是instanceof可靠一些。以上person实例及时Person类型,又是Object类型。
3、原型模式
我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
创建了构造函数后,其原型对象默认只会取得constructor属性(指回构造函数),其余的方法都是从Object继承而来。
通过构造函数访问原型使用:Person.prototype;
通过实例对象访问原型则使用:person1.constructor.prototype; (person1.constructor指向构造函数Person)
而通过实例访问原型,则是通过实例下的[[prototype]]指针,在浏览器里一般表现为_proto_
但实际实例与原型之间的联系并不是通过Person,而是通过实例自身的__proto__属性:
所以构造函数&实例&原型的关系图可以表示为如下:
在调用读取时,会先找实例中是否有该属性方法,如果没有才会去原型中找。
使用hasOwnProperty()可以检测一个属性是否存在实例中,如果实例中存在,返回true,否则返回false:(如果实例&原型中都存在,返回true,因为实例中有,便会使用实例中的属性)
console.log(person1.hasOwnProperty("name")); //true console.log(person1.hasOwnProperty("sayName")); //false
使用in可以检测实例或原型中是否有某属性。有便返回true。所以根据这两点,自定义函数检测原型中是否有某属性:
function hasPrototypeProperty(Object,name){ return !Object.hasOwnProperty(name)&&(name in Object) } console.log(hasPrototypeProperty(person1,"name")); //false console.log(hasPrototypeProperty(person1,"sayName")); //true
循环遍历对象:
在使用for in 循环时,返回的是所有能通过对象访问的,可枚举的属性,包括实例&原型。
for(var i in person1){ console.log(i); //name,age,sayName }
使用Object.keys(object),返回object对象所有可枚举属性的字符串数组,原型实例分开。
var result=Object.keys(person1); console.log(result); //["name", "age"] var resultP=Object.keys(Person.prototype); console.log(resultP); //["sayName"]
使用Object.getOwnPropertyNames()可遍历出不可枚举的属性,实例原型分开。
var result1=Object.getOwnPropertyNames(person1); console.log(result1); // ["name", "age"] var result2=Object.getOwnPropertyNames(Person.prototype); console.log(result2); // ["constructor", "sayName"],constructor 为不可枚举的属性。