一张图概括为:
图片很大,可以调整分辨率在放大看,或者保存图片后看
详细内容:
简单直接创建对象:
好处:简单,方便
弊端:无法做到量产
var obj={
name:"张三",
age:16,
eat:function(){
console.log(this.age + "岁的" + this.name + "正在吃饭");
}
}
console.log(obj);//{name: '张三', age: 16, eat: ƒ}
obj.eat();//16岁的张三正在吃饭
运行结果图:
因为该方法无法量产对象,所以把对象用函数包一下就变成了工厂模式
工厂模式:
好处:快速量产
弊端:无法检测对应类型
function createObj(name,age){
var obj=new Object();//new 一个对象
obj.name=name;
obj.age=age;
obj.eat=function(){
console.log(this.age + "岁的" + this.name + "正在吃饭");
}
return obj;
}
var obj=createObj("李四",17);
console.log(obj);//{name: '李四', age: 17, eat: ƒ}
obj.eat();//17岁的李四正在吃饭
运行结果图:
instanceof 检测对应的数据类型 (是否为对应类 所产生的实例化对象) ,如果是简单数据类型(数值,字符,布尔),必须使用 new 类 来创建才能检测成功
使用方法: 实例化对象 instanceof 数据类型
例:
var a=9;
console.log(typeof a);//返回a的数据类型为number,说明a是number数据类型
console.log(a instanceof Number);//实例化对象a instanceof 数据类型
//a是否是由Number产生的实例化对象
运行结果:
因为number属于简单数据类型,不用new来创建,所以检测结果是false
所以现在用new创建,重新检测
var a=new Number(9);
console.log(a instanceof Number);
运行结果:
检测成功了,
现在用工厂模式分别创建一个学生对象和一个教师对象,在检测实例化对象是基于学生还是教师创建的
//学生
function student(name,age){
var obj=new Object();//new 一个对象
obj.name=name;
obj.age=age;
obj.learning=function(){
console.log(this.age + "岁的" + this.name + "正在写作业");
}
return obj;
}
var w=student("王五",18);
console.log(w);//{name: '王五', age: 18, learning: ƒ}
w.learning();//18岁的王五正在写作业
//教师
function teacher(name,age){
var obj=new Object();//new 一个对象
obj.name=name;
obj.age=age;
obj.teaching=function(){
console.log(this.age + "岁的" + this.name + "正在上课");
}
return obj;
}
var t=teacher("赵六",18);
console.log(t);//{name: '赵六', age: 18, teaching: ƒ}
t.teaching();//18岁的赵六正在上课
//检测学生实例化对象 w 是否是由 函数 创建的
console.log(w instanceof Function);//false
//检测学生实例化对象 w 是否是由 对象 创建的
console.log(w instanceof Object);//true
//只能检测出这个实例化对象属于对象,但是不知道是老师,还是学生
因为无法检测对应类型,所以要把工厂模式改为构造函数,即:
1,在函数外部new一个空对象,
2,再利用函数的this指向性,让函数中的this指向空对象,
3,最后在把对象返回出来(对象赋给变量)
构造函数:
好处:量产,解决了 工厂模式 无法检测类型的问题
弊端:同样的方法会开辟不同的空间,导致造成大量的内存消耗
注意:
该方法是模拟其他语言中的 类,但是原生js中没有类这个概念,所以用构造函数模拟
什么是类? 描述一系列相同类型事物的总称 例如:人类 禽类 动物 植物
构造函数的 函数名 首字母要大写 (用于表示你写的是构造函数)
将上面用工厂模式写的学生和教师 改成 构造函数
//学生
function Student(name,age){
this.name=name;
this.age=age;
this.learning=function(){
console.log(this.age + "岁的" + this.name + "正在写作业");
}
}
var w=new Student("王五",18);
console.log(w);//{name: '王五', age: 18, learning: ƒ}
w.learning();//18岁的王五正在写作业
//教师
function Teacher(name,age){
this.name=name;
this.age=age;
this.teaching=function(){
console.log(this.age + "岁的" + this.name + "正在上课");
}
}
var t=new Teacher("赵六",18);
console.log(t);//{name: '赵六', age: 18, teaching: ƒ}
t.teaching();//18岁的赵六正在写作业
//检测学生实例化对象 w 是否是由 教师类 创建的
console.log(w instanceof Teacher);//false
//检测学生实例化对象 w 是否是由 学生类 创建的
console.log(w instanceof Student);//true
为了验证构造方法的弊端:同样的方法会开辟不同的存储空间(占用不同的内存地址)
再通过Student类实例化一个w2对象,看看实例化后的两个对象w和w2是否相等
var w2=new Student("王五",18);
console.log(w2);
w2.learning();
//实例化对象w和w2是否相等
console.log(w==w2);//false
//因为属性都一模一样,所以两个对象应该是相等的才对
//千万不要因为我上面的这句话误导你们,注意一下下面两句话!!!!
//注:普通对象,属性和值一模一样也不会相等!!!!
//但是因为每个对象占有一段独立的内存,所以不相等!!!!
运行结果图:
注:
普通对象,属性和值都一摸一样,在一起比较也不会相等 !!!!!!!
千万千万千万别被我一句话 “应该是相等的才对” 给误导!!!!!
原因也是因为开辟了不同的存储空间
因为构造函数的弊端:同样的方法会开辟不同的存储空间
所以要把方法剥离出来,不放在函数内部,放在函数的原型(prototype)上
函数的原型(prototype)是函数创建的同时默认产生的,用于保存公有的属性或方法
注:实例化对象的原型(__proto__)= 函数的原型(prototype)
原型模式创建对象:
好处:解决了构造函数的弊端(同样的方法会开辟不同的空间,导致造成大量的内存消耗),将共有的方法或者属性 ,写到构造函数的原型 ==对象的原型 上
//学生
function Student(name,age){
this.name=name;
this.age=age;
}
//将learning方法写到函数Student的原型上
Student.prototype.learning=function(){
console.log(this.age + "岁的" + this.name + "正在写作业");
}
var w3=new Student("w3",18);
console.log(w3);//{name: '王五', age: 18, learning: ƒ}
var w4=new Student("w4",18);
console.log(w4);
//函数Student的原型(prototype) 是否等于 实例化对象w的原型__proto__
console.log(Student.prototype==w3.__proto__);//true,说明原型是同一个
//分别调用两个实例化对象的方法
w3.learning();//18岁的w3正在写作业
w4.learning();//18岁的w3正在写作业
//更改w4的原型为正在上课
w4.__proto__.learning=function(){
console.log(this.age + "岁的" + this.name + "正在上课");
}
//现在再调用一下w3的learning方法看看是什么
w3.learning();//18岁的w3正在上课
运行结果图:
原型创建对象到此结束。
如果不是很懂原型是什么可以单击下面的链接,看一下关于原型链图的讲解