1、面向对象:在程序中都是用一个对象来描述现实中一个具体的东西
现实中任何一个东西都包含属性和功能:
属性——描述一个东西特点的变量,一个值
功能——东西可以执行的操作
(1)什么是对象?
封装多个数据和方法的存储空间
(2)什么是自定义对象?
封装现实中一个东西的属性和功能的存储空间。
注意:
a、现实中东西的属性——对应对象中的属性变量
b、现实中东西的功能——对应对象中的方法
2、创建自定义对象:3种
a、var obj={'属性名1':值1,
'属性名2':值2,
'功能名1':function(){...}
};
js中一切都是对象,所有对象底层都是hash数组
注意:项a方法类似于封装,在程序开发中用的较多。
b、var obj=new Object(); //创建一个空对象
obj.属性名=值;
obj.方法名=function(){...this.属性名...}
c、利用构造函数——反复创建相同结构的对象
构造函数:描述一类对象结构的特殊函数
分为2步:
a、定义构造函数
function 构造函数名|类型名(属性参数1,属性参数2){
this.属性名=属性参数1;
//在当前正在创建的对象中添加一个属性名
//赋值为属性参数1的值
...
this.方法名=function(){
...this.属性名...
}
}
b、利用构造函数创建对象
var obj=new 构造函数名|类型名(属性值1,...)
new:1、创建一个空对象,new obj={ };
2、用空对象,调用构造函数
构造函数在空对象中添加属性和方法
3、设置新对象的_proto_指向构造函数的prototype对象
4、返回新对象的地址
//先定义构造函数
function Student(sname,age){
this.sname=sname;
this.age=age;
this.intSelf=function(){
alert("I'm"+this.sname+"I'm"+this.age);
}
}
var lilei=new Student("Li Lei",12);
(1)属性:如何访问?(2种)
obj.属性名 obj["属性名"]
注意——若访问对象中不存在的属性下标,不会出错,但是会返回undefined
(2)如何判断某个对象是否包含指定成员——3种?
a、obj.hasOwnProperty("");
如果找到,返回true,否则返回false
b、“属性名” in 对象
如果找到,返回true,否则返回false
c、直接使用obj.属性名作为条件:
arr.indexOf==undefined
若不包含,返回undefined——false;
若包含,返回值或function——false
(3)this关键字
方法:如何在方法中,访问当前对象自己
this关键字:运行时,指定正在调用方法的对象(.前的对象)
this本质是window下唯一的一个指针,指向当前正在调用方法的对象。
如何在方法内,访问当前对象自己的属性:this.属性名
注意——
(1)this和定义在哪无关,仅和调用时使用的当前对象有关
(2)所有无主的赋值,都是默认了window对象
(window.)a=100; //全局变量,this——>window
案例1:在匿名函数中有this关键字
var a=100;
(function(){
var a=99;
console.log(this.a);
})(); //100
解析——
由于在匿名函数中用了this关键字,即当前this指向window对象,作为全局变量,所以为“100”,作为全局变量输出。
案例2:在匿名函数中无this关键字
var a=100;
(function(){
var a=99;
console.log(a);
})(); //99
解析——由于在匿名函数中没有用this关键字,所以不用指向外部全局变量,仅仅是作为局部变量输出,即为“99”。
this关键字——面试题
/*笔试题*/
//this——>window
var a=2;
//this—->window
function fun(){
console.log(this.a);
}
//this——>window
var o={a:3,fun:fun}; //创建对象同时,this——>o
var p={a:4}; //赋值同时,this——>p
o.fun(); //this.o 3
//console.log(o.a); //3
/*结论——this与它定义在哪无关,this都指向的是当前的对象,上述o.fun(),指向的是“o”,其对应的是3,所以输出3*/
(p.fun=o.fun)(); //2,匿名函数的自调,还是作为全局变量,所以返回2
//p.fun=0x1011
//p={a:4,fun:0x1011}
//返回o.fun中的值! 0x1011(地址)
//(0x1011)(); ——>匿名函数自调 ——>this_window
/*结论——赋值表达式的结果相当于等号右侧表达式的值*/
p.fun(); //4
/*结论——this与它定义在哪无关,this指向当前的对象,即为p*/
3、面向对象3大特点:
封装、继承、多态
(1)封装:将描述同一个东西的属性+方法,定义在一个对象中。
(2)继承:父对象中的属性+方法,子对象可以直接使用
(3)多态:同一个对象,在不同情况下,呈现不同的形态(注意:在js中无“多态”概念)
a、重载:同一方法名,传入参数不同,执行不同操作。
b、重写:子对象觉得父对象的成员不好用,可自己写一个,覆盖父对象成员。
4、继承——js中一切继承都是用原型对象实现“_proto_”
原型对象:每个函数对象都有一个原型对象
在构造函数的原型对象负责保存所有子对象共享的成员
建议:所有子对象共享的方法,都应定义在构造函数的原型对象中。
这样做,可避免重复定义方法的对象,浪费内存。
注意:所有内置类型的API都是定义在类型.prototype
//创建一个构造函数
function Student(){
this.sname=sname;
this.age=age;
}
//在构造函数原型对象中定义公共方法
Student.prototype.inteSelf=function(){
alert("I'm"+this.sname+"I'm"+age);
}
//用new关键字创建新对象
var lilei=new Student("Li Lei",12);
var hmm=new Student("Han Meimei",11);
//在构造函数原型中定义公共属性
Student.prototype.money=100;
console.log(lilei.money);
//先在当前对象本地去找,找不到再去原型
//原型也没有,才undefined
console.log(hmm.money);
Student.prototype.money-=20;
console.log(lilei.money);
(1)扩展对象属性:2种
a、扩展共有属性:通过构造函数.prototype添加的属性
b、扩展自有属性:通过某一个具体子对象添加的属性
判断自有属性或共有属性:
a、判断自有属性:obj.hasOwnProperty("属性名")
b、判断共有属性:"属性名" in obj && !obj.hasOwnProperty("属性名")
(表示在原型关系中包含 且 子对象自己没有)
(2)原型链:由各级对象的_proto_逐级继承形成的关系
获得任意对象的父级原型对象:
Object.getPrototypeOf(子对象) ==> 子对象._proto_
检测数组arr的_proto_原型链
var arr=[];
Object.getPrototypeOf(arr);
//[]
var arr=[];
Object.getPrototypeOf(arr)==Array.prototype
//true
Object.getPrototypeOf(Object.getPrototypeOf(arr))
//Object{}
2_1:检测对象的原型isPrototypeOf()
isPrototypeOf()用于判定一个prototype对象是否存在另一个对象的原型链中。如果是,返回true,否则返回false。
2_2:检查对象的父对象:
父对象.isPrototypeOf(子对象)
5、面向对象:封装、继承、多态
(1)创建对象:3种/4种
a、直接量:var obj={"属性名":值,
"方法名":function(){
...this.属性名...
}
}}_proto_——>Object.prototype
(2)new关键字:var obj = new Object();
obj.属性名=值;
obj.方法名=function(){
...this.属性名...
}
(3)使用构造函数反复创建相同结构的对象:2步
a、定义构造函数:
function 构造函数名(属性参数,...){
this.属性名=属性参数;
if(!构造函数名.prototype.方法名){
构造函数名.prototype.方法名=
function(){
...this.属性名...
}
}
}
b、使用new创建对象同时,调用构造函数:
var obj=new 构造函数名(属性值,...)
6、总结
(1)this:指代当前正在调用方法的对象
this和定义在哪无关!仅和调用时使用的对象有关
所有无关(不用var赋值的变量,匿名函数)都是window
(2)原型 原型链 继承
a、原型:保存所有子对象共有属性和方法的对象
所有函数都有prototype,指向自己的原型对象
所有对象都有_proto_,指向自己父级原型对象
(所有原型对象都有constructor,指向原型对应的构造函数)
b、原型链:所有父子级对象间_proto_形成的多级引用关系
——>多级继承
c、原型相关API:
1、判断自有属性和共有属性
a、判断自有——obj.hasOwnProperty("属性名")
b、判断原型链上的属性(2种)
判断不包含:if(!("属性名" in obj))——“用得最多”
if(obj.属性名===undefined)
if(!obj.属性名)
c、仅判断共有:必须满足两个条件
!obj.hasOwnProperty("属性名")
&&
obj.属性名
2、获得任意对象的原型
obj._proto_X
Object.getPrototypeOf(obj)
3、判断父对象是否在子对象的原型链上
父对象.isPrototypeOf(子对象)
d、检测一个对象是不是数组类型(4种)
1、Array.prototype.isPrototypeOf(obj)
2、obj instanceof Array
对象 是不是 构造函数 的实例
3、obj.constructor==Array 仅判断直接父级
4、利用当前对象,强行调用原始的toString方法
Object.prototype.toString.call(obj) == "[Object Array]"
.apply(obj)
e、继承
为什么要继承? ——代码重用、节省空间
1、直接继承对象:想方设法修改对象的_proto_
3种:
(1)仅修改一个对象的_proto_
Object.setPrototypeOf(子对象,父对象)
(2)通过修改构造函数的原型对象,实现批量修改后续子对象的继承关系
构造函数.prototype=父对象
强调:仅影响之后创建的对象的继承关系
之前创建的对象依然及继承旧构造函数.prototype
(3)Object.create(父对象[,{属性列表}]);
var hmm=Object.create(father);
var hmm=Object.create(father,
{intrSelf:{value:intrSelf},
toString:{value}
}
);
该一句话可以办三件事:
a、创建一个空对象,
b、继承父对象的属性,
c、继承同时可再扩展属性和方法。
2、仅继承结构:
function 父类型构造函数(属性参数1,属性参数2){
this.属性1=属性参数1;
this.属性2=属性参数2;
}
function 子类型构造函数(属性参数1,属性参数2,属性参数3){
父类型构造函数.call(this,属性参数1,属性参数2);
this.属性3=属性参数3;
}
var obj=new 子类型构造函数(值1,值2,值3);