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());
原文地址:https://www.cnblogs.com/zhongchao666/p/9275586.html