批量创建对象的方法:
1、工厂模式
需要显示创建对象,并要返回对象,缺点在于无法判断对象类型。
//工厂模式 function createperson(name,age,friends){ var o=new Object(); o.name=name; o.age=age; o.friends=friends; return o; } var person1=createperson('张三',19,['小花','等等']); var person2=createperson('李四',39,['二狗','小明']); console.log(person1); console.log(person2);
2、构造函数模式
没有显示创建对象,直接将属性和方法赋给了this对象,没有return;
要创建对象新实例,会有以下四个步骤:1.创建一个新对象;2.将构造函数作用域赋给新对象;3.执行构造函数代码;4.返回新对象
创建对象新实例要用new操作符,可用instanceof操作符检测对象类型;
缺点在于每次创建新对象时,每个方法都会在每个实例上被重新创建一次;
//构造函数模式 function Person(name,age){ this.name=name; this.age=age; this.run=function(){ console.log('run'); } } var person1=new Person('张三',19); var person2=new Person('李四',39); console.log(person1); person1.run(); console.log(person2); //instanceof检测对象类型 console.log(person1 instanceof Person);//true console.log(person1 instanceof Object);//true
3、原型模式
好处在于可以让所有实例对象共享属性方法
缺点在于无法传参
//原型模式 function Person(){ } Person.prototype.name='zhangsan'; Person.prototype.age=19; Person.prototype.run=function(){ console.log('run'); } var person1=new Person(); var person2=new Person(); console.log(person1); person1.run(); console.log(person1.name===person2.name);//true表明共享 //对象实例不能重写原型中的值 person1.name='wangwu';//实例属性会覆盖原型属性 console.log(person1.name);//wangwu console.log(person2.name);//zhangsan //hasOwnProperty()方法可以检测方法或属性在实例中还是原型中 console.log(person1.hasOwnProperty('name'));//true console.log(person2.hasOwnProperty('name'));//false //in操作符可以检测方法或属性是否存在,无论是在实例中还是原型中 console.log('name' in person1);//true console.log('name' in person2);//true //结合hasOwnProperty()方法与in操作符可以判断属性到底存在于实例中还是原型中 function hasprototypeproperty(object,name){ return !(object.hasOwnProperty(name))&&(name in object); } console.log(hasprototypeproperty(person1,'name'));//false console.log(hasprototypeproperty(person2,'name'));//true //Object.keys()方法可枚举对象上所有实例属性 console.log(Object.keys(Person.prototype));//["name","age","run"] console.log(Object.keys(person1));//["name"] //delete可以删除实例属性 delete person1.name; console.log(person1.name);//zhangsan console.log(person2.name);//zhangsan //更简单的原型语法 Person.prototype.name='zhangsan'; Person.prototype.age=19; Person.prototype.run=function(){ console.log('run'); } //可写成对象字面量形式,但是这种对象形式相当于重写整个原型库,constructor属性改变,慎用! Person.prototype={ constructor:Person,//constructor属性要跟回来! name:'zhangsan', age:19, run:function(){ console.log('run'); } } //原型的动态性,即对原型对象的任何修改都能实时从实例上反映出来,即使先实例对象,后修改原型
4、组合使用构造函数模式和原型模式
构造函数模式用于定义实例属性
原型模式用于定义方法和共享属性
//组合使用构造函数模式和原型模式 function Person(name,age){ this.name=name; this.age=age; } Person.prototype.run=function(){ console.log('run'); }; var person1=new Person('zhangsan',16); console.log(person1);
继承实现的方式
1、原型链继承
//原型链继承 function Animal() { this.type = 'Animal' } Animal.prototype.run = function () { console.log('跑'); }; function Dog(name) { this.name = name; } Dog.prototype.speak = function () { console.log(this.name+'汪汪'); }; Dog.prototype=new Animal();//修改Dog的原型对象为Animal的实例 var dog=new Dog('小花'); console.log(dog.__proto__.constructor);//Animal console.log(dog.type);//Animal console.log(dog instanceof Dog);//true console.log(dog instanceof Animal);//true
原型链继承存在的问题:1.引用类型值会被共享;2.创建子类型的实例时,不能向超类型的构造函数传递参数
//原型链继承存在的问题 //引用类型值会被所有实例共享 function Animal() { this.friends = ['小花','二毛']; } Animal.prototype.run = function () { console.log('跑'); }; function Dog(name) { this.name = name; } Dog.prototype.speak = function () { console.log(this.name+'汪汪'); }; Dog.prototype=new Animal();//修改Dog的原型对象为Animal的原型 var dog1=new Dog(); dog1.friends.push('狗蛋'); var dog2=new Dog(); console.log(dog1.friends);//小花,二毛,狗蛋 console.log(dog2.friends);//小花,二毛,狗蛋
2、使用构造函数继承
子类型借调超类型,用call或apply方法,可传参,但是构造函数继承存在问题在于:1.超类型原型对象上的方法无法为子类型所用;2.因此方法只能写在超类型构造函数中,无代码复用性可言;
//利用构造函数继承,call或apply借调 function Animal() { this.friends = ['小花','二毛']; } Animal.prototype.run = function () { console.log('跑'); }; function Dog(name) { Animal.apply(this); this.name = name; } Dog.prototype.speak = function () { console.log(this.name + '汪汪'); }; var dog1 = new Dog(); dog1.friends.push('狗蛋'); var dog2 = new Dog(); console.log(dog1.friends);//小花,二毛,狗蛋 console.log(dog2.friends);//小花,二毛 dog1.run();
3、组合式继承(伪经典继承)
综合使用原型链继承和构造函数继承,一般可满足开发所用,小问题在于父类属性重复。
//组合式继承 function Animal(friends) { this.friends = friends; } Animal.prototype.run = function () { console.log('跑'); }; function Dog(name, friends) { Animal.call(this, friends); this.name = name; } Dog.prototype.speak = function () { console.log(this.name + '汪汪'); }; Dog.prototype = new Animal(); Dog.prototype.constructor = Dog; var dog1 = new Dog('狗蛋', ['lala','cindy']); console.log(dog1.friends);//Dog
4、寄生式继承
借助一个空的构造函数,实例化出一个对象,作为子类型的原型对象,它的原型对象指向超类型的原型对象,修复constructor,即可。
//寄生式继承 function Animal(friends) { this.friends = friends; } Animal.prototype.run = function () { console.log('跑'); }; function Dog(name, friends) { Animal.call(this,friends); this.name = name; } Dog.prototype.speak = function () { console.log(this.name + '汪汪'); }; function Temp(){} Temp.prototype=Animal.prototype; var o=new Temp(); Dog.prototype=o; Dog.constructor=Dog; var dog1 = new Dog('狗蛋', ['lala','cindy']); console.log(dog1.friends);//Dog dog1.run();