首先,在js里,对象是由函数构建而成的。
创建对象的几种模式
1.工厂模式
function person(name,age,job) { var o=new Object(); o.age=age; o.name=name; o.job=job; o.sayname=function () { console.log(this.name); } return o; } var person1=person("1",1,"1"); person1.sayname();
//检测对象什么类型
console.log(person1 instanceof Object);//trueconsole.log(person1 instanceof person);//FALSE
工厂模式解决了创建多个相似对象的问题,但是不知道如何知道一个对象的类型。
2.构造函数模式
function person(name,age,job) { this.name=name; this.age=age; this.job=job; this.sayname=function () { console.log(this.name); } } var person1=new person("1",1,"1"); person1.sayname();
console.log(person1 instanceof Object);//检测对象什么类型console.log(person1 instanceof person);//都是true
与工厂模式不同点:
1.没有显式创建对象
2.属性方法赋予给this对象
3.没有return语句
创建对象使用new时,调用构造函数会有一下几步
1.创建一个新对象
2.构造函数的作用域给新对象
3.执行构造函数的代码
3.返回新对象
任何函数,只要通过new来调用,那么他就可以作为构造函数,他的问题就是每个方法要在每个实例上重新构造一遍
上述sayname方法等同于下
this.sayname=new function("console.log(this.name)")
如果再新建对象person2
console.log(person1.sayname==person2.sayname) ;结果是FALSE
当然我们可以把这些函数放在外面,在构造函数内调用,但是这样就毫无封装性。3. 3.原型模式每个函数都有一个prototype属性
function person() { } person.prototype.name="1"; person.prototype.age=12; person.prototype.sayname=function () { console.log(this.name); } var person1=new person(); person1.sayname(); //1 var person2=new person(); person2.sayname(); //1
好处:让所有实例共享他的属性和方法
如果实例添加一个新属性且新属性与原型中的属性重名,那么就在实例中创建该属性,该属性会屏蔽掉原型中的该属性。
function person() { } person.prototype.name="1"; person.prototype.age=12; person.prototype.sayname=function () { console.log(this.name); } var person1=new person(); person1.name="2"; person1.sayname(); delete person1.name;//删除新添加的属性 person1.sayname(); //会显示原型里的属性
接下来是重点:
function person() { } person.prototype={ name:"1", age:12, sayname:function () { console.log(this.name); } } var friend=new person(); console.log(friend instanceof Object); //true console.log(friend instanceof person); //true console.log(friend.constructor == person); //false console.log(friend.constructor == Object);//true person.prototype.sayhi=function () { console.log("hi"); } friend.sayhi(); //hi
instanceof 判断一个变量是不是属于一个变量的实例。
constructor 属性返回对创建此对象的数组函数的引用。
friend是person的一个实例
所以向person中添加 Protype时friend也可以引用。
原型的动态性:
function person() { } var friend=new person(); console.log(friend instanceof Object); //true console.log(friend instanceof person); //true console.log(friend.constructor == person); //true console.log(friend.constructor == Object); //true console.log(friend.constructor); //【Function:person】 person.prototype={ constructor:person, name:"1", age:12, sayname:function () { console.log(this.name); } } friend.sayname();//报错
当执行到最后一句时会报错,原因是我们重写了整个原型对象。
大致就是这个样子,person原本指向person Protype,在重写原型对象后指向了new person Protype,但是friend仍然指向原来的person Protype,所以出现错误。
原型模式的问题:
function person() { } person.prototype={ constructor:person, friends:["a","b","c"] } var person1=new person(); var person2=new person(); person1.friends.push("d"); console.log(person1.friends);//【a,b,c,d】 console.log(person2.friends);//[a,b,c,d]
会发现person2的friends也会有d
针对包含引用类型值的属性:
原因就是这个样子,person1引用Protype,所以修改person1就修改了person2。
最常用的创建对象对象
--------------------组合使用构造函数模式和原型模式
因为构造函数模式new时会创建一个新对象,而原型模式就是用于定义方法和共享属性。
function person(name) { this.name=name; this.friends=[‘a‘] } person.prototype={ constructor:person, sayname:function () { console.log(this.name); } } var person1=new person("1") ; var person2=new person("2") ; person1.friends.push("b"); console.log(person1.friends); console.log(person2.friends); console.log(person1.friends==person2.friends); console.log(person1.sayname==person2.sayname);
结果:
[ ‘a‘, ‘b‘ ]
[ ‘a‘ ]
false
true
到这相信大家对JS构建对象有了一定的了解了!