面向对象
1.什么是对象?
对象是一个整体(相当于是一个盒子,对外是封闭的),对外提供了一些操作。
2.什么是面向对象?
使用对象时,只关注对象提供的功能,并不关注内部的细节。比如JQuery
3.面向对象是一种通用的思想,并非只有编程中能用,任何事情都可以用。
4.JS中的面向对象
(1)面向对象编程(OOP)的特点
抽象:抓住核心问题(比如,把一个人填写表单提交到数据库,有用户名,密码,身高等等,这样,一个人就变成数据库里面的一条数据记录)
封装:不考虑内部的实现,只考虑功能的使用(从外面看不到里面,留了几个功能在外面)
继承:从已有的对象上,继承出新的对象(不改变原有的对象)就是继承属性和方法,先执行父类的构造函数,再添加子类的属性
特性: -多重继承(有多个父类)
-多态(父类和子类具有相同的操作,但是不是那么一样)
(2)对象的组成
方法——函数:过程,动态的(方法和函数也是同一级别,如果是属于某个对象的函数,那就是方法。)
属性——变量:状态,静态的(变量和属性是同一级别的,如果是自由的,不属于任何对象的,就是变量。但如果是属于某个对象的就是属性了。)
栗子:
var arr=[1,2,3,4,5]; //arr是对象 var a=6; //变量 arr.a=6; //属性 function show(){ //函数 alert('a'); } show(); arr.fn=function(){//方法 alert('a'); } fn();
(3)为对象添加方法和属性
this详解,事件中处理this的本质
-window(全局函数,变量本身就属于window上的方法和属性)
-this——函数属于谁(谁发生事件,this就指向谁)
oDiv.onclick=function(){ alert(this); //this指向oDiv }
过去给一个物体添加事件,本质上就是给其添加方法。
this表示当前的方法,属于谁。如上面的栗子,onclick这个方法属于oDiv,所以this就是oDiv。
window
function show(){
alert(this);
}
show();//显示的是window,也就是说这个this指向的是window
就相当于:
window.show=function(){
alert(this);
}
show();
自然,这个this就是指向window的
同样的关于变量和属性
var a=12;
alert(a); //a是变量
alert(window.a);//a是window的属性
不能在系统对象中随意附加方法、属性,否则会覆盖已有方法,属性。
(4)工厂方式
用工厂方式构造对象
工厂:
1.原料
2.加工
3.出厂
规范:构造函数首字母要大写
function CreatePerson(name,sex)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>工厂方式</title> <script> function CreatePerson(name,sex){//构造函数,作用是构造一个对象 //1.原料,创建空白对象,object几乎是空白对象,可以在其身上添加属性和方法 var obj=new Object(); //2.加工,添加属性和方法 obj.name=name; obj.sex=sex; obj.showName=function(){ console.info("我的名字叫:"+this.name); } obj.showSex=function(){ console.info("我是"+this.sex+"的"); } //3.出厂,现在的Obj中已经包含了属性和方法 return obj; } var p1=CreatePerson('blue','男'); var p2=CreatePerson('leo','女'); p1.showName(); p1.showSex(); p2.showName(); p2.showSex(); </script> </head> <body> </body> </html>
但是,工厂方式也存在着一些问题:
1.没有new,一般构造对象是有new的,比如var arr=new Array();
2.每个对象都有一套自己的函数--浪费资源
解释:
var p1=CreatePerson('blue','男');
var p2=CreatePerson('leo','女');
console.info(p1.showName==p2.showName);//false
发现这两个函数对象并不相同,其实这是匿名函数在作怪,因为匿名函数没写一次function,就会诞生一个函数对象。
var a=function(){
alert('abc');
}
var b=function(){
alert('abc');
}
alert(a==b);//false
/*其实是匿名函数
上面的和下面的是一致的*/
var a=new Function("alert('abc')");
var b=new Function("alert('abc')");
/*每写一次function就会诞生一个函数对象*/
(5)解决工厂方式的问题的方法
前面说到this表示当前方法属于谁,但是在有一种情况下会失效,就是函数前面有new 的时候。
function show(){
console.info(this);
}
show();//这个this就是window
new show();//新创建的对象,这个this就是Object,因为函数前面加了个new,系统会自动创建var this=new Object();
1.针对没有new的问题的解决方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>工厂方式</title> <script> function createPerson(name,sex){//构造函数,作用是构造一个对象 //假想的系统内部工作流程var this=new Object(); //2.加工,添加属性和方法 this.name=name; this.sex=sex; this.showName=function(){ console.info("我的名字叫:"+this.name); } this.showSex=function(){ console.info("我是"+this.sex+"的"); } /*假想的系统内部工作流程 return obj;*/ } var p1=new createPerson('blue','男'); var p2=new createPerson('leo','女'); p1.showName(); p1.showSex(); p2.showName(); p2.showSex(); </script> </head> <body> </body> </html>
2.针对每个对象都有一套自己的函数--浪费资源的问题的解决方法
prototype(原型)
在CSS中
class 改变一类元素的样式<----->类似于 prototype(原型),给一类元素添加属性和方法
行间样式 改变一个元素的样式,优先级更高<----->类似于给一个对象加方法
在JS中
类,就相当于一个,模子,作用就是用来生产蛋糕的。
对象(实例),就相当于一个,蛋糕,作用就是用来吃的。
对于 var arr=new Array();
Array(类),不具备实际功能,只能用来构造对象。
arr(对象),真正有功能的东西,被类给构造出来。
栗子:
不可能在arr1.sum=function(){},arr2.sum=function(){}
Array.prototype.sum=function(){},这里就是给类的原型添加方法,这一类里面所有的东西都有这个方法了。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>工厂方式1</title> <script> var arr1=new Array(1,2,3,4,5); var arr2=new Array(6,7,8,9,10); Array.prototype.sum=function(){ var result=0; var i=0; for(i=0;i<this.length;i++){ result+=this[i]; } return result; } console.info(arr1.sum()); console.info(arr2.sum()); </script> </head> <body> </body> </html>
原型的一个重要应用:可以扩展系统对象,给它添加一些本不支持的方法。
var arr1=new Array(1,2,3,4,5); var arr2=new Array(6,7,8,9,10); Array.prototype.sum=function(){ var result=0; var i=0; for(i=0;i<this.length;i++){ result+=this[i]; } return result; } console.info(arr1.sum==arr2.sum);//true
发现arr1.sum和arr2.sum竟然相等了,那是因为它们都等于Array.prototype.sum
原型既然可以给系统对象添加方法,也可以可自己创造的函数添加方法(构造函数就是类,类就是构造函数,是一个东西)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>工厂方式</title> <script> function CreatePerson(name,sex){//构造函数,作用是构造一个对象 this.name=name; this.sex=sex; } CreatePerson.prototype.showName=function(){ console.info("我的名字叫:"+this.name); } CreatePerson.prototype.showSex=function(){ console.info("我是"+this.sex+"的"); } var p1=new CreatePerson('blue','男'); var p2=new CreatePerson('leo','女'); p1.showName(); p1.showSex(); p2.showName(); p2.showSex(); console.info(p1.showName==p2.showName);//true </script> </head> <body> </body> </html>
这说明每个对象都同样的函数--节省了资源
总结:
属性:每个对象都各不相同,就放在构造函数里面
方法:所有对象都一样,就用原型
还有一个问题:利用了原型,那里面的this指向的是谁呢?
栗子:
Array.prototype.sum=function(){
this;
}
var arr=new Array();
arr.sum();
/*可以明白了,this就是指向new出来的对象arr*/
总结:
this 永远指向函数运行时所在的对象,而不是函数被创建时所在的对象。匿名函数或不处于任何对象中的函数指向 window
1.如果是call,apply,with,指定的this是谁,就是谁
2.普通的函数调用,函数被谁调用,this就是谁
(5)原型的优先级
给对象加方法比原型优先级高
栗子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>工厂方式2</title> <script> Array.prototype.a=12; var arr=[1,2,3]; console.info(arr.a); arr.a=5; console.info(arr.a); delete arr.a; console.info(arr.a); </script> </head> <body> </body> </html>