22、闭包与继承
闭包和面向对象都是面试的重点,
1.闭包
一.什么是闭包函数?
嵌套在一个函数中的函数,称为闭包函数。
内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
二.闭包的作用
可以在函数外部通过闭包函数访问到函数内部的局部变量。
三.闭包原理
JS中利用垃圾回收机制清理内存中被释放的内容,当被释放的内容被另一个程序使用的时候,这内容就会被长期保留在内存。
四.闭包优缺点?
优点:可以使局部变量长驻内存,不被释放,从而让函数外部访问到该变量。
缺点:长驻内存,内存长期得不到释放,可能造成内存泄露。
function me(){
var a = 4;
return function fn(){
return a;
}
}
var fn1 = me(); //fn1 = function fn(){ return a;};
alert(fn1());//4
(function(){
})()`
2.闭包的应用
使用全局变量进行累加和
使用局部变量进行累加和
循环里的匿名函数的取值问题
<script type="text/javascript">
var a = 3;
function fn(){
a ++;//全局
}
alert(a); //3
fn();
alert(a); //4
fn();
alert(a); //5
function fn(){
var a = 3;
a ++;//局部
alert(a);
}
fn(); //4
fn(); //4
fn(); //4
function fn(){
var a = 3;
return function(){ //闭包函数
return a++; //a=4,a++ = 3
}
}
alert(fn()()); //3
alert(fn()()); //3
alert(fn()()); //3
function fn(){
var a = 3;
return function(){ //闭包函数
return a++; //a = 4
}
}
var me = fn(); // var me = function(){ return a++}; //6,只执行一次me = fn(),a=3只初始化一次
alert(me()); //3
alert(me()); //4
alert(me()); //5
alert(me()); //6
function fn(){
var arr = [];
for(var i = 0;i < 5;i ++){
arr[i] = function(){
return i;
};
}
return arr;
}
var me = fn();
for(var i = 0;i < me.length;i ++){
alert(me[i]());//5,5,5,5,5
}
function fn(){
var arr = [];
for(var i = 0;i < 5;i ++){
arr[i] = (function(){
return i;
})();
}
return arr;
}
var me = fn();
for(var i = 0;i < me.length;i ++){
alert(me[i]);//0,1,2,3,4
}
function fn(){
var arr = [];
for(var i = 0;i < 5;i ++){
arr[i] = (function(i){
return i;
})(i);
}
return arr;
}
var me = fn();
for(var i = 0;i < me.length;i ++){
alert(me[i]);//0,1,2,3,4
}
function fn(){
var arr = [];
for(var i = 0;i < 5;i ++){
arr[i] = (function(i){
//0
/*
* function(){
return i;
};
i = 1;
function(){
return i;
};
i = 2;
function(){
return i;
};
i = 3;
function(){
return i;
};
i = 4;
function(){
return i;
};
*/
return function(){
return i;
};
})(i);
}
return arr;
}
var me = fn();
for(var i = 0;i < me.length;i ++){
alert(me[i]());//0,1,2,3,4
}
面向对象
// ES6:
class 类名{
constructor([参数]){
this.属性名 = 属性值;
……
}
方法名([参数]){
处理语句
}
……
}
class 子类名 extends 父类名{
constructor([参数]){
super([参数]);
this.属性名 = 属性值;
……
}
方法名([参数]){
处理语句
}
}
//ES5:
function 类名([参数]){
this.属性名 = 属性值;
……
}
类名.prototype.方法名 = function([参数]){
处理语句
}
function 子类名([参数]){
父类名.apply(this,arguments);
this.属性名 = 属性值;
}
for(var i in 父类.prototype){
子类.prototype[i] = 父类.prototype[i];
}
子类名.prototype.方法名 = function([参数]){
处理语句;
}
3.es5面向对象
创建构造函数
缺点:浪费内存空间
实例继承
call(当前对象,参数1,参数2,参数3,……)
apply(当前对象,[参数1,参数2,参数3,……])
apply(当前对象,arguments)
//创建构造函数
function Father(name,age){
//实例属性或实例方法
//属性
this.name = name;
this.age = age;
//方法
this.showName = function(){
return this.name;
}
this.showAge = function(){
return this.age;
}
this.song = function(){
return '唱歌';
}
}
var fa1 = new Father('张三',18);
var fa2 = new Father('张三',20);
console.log(typeof fa1.showName);//function
console.log(typeof fa2.showName);//function
console.log(fa1 === fa2);//false
console.log(fa1.song === fa2.song);//false //函数存在堆里,栈里存的是地址.
console.log(fa1.name === fa2.name);//true
//缺点:浪费内存空间
//继承
function Son(name,age){
//继承实例属性或实例方法
//经典继承
//call(当前对象,参数1,参数2,参数3,……)
//apply(当前对象,[参数1,参数2,参数3,……])
//apply(当前对象,arguments)
// Father.call(this,name,age); //继承父类的实例属性和实例方法
// Father.apply(this,[name,age]);
Father.apply(this,arguments);
}
var son = new Son('李四',18);
alert(son.showName());//李四
原型继承
Prototype : 原型
原型缺点:无法传参,所有的对象都具有相同的属性值。
原型继承 Son.prototype = Father.prototype;
原型链继承Son.prototype = new Father();
拷贝继承
var son = new Son();
//拷贝继承
for(var i in Father.prototype){
Son.prototype[i] = Father.prototype[i];
}
//创建构造函数
function Father(){
}
//原型属性
Father.prototype.name = '张三';
Father.prototype.age = 18;
//原型方法
Father.prototype.showName = function(){
return this.name;
}
Father.prototype.showAge = function(){
return this.age;
}
Father.prototype.song = function(){
return '唱歌';
}
var fa1 = new Father();
var fa2 = new Father();
// console.log(typeof fa1.showName);
// console.log(typeof fa2.showName);
// console.log(fa1 === fa2);
console.log(fa1.song === fa2.song);
// console.log(fa1.name === fa2.name);
//原型缺点:无法传参,所有的对象都具有相同的属性值。
function Son(){}
//原型继承
// Son.prototype = Father.prototype;
// Son.prototype = new Father();//原型链继承
var son = new Son();
//拷贝继承
for(var i in Father.prototype){
Son.prototype[i] = Father.prototype[i];
}
alert(son.song());
混合继承
既有实例继承,也有原型继承
//创建构造函数
function Father(name,age){
//实例属性
this.name = name;
this.age = age;
}
//Prototype : 原型
//原型方法
Father.prototype.showName = function(){
return this.name;
}
Father.prototype.showAge = function(){
return this.age;
}
Father.prototype.song = function(){
return '唱歌';
}
var fa1 = new Father();
var fa2 = new Father();
// console.log(typeof fa1.showName);
// console.log(typeof fa2.showName);
// console.log(fa1 === fa2);
console.log(fa1.song === fa2.song);
// console.log(fa1.name === fa2.name);
//混合继承
function Son(name,age){
//实例继承
Father.apply(this,arguments);
}
//拷贝继承
for(var i in Father.prototype){
Son.prototype[i] = Father.prototype[i];
}
var son = new Son('张三',18);
var son1 = new Son('李四',20);
alert(son.showName == son1.showName);
es5关于实例和原型的拓展
in : 判断一个属性是否属于某个类,属于返回true,不属于返回false
if('long' in Father){
alert('ok');
}else{
alert('no');
}
delete : 删除对象的实例属性
delete fa.name;
delete Father.prototype.name;
alert(fa.showName());
//创建构造函数
function Father(name,age){
//实例属性
this.name = name;
this.age = age;
}
//Prototype : 原型
Father.prototype.name = '张三';
//原型方法
Father.prototype.showName = function(){
return this.name;
}
Father.prototype.showAge = function(){
return this.age;
}
Father.prototype.song = function(){
return '唱歌';
}
var fa1 = new Father();
var fa2 = new Father();
// console.log(typeof fa1.showName);
// console.log(typeof fa2.showName);
// console.log(fa1 === fa2);
console.log(fa1.song === fa2.song);
// console.log(fa1.name === fa2.name);
//混合继承
function Son(name,age){
//实例继承
Father.apply(this,arguments);
}
// Son.prototype = Father.prototype;
// Son.prototype = new Father();//原型链继承
//拷贝继承
for(var i in Father.prototype){
Son.prototype[i] = Father.prototype[i];
}
var fa = new Father('李四',20);
fa.name = '王五';
// alert(fa.showName());
//in : 判断一个属性是否属于某个类,属于返回true,不属于返回false
// if('long' in Father){
// alert('ok');
// }else{
// alert('no');
// }
//delete : 删除对象的实例属性
delete fa.name;
delete Father.prototype.name;
alert(fa.showName());//undefined
增加和修改现有类的方法
给Array添加求和方法:
Array.prototype.mySum = function(){
var sum = this.reduce(function(up,down){
return up + down;
})
return sum;
}
修改数组的.push()方法:
Array.prototype.push = function(){
alert('呵呵');
}
var arr = [1,2,3,4,5];
alert(arr.mySum());
alert(arr.push());