目录
对象创建模式
方式一:Object构造函数模式
先创建空Object对象,再动态添加属性/方法;适用于起始时不确定对象内部数据的场景;缺点是语句太多
var p=new Object();
p.name='tml';
p.age=12;
p.setName=function(name){
this.name=name;
}
p.setName('zy');
console.log(p.name,p.age);//zy 12
方式二:对象字面量模式
使用{ }创建对象,同时指定属性/方法;适用于起始时对象内部数据确定的场景;缺点是如果创建多个对象,有重复代码
var p1={
name:'tml',
age:12,
setName:function(name){
this.name=name;
}
}
var p2={
name:'tml',
age:12,
setName:function(name){
this.name=name;
}
}//创建多个对象代码重复
p1.setName('ly');
console.log(p1.name,p1.age);//ly 12
方式三:工厂模式
通过工厂函数(返回一个对象的函数)动态创建对象并返回;适用于需要创建多个对象的场景;缺点是对象没有一个具体的类型,都是Object类型
function createPerson(name,age){
var obj={
name:name,
age:age,
setName:function(name){
this.name=name;
}
}
return obj;
}
var p1=createPerson('tml',21);
var p2=createPerson('ly',22);
方式四:自定义构造函数模式
自定义构造函数,通过new创建对象;适用于需要创建多个类型确定的对象的场景;缺点是每个对象都有相同的数据,浪费内存
function Person(name,age){
this.name=name;
this.age=age;
this.setName=function(name){
this.name=name;
}
}
function Student(name,price){
this.name=name;
this.price=price;
this.setName=function(name){
this.name=name;
}
}
var p=new Person('tml',21);
var s=new Student('ly',90);
console.log(p instanceof Person);//true
console.log(s instanceof Student);//true
方式五:构造函数+原型
自定义构造函数,属性在函数中初始化,方法添加到原型上;适用于需要创建多个类型确定的对象的场景
function Person(name,age){
// 在构造函数中只初始化一般函数
this.name=name;
this.age=age;
}
Person.prototype.setName=function(name){
this.name=name;//this是实例化对象
}
var p=new Person('tml',21);
console.log(p);
// Person {name: "tml", age: 21}
// name: "tml"
// age: 21
// __proto__:
// setName: ƒ (name)
// constructor: ƒ Person(name,age)
// __proto__: Object
继承模式
原型链继承:
1.定义父类型构造函数
2.给父类型的原型添加方法
3.定义子类型的构造函数
4.创建父类型的对象赋值给子类型的原型
5.将子类型原型的构造属性设置为子类型
6.给子类型原型添加方法
7.创建子类型的对象:可以调用父类型的方法
关键:子类型的原型为父类型的一个实例对象
// 父类型
function Supper(){
this.supProp="Supper property";
}
Supper.prototype.showSupperProp=function(){
console.log(this.supProp);
}
// 子类型
function Sub(){
this.subProp="Sub property";
}
// 子类型的原型为父类型的一个实例对象
Sub.prototype=new Supper();
// (原本Object是sub原型的父亲,现在supper的原型是父亲了,Object是祖父,一样可以访问到)
Sub.prototype.showSubProp=function(){
console.log(this.subProp);
}
var sub=new Sub();
sub.showSupperProp();//Supper property
sub.showSubProp();//Sub property
console.log(sub.constructor);//Supper(){this.supProp="Supper property";}
// 实例的constructor来自实例指向的prototype对象中的constructor
// 让子类型原型的constructor指向子类型
Sub.prototype.constructor=Sub;
console.log(sub.constructor);//Sub(){this.subProp="Sub property";}
/**弹幕
* 1. 这里可以补充一下constructor 的作用:constructor中文就是构造函数
* 2. 其作用是让某个构造函数产生的 所有实例对象(比如f) 能够找到他的构造函数(比如Fun),用法就是f.constructor
* 3. 此时实例对象里没有constructor 这个属性,于是沿着原型链往上找到Fun.prototype 里的constructor,并指向Fun 函数本身
* 4. 由于这里的继承是直接改了构造函数的prototype 的指向,所以在 sub的原型链中,Sub.prototype 没有constructor 属性,反而是看到了一个super 实例
* 5. 这就让sub 实例的constructor 无法使用了。为了他还能用,就在那个super 实例中手动加了一个constructor 属性,且指向Sub 函数
*/
借用构造函数继承(假继承):
1.定义父类型构造函数
2.定义子类型构造函数
3.在子类型构造函数中调用父类型构造
关键:在子类型构造函数中通用call()调用父类型构造函数
function Person(name,age){
this.name=name;
this.age=age;
}
function Student(name,age,price){
Person.call(this,name,age);//相当于 this.Person(name,age); 临时让Person成为this的方法调用
// this.name=name;
// this.age=age;
this.price=price;
}
var s=new Student('tml',21,12000);
console.log(s.name,s.age,s.price);
原型链+借用构造函数的组合继承:
1.利用原型链实现对父类型对象的方法继承
2.利用super()借用父类型构建函数初始化相同属性
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.setName=function(name){
this.name=name;
}
Person.prototype.setAge=function(age){
this.age=age;
}
function Student(name,age,price){
Person.call(this,name,age);//为了得到属性
this.price=price;
}
Student.prototype=new Person();//使其能看到父类型的方法
Student.prototype.constructor=Student;//修正constructor属性
Student.prototype.setPrice=function(price){
this.price=price;
}
var s=new Student('tml',18,8000);
s.setAge(21);
s.setPrice(12000);
console.log(s.name,s.age,s.price);//tml 21 12000
(视频:B站尚硅谷)