闭包&继承

闭包

  JavaScript中的函数会形成闭包,闭包是由函数以及创建该函数的词法环境组合形成。这个环境包含了这个闭包创建时所能访问的所有局部变量。
1、每次调用执行foo函数,将foo内部从头到尾执行一遍,打印10。

function foo(){
	var a = 10;
	function bar(){
		console.log(a++);
	}
	bar();
}
foo(); // 10
foo(); // 10

2、返回函数体,在外部可访问到变量a,并在每次的基础上进行变化。

function foo(){
	var a = 10;
	return function bar(){
		console.log(a++);
	}
}
		
var baz = foo();
// 定义变量接收返回的函数体
baz(); // 10 
baz(); // 11 在之前的基础上进行变化

闭包的优点

  减少全局变量的污染,创建命名空间。

var yh = (function(){
	var a = 10;
	var b = 20;
	function foo(){
		console.log(a); // 10
	}
	function bar(){
		console.log(b);
	}
	// 把函数内部的变量和函数当做变量属性和方法返回
	// 可供外部调用
	return {
		foo,
		a
	}
})();		
yh.foo();
console.log(yh.a); // 10

闭包的缺点

  内存泄漏,一块内存空间既不能被使用也不能被释放。
  JavaScript中的两大回收机制:标记清除、引用计数。
1、标记清除

function foo(){
	var a = 10;//进入环境的标记
}
foo();//调用完成之后  a变量的标记置为退出环境的标记

2、引用计数
  引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。

var obj1 = {};
var obj2 = obj1;  // 此时obj2引用了obj1,则obj1不能被回收
obj2 = null; // 此时obj1的引用次数为0,可回收

闭包的经典应用

//结合闭包实现点击每个li,打印对应的索引
var aLi = document.querySelectorAll("li");
for(var i = 0; i < aLi.length; i++){
	(function(i){
		aLi[i].onclick = function(){
			console.log(i);
		}
	})(i);	
}

闭包面试题

function fun(n, o) {
	console.log(o);
	return {
		fun: function(m) {
			return fun(m, n);
		}
	};
}
var a = fun(0); //传入参数n=0
// 此时没有第二个参数o,打印undefined
// a接收的返回值是对象{ fun:function(m){ return fun(m,0); } }
			
a.fun(1); // 传入参数1 打印第二个参数0
// 执行函数 function(m){ return fun(m,0); }
a.fun(2); // 传入参数2 打印第二个参数0
// 执行函数function(m){ return fun(m,0); }
a.fun(3); // 传入参数3 打印第二个参数0
// 执行函数function(m){ return fun(m,0); }
			
//var b = fun(0).fun(1).fun(2).fun(3);
var b=fun(0); // 此时无第二个参数,打印undefined
// b此时接收的返回值是对象 { fun:function(m){ return fun(m,0); } }
var c=fun(0).fun(1);
//打印undefined 0
			
var d=fun(0).fun(1).fun(2);
//打印undefined 0 1
			
var e=fun(0).fun(1).fun(2).fun(3);
//打印undefined 0 1 2
			
var f = fun(0).fun(1);  // undefined 0
f.fun(2);  // 1
f.fun(3);  // 1

继承

1、构造函数继承
通过call()、apply()、bind()改变this指向
此方法只能继承构造函数内的属性和方法,不能继承原型对象上的属性和方法。

function Person(name,age){
	this.name = name;			
	this.sayHello = function(){
		console.log(this.name);
	}
}
function Male(name,age){
	/*this.name = name;
	this.sayHello = function(){
		console.log(this.name);
	}*/
	Person.call(this,name);
}
var male = new Male("john");
male.sayHello();

2、原型对象继承
通过Male.prototype = new Person();更改子类的原型对象,再Male.prototype.constructor = Male;纠正指向。

function Person(){
				
}
Person.prototype.name = "john";
Person.prototype.age = 20;
Person.prototype.sayHello = function(){
	console.log(this.name);
}
			
function Male(){
			
}
Male.prototype = new Person();
Male.prototype.constructor = Male;

Male.prototype.sayHi = function(){
	console.log("hi");
}
						
var male = new Male();
			
male.sayHello();
male.sayHi();
			
console.log(male.__proto__.constructor);

3、组合继承

function Person(name,age){
	this.name = name;
	this.age = age;
}
Person.prototype.sayHello = function(){
	console.log(this.name);
}
			
function Male(name,age){
	Person.call(this,name,age);
}
			
/*Male.prototype = new Person();*/
			
for(var attr in Person.prototype){
	Male.prototype[attr] = Person.prototype[attr];
}
			
Male.prototype.sayHi = function(){
	console.log("hi");
}
			
var male = new Male("john",20);
			
male.sayHello();
			
var person = new Person("mr",18);
person.sayHi();

4、寄生式组合继承

function Person(name,age){
	this.name = name;
	this.age = age;
}
Person.prototype.sayHello = function(){
	console.log(this.name);
}
			
function Male(name,age){
	Person.call(this,name,age);
}
						
//继承原型对象上的方法
			
Male.prototype = Object.create(Person.prototype);
Male.prototype.constructor = Male;
						
Male.prototype.sayHi = function(){
	console.log("hi");
}
						
var male = new Male("john",20);
male.sayHello();
console.log(male.__proto__.constructor);
						
function inherit(subType,superType){
	subType.prototype = Object.create(superType.prototype);
	subType.prototype.constructor = subType;
}

5、ES6继承

class Person{
	constructor(name,age){
		this.name = name;
		this.age = age;
	}
	sayHello(){
		console.log(this.name);
	}
	static foo(){ //类方法
		console.log("foo");
	}
}
			
//Person.foo();
			
class Male extends Person{
	constructor(name,age){
		super(name,age);//创建this对象,改变this指向,指向父类的构造函数的
		this.sexy = "male";
	}
	sayHi(){
		//this.sayHello();
		super.sayHello();//指向父类的原型对象
		console.log("hi");
	}
	static bar(){
		super.foo();//指向父类
	}
}
						
Male.bar();
			
var male = new Male("john1",20);
			
//male.sayHello();
male.sayHi();

补充:给数组添加最大值最小值的方法

//getMinVal() getMaxVal() 所有的数组都能访问这个方法
//把这两个方法挂载到原型对象上
var arr = [11,1,5,78];
var arr1 = [32,34,9,243];
			
Array.prototype.getMinVal = function(){
	return Math.min.apply(null,this);
}
Array.prototype.getMaxVal = function(){
	return Math.max.apply(null,this);
}
			
var min = arr1.getMinVal();
var max = arr1.getMaxVal();
			
console.log(min,max);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值