一,面向对象编程(OOP)的特点:
抽象:抓住核心问题,
封装:只能通过对象来访问方法,
继承:从已有的对象下继承出新的对象,
多态:多对象的不同形态,目的是灵活的复用,
JS不支持面向对象(半面向对象)
最终目的:方便扩展,灵活复用
一.建立面向对象3步:
1.创建构造函数或类(公有属性):
function Person(name1,gender1){ //声明一个构造函数
this.name=name1; // 把变量变成对象的属性用this
this.gender=gender1;
}
2.通过原型扩展构造函数功能:把函数变成对象的方法(用prototype)
Person.prototype.eat=function(){
console.log('姓名:'+this.name+'性 别:'+this.gender)
}
3.创建实例化对象,通过new
var man=new Person('张三','男');
调用方法:
man.eat();
man.say();
//面向过程中的封装函数-工厂模式,把变化的当成参数传递进去 //缺点:1.没有new,有new 代码可以得到很大简化 2.每个对象都有自己的一个函数showName(),浪费资源 function person(name){ //原料 var obj={}; //加工 obj.name=name; obj.showName=function(){ console.log(this.name); } //出厂 return obj; } var p1= person('小明'); p1.showName(); var p2= person('小王'); p2.showName(); console.log(p1.showName()==p2.showName()) //true 每个对象都有自己的一个函数showName(),浪费资源
二,this.指向问题
关于this的指向-在事件函数里,指向当前调用者,其它一切指向window对象
var oDiv=document.getElementsByTagName('div')[0];
1.1/* oDiv.onclick = function(){ console.log(this) //this当前对象
// 1.2.又套一层函数,this指向window /* oDiv.onclick = function(){ show(); }; function show(){ console.log(this) //this指向window } */
}; */
1.3可在this正常的地方外面存储下 var that1=0; oDiv.onclick = function(){ //this指向 window that1=this; setTimeout(function(){ console.log(that1) },10) };
1.4 如果要用定时器里如果有this,this指向也是window,可在外存储下this
/* oDiv.onclick = function(){ setTimeout(function(){ console.log(this) //this指向 window },0) }; */
三:原型prototype
/2.oop里创建对象 //2.1构造函数:放的公有属性(共用的) /* function Person(){ this.name="张三" ; //this理解为公有的,谁new我指向谁 this.say=function(){ console.log(this.name+'会说话') } } var person=new Person(); //2.2 :调用的对象:new 构造函数 person.say(); //直接调方法 console.log(person.name) //直接调属性*/ //3.传入参数 /* function Person(name){ this.name=name; //this理解为公有的,谁new我指向谁 this.say=function(){ console.log(this.name+'会说话') } } var person=new Person('李四'); //2.2 :调用的对象:new 构造函数 person.say(); //直接调方法 console.log(person.name) //直接调属性 var person1=new Person('强哥'); person1.say(); // 4.prototype 原型,扩展构造函数功能,方法放到原型里-节省内存,性能提高 /*构造函数名.prototype.方法名=function(){ 可以调用属性 }*/ function Person(name1,sex1){ this.name=name1; //this理解为公有的,谁new我指向谁 this.sex=sex1; } Person.prototype.say=function(){ //方法挂载到原型上 console.log(this.name+'会说话,性别'+this.sex) } var person2=new Person('李四','男人'); console.log(person2.name,person2.sex) //调公有属性 person2.say(); //调公用方法 var personH=new Person('昊哥','男孩'); personH.say();
面向对象:6大继承
1,原型继承 将父类的实例对象赋值给子类的原型;私有的公有的都继承为公有的
2,call继承 call方法是函数/类天生自带的一个方法。将父类私有的继承为子类私有的。
3,冒充对象继承 将父类私有的和公有的都继承为子类私有的。 使用for in
for in 可以遍历对象的公有属性 fn 就是公有的
冒充对象继承的案例
4.混合继承 私有的继承为私有的 私有的和公有的再次继承为公有的。
Call继承和原型继承的结合
5.组合继承 私有继承为私有 公有继承为公有
私有继承私有 借助call 公有继承为公有 不能是原型赋值给原型。因为原型是对象,是复合数据类型,是地址赋值给了前者,导致二者指向同一个原型。得克隆。
Js的克隆如何实现 var obj2= Object.create(obj1)
6.中间类继承
面向对象工厂模式
//面向过程中的封装函数-工厂模式,把变化的当成参数传递进去 //缺点:1.没有new,有new 代码可以得到很大简化 2.每个对象都有自己的一个函数showName(),浪费资源 function person(name){ //原料 var obj={}; //加工 obj.name=name; obj.showName=function(){ console.log(this.name); } //出厂 return obj; } var p1= person('小明'); p1.showName(); var p2= person('小王'); p2.showName(); console.log(p1.showName()==p2.showName()) //true 每个对象都有自己的一个函数showName(),浪费资源
三.面试题:将方法写在原型里与将方法写在构造函数里有什么不同
1.把方法写在原型中比写在构造函数中消耗的内存更小,因为在内存中一个类的原型只有一个,而写在类中的方法,实例化的时候会在每个实例中再复制一份,所以消耗的内存更高
所以没有特殊原因,我们一般把属性写到类中,而方法写到原型中
2、构造函数中定义的属性和方法要比原型中定义的属性和方法的优先级高,如果都定义了同名称的属性和方法,构造函数中的将会覆盖原型中的
四:原型连图
qq :1808886962