一、自我执行函数
()();第一个括号里面放是匿名函数,第二个括号是调用执行
;(function(形参){
alert("11");
})(实参); 注意(在代码的前后都要加上一个分号,防止代码压缩报错)
例子:;(function(a){
alert(a);
})(3);//3
作用:防止变量污染
二、闭包
闭包是一种现象,没有一个具体的概念。
什么是闭包?
函数里面套函数,里面的函数就形成了闭包。
例子:
1)function box(){
var a=0;
return function(){
return a;
}
}
var b=box();
var c=box();
alert(c());
alert(b());
2)function box(){
var a=0;
return function(){
a++;
return a;
}
}
var a=box();//a=0;
var b=box();//a=0;
a();//1
a();//2
a();//3
b();//1
a();//4
b();//2
alert(a());//5
alert(b());//3
闭包的作用?
在函数的外部访问内部的变量;( 当一个函数a返回值是一个函数时,可以在a的外部通过这个函数访问a内部 的变量,这返回值的函数形成了闭包。)
延长变量的使用周期。
闭包缺点:
大量消耗内存资源。
因为变量会驻留在内存中得不到释放,ie浏览器会造成内存泄漏。
经典案例:(重要)
1)
function box(){
var a=9;
add=function(){
a++;
};
return function(){
alert(a);
}
}
var result1=box();//a=9
var result2=box();//a=9
result1();//9
result2();//9
add();//相当于var i=0;var i=1; alert(i);//1
result1();//9
result2();//10
2)
function box(a,b){
console.log(b);
return {//返回一个对象
box:function(m){
return box(m,a);
} //1 0
} //2 1
//3 2
}
第一种. var c=box(0);//undefined
c.box(1)//0
c.box(2)//0
c.box(3)//0
第二种. var d = box(0).box(1).box(2).box(3);//undefined/0/1/2
第三种. var c=box(0).box(1);//undefined/0
c.box(2);//1
c.box(3);//1
三、原型链(prototype)
1) 创建一个函数时,这个函数自动在内存中开闭了一个独立的空间来存放这个原型对象数据。
2) 构造函数有原型对象prototype
实例对象没有原型对象。
3) 但是实例对象指向了构造函数的原型对象。
如何指向?
当我们用new关键字去构建一个实例对象时,会自动的产生一个指针,这个指针是__proto__
实例对象通过__proto__这个指针与构造函数的原型对象产生了联系,这个时候实例对象可
以访问构造函数的原型对象下面的方法和属性。
constructor:
这个也是一个指针,这个指针在构造函数的原型对象里,也是自动生成的。constructor指向构造函数本身。
主要用于实现继承。
4)什么是原型链?(面试)
原型链就是:
实例对象通过__proto__这个指针与构造函数的原型对象产生了联系,原型下又有一个指针__proto__;
原型下的指针指向Object(父类或超类),使得实例对象与构造函数原型对象再与超类的原型对象发生的链条的关系。
四、实例对象访问属性和方法的原则
先查找实例,实例没有,去原型下面去查,如果原型下没有去超类去查。
如果超类也没有,返回undefined.
例子:
function Person(name,age){
this.name=name;
this.age=age;
this.eat=function(){
alert(this.name+"在吃饭");
}
}
Person.prototype.name="jerry";
Person.prototype.run=function(){
alert(this.name+"在跑步");
}
(如果实例中没有this.name=name;
var p1=new Person("tom",23); 就会在原型中找 )
alert(p1.name);//tom //jerry
p1.eat();//tom在吃饭 //jerry在吃饭
p1.run();//tom在跑步 //Jerry在跑步
五、Object类的提供的方法和关键字:
1)实例对象.hasOwnProperty("属性名或方法名");如果在实例中有,返回true,没有返回false 例子:p1.hasOwnProperty("phone")
2) in关键字:
“属性名或方法名” in 实例对象,返回true表示有属性或方法,返回false表示没有该属性或方法,没有精确到实例还是原型。用封装来精确
例子:"phone" in p1
封装函数查找原型是否有某个属性或者方法:
alert(isHasProperty(zs,"age"));//返回true表示在原型下有这个属性,返回false表示没有
function isHasProperty(obj,attr){
return !obj.hasOwnProperty(attr) && attr in obj;
}
例子:
function Person(name,age){
this.name=name;
this.age=age;
this.eat=function(){
alert(this.name +"在吃饭");
}
}
Person.prototype.name="jerry";
Person.prototype.phone=function(){
alert(this.name+"电话号码是:123");
}
Person.prototype.run=function(){
alert(this.name+"在跑步");
}
var p1=new Person("张三",19);
alert(p1.hasOwnProperty("phone"));//false
alert("phone" in p1);//true 不能判断属性或者方法是在原型中还是在实例中
调用:alert(isHasProperty(p1,"phone"));//true 封装的一个函数,判断属性或者方法是否在原型中
封装:
function isHasProperty(obj,attr){
return !obj.hasOwnProperty(attr)&& attr in obj;
}
构造函数.prototype.isPrototypeOf(实例对象);检测实例对象是否是属于该构造函数的实例对象。相当于instanseof
alert(Person.prototype.isPrototypeOf(p1));//true 连接上面代码
var arr=new Array();
alert(Person.prototype.isPrototypeOf(arr));//flase
alert(Array.prototype.isPrototypeOf(arr));//true
3)delete关键字:
delete 实例对象.属性名或方法名;删除实例中的属性或方法,无法删除原型中的属性或方法。
例子:delete p1.age;
alert(p1.age);//undefined
六、面向对象的三个特征
封装
继承
多态(在js中不存在,只是有,模糊不清)
七、继承 (面试)
父类也叫超类
1)改变父类的this执行环境实现继承
缺点:无法继承父类的原型下的属性和方法。
function Father(name,age,money){
this.name=name;
this.age=age;
this.money=money;
this.eat=function(){
alert(this.name+"在吃饭");
}
}
Father.prototype.run=function(){
alert(this.name+"在跑步");
}
//改变父类的this执行环境实现继承
function Son(name,age,money){
this.father=Father;
this.father(name,age,money);
}
var son=new Son("小王",18,500);
son.eat();//小王在吃饭
son.run();//无法继承父类原型下的属性和方法
2)call和apply继承
缺点:无法继承父类的原型下的属性和方法
function Father(name,age,money){
this.name=name;
this.age=age;
this.money=money;
this.family = ["哥哥","妹妹"];
this.eat=function(){
alert(this.name+"在吃饭");
}
}
Father.prototype.sex="男";
Father.prototype.run=function(){
alert(this.name+"在跑步");
}
//apply继承
function Son(name,age,money){
Father.apply(this,arguments);//arguments是所有的参数,只能apply用arguments
}
//call继承
function Son(name,age,money){
Father.call(this,name,age,money);
}
var son=new Son("小张",19,1900);
son.family.push("弟弟");
var son1=new Son(" 小王",29,900);
alert(son.name);//小张
son.eat();//小张在吃饭
son1.eat();//小王在吃饭
alert(son.family);//哥哥,妹妹,弟弟
alert(son1.family);//哥哥,妹妹
son.run();//报错; 原型下的属性和方法无法继承
3)原型链继承
优点:
解决了无法继承父类的原型下的属性和方法的问题。
缺点:
无法传参。
所有实例对象共享了所有的属性和方法。
function Father(name,age,money){
this.name=name;
this.age=age;
this.money=money;
this.family=["哥哥","妹妹"];
this.eat=function(){
alert(this.name+"在吃饭");
}
}
Father.prototype.run=function(){
alert(this.name+"在跑步");
}
function Son(){};
Son.prototype=new Father("小张",18,500);
var son1=new Son("小张",18,4567);
son1.family.push("弟弟");
var son2=new Son();
alert (son1.age);//18
son1.run();//小张在跑步
alert(son1.family);//哥哥,妹妹,弟弟
alert(son2.family);//哥哥,妹妹,弟弟
4)混合继承:
优点:
解决了上面所有问题;
缺点:
子类的constructor指向被修改了。子类添加的原型方法或属性会被添 加到父类的原型中去。
function Father(name,age,money){
this.name=name;
this.age=age;
this.money=money;
this.family=["哥哥","妹妹"];
this.eat=function(){
alert(thia.name+"在吃饭");
}
}
Father.prototype.run=function(){
alert(this.name+"在跑步");
}
function Son(){
Father.apply(this,arguments);
}
Son.prototype=Father.prototype;
var son=new Son("tom",19,988);
son.family.push("弟弟");
var son2=new Son("小黄",18,1000);
alert(son.family);//哥哥,妹妹,弟弟
alert(son2.family);//哥哥,妹妹
son.run();//tom在跑步
son2.run();//小黄在跑步
5)寄生组合继承
优点:解决了以上所有的问题
// 实现原型继承的封装
function heritPrototype(subType,superType){
var proto=Object.create(superType.prototype);
proto.constructor=subType;
subType.prototype=proto;
}
function Father(name,age,money){
this.name=name;
this.age=age;
this.money=money;
this.family=["哥哥","妹妹"];
this.eat=function(){
alert(thia.name+"吃饭");
}
}
Father.prototype.run=function(){
alert(this.name+"在跑步");
}
function Son(name,age,money){
//实现实例继承
Father.apply(this,arguments);
}
//调用封装的方法
1)heritPrototype(Son,Father);
//实现原型继承
//2)Son.prototype=Object.create(Father.prototype);
// Son.prototype.constructor=Son;
// 实现原型继承的封装
function heritPrototype(subType,superType){
var proto=Object.create(superType.prototype);
proto.constructor=subType;
subType.prototype=proto;
}
Son.prototype.say=function(){
alert(this.name+"o了");
}
var son =new Son("小吴",15,10000);
var father=new Father("安咯",55,1000);
son.say();
father.say();
案例:原型与继承实现拖拽
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
div{
width: 100px;
height: 100px;
position: absolute;
}
#box1{
background: red;
left: 100px;
top: 100px;
}
#box2{
background: yellow;
left: 300px;
top:150px;
}
</style>
</head>
<body>
<div id="box1">
</div>
<div id="box2">
</div>
</body>
</html>
<script type="text/javascript">
function DragBox1(id){
this.box=document.getElementById(id);
this.init();
}
DragBox1.prototype.init=function(){
var _this=this;
this.box.onmousedown=function(e){
var e=e||event;
_this.x=e.offsetX;
_this.y=e.offsetY;
document.onmousemove=function(e){
_this.move(e);
return false;
}
document.onmouseup=function(){
document.onmousemove=null;
}
}
}
DragBox1.prototype.move=function(e){
var e=e||event;
var l=e.clientX-this.x;
var t=e.clientY-this.y;
this.box.style.left=l+"px";
this.box.style.top=t+"px";
}
new DragBox1("box1");
function DragBox2(){
DragBox1.apply(this,arguments);
}
heritPrototype(DragBox2,DragBox1);
function heritPrototype(subType,supperType){
var proto=Object.create(supperType.prototype);
proto.constructor=subType;
subType.prototype=proto;
}
DragBox2.prototype.move=function(e){
var e=e||event;
var l=e.clientX-this.x;
var t=e.clientY-this.y;
var maxt=document.documentElement.clientHeight;
var maxl=document.documentElement.clientWidth;
t=t<0?0:(t>maxt?maxt:t);
l=l<0?0:(l>maxl?maxl:l);
this.box.style.left=l+"px";
this.box.style.top=t+"px";
}
new DragBox2("box2");
</script>