闭包:
百度百科:
官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
闭包的特点:
1.作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
2.一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
简单的说,javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
这样看起来是不是更太好懂了
那我们先来看一个例子
function closure(){
var str = "I'm a part variable.";
return function(){
alert(str);
}
}
var fObj = closure();
fObj();
在这里很明显是在函数里写函数,但是这样就算是闭包了吗?并不是,那只是单纯的写两个函数有什么作用呢?所以,闭包的作用是什么?
1、保证函数内部的变量(属性)不受污染
难道不用闭包变量和属性就会受到污染吗?
你猜!
在es面世之前,js是没有块级作用域的,那么就会有一个问题,我和你的代码合并,变量会不会冲突?答案是变量会覆盖,在es6之前我们都是用var来定义变量的,var的特点是什么呢?可重复,会有变量提升,这里说的覆盖其实就是我们说的收到了污染。当变量收到污染的时候我们该怎么做?
2、函数外部可以调用到函数内部的变量(属性)
这个时候我们需要一个叫做“作用域”的功能,这个时候我们就发现函数能做到这一点,函数能保证我的变量不受污染,那我们又该怎样使用这个不收到污染的变量或者属性呢?很简单,一个return,把你在函数外想调用的东西“弹”出去就好了。
看到这里是不是瞬间感觉两个函数在一起的作用那么厉害,事情有好的一面就会有不好的一面,下面播报一条关于闭包的负面新闻:
由于某程序猿在代码中多次使用闭包导致内存泄漏
闭包那么好,为什么还会导致内存泄漏呢?
浏览器很喜欢收纳函数,所以当运行时出现的函数都会存在内存中,直到浏览器彻底承担不起函数的个数,这个时候就会产生内存泄漏。
原型链
百度百科:
没找到~~
说到原型链,那就先说一下原型
原型:一个对象具有prototype和constructor ,这样就可以说这个对象是原型
原型链:当对象可以被称之为一个原型的时候,每个原型又可以追溯自己的原型对象,然而原型对象又是一个对象,所以它也可以称之为原型,那就又可以找自己的原型对象,就这样一直追溯到null这个结果才会终止,从对象到null的这一段一段的关系,我们可以称之为原型链。
一张图解释一下:!
比如我创建一个函数
function foo(){};
这个函数我们可以有两种方法处理
var a=foo();
var b=new foo();
第一种我们一般称之为调用函数。
第二种就叫做实例化对象
在实例化的对象上我们可以为它扩展很多东西,那这个时候就会用到原型链
例如:
foo.prototype.={
say:function(){}
}
现在就可以在实例化对象之后继续去封装内部的方法了
对于如何访问对象中的属性和方法,谷歌和火狐大大都提供了proto来帮助我们查询。
面向对象
万物皆对象~~
好像是程序猿被问到什么是对象时内心最想丢出去的话~但是又碍于逼格还要好好解释一下什么是对象。
对象:就是具体的一个东西,比如说你刚刚吃掉的一个馒头或者一粒米饭都可以说是一个对象,对象又具有自己的属性和方法,比如说这个米是熟的,这就是一个属性。
这里又不得不说类。
类:刚才说你吃掉的一粒米饭是对象,那如果只说米饭,这就可以说是一个类
所以也可以说,对象是具体的一个,类是一堆对象的集合
所以说面向对象其实是一个很抽象,很大的话题
面向对象的特性
三大特性:继承,封装,多态
继承:可以说是父子关系,儿子具有爸爸的特征,但是儿子也具有自己的特征,在javascript里实现继承大多都会用的原型,可以参考原型链的话题,我们先在一个对象里写了自己的方法,然后另一个对象也可以使用这个对象的方法和属性,并可以拓展自己的方法和属性,这样我们就可以称之是一个实现继承的例子
封装:每个对象都有自己的属性和方法,比如说程序猿他长得很好看这是一个属性,它会敲代码,这是一个方法,那至于他敲代码用的谁的键盘,敲了什么代码,这些细节的东西都被封装起来,我们只知道他会敲代码。
多态:那就说一下封装里的具体内容,比如说程序猿可以用你的代码敲‘hello word’,也可以用我的键盘敲一段‘你好’,这样的同一个封装,造就了不一样的结果,我们称之为多态。
从概念上我们理解了继承、封装、多态,来试着实操一下
继承
//爸爸
function parent(eye,likeFood){
this.eye=eye;
this.likeFood=likeFood;
}
parent.prototype.exercise(){
console.log('like football');
}
//儿子获取到爸爸的属性
function son(eye,likeFood,mouth){
parent.call(this,eye,likeFood);//构造函数伪装 调用父级的构造函数--为了继承属性
this.mouth=mouth; //儿子自己的属性
}
//儿子获取到爸爸的方法
for(attr in parent.prototype){
son.prototype[attr]=person.prototype[attr];
}
//儿子自己的方法
son.prototype.doing=function(){
console.log('写作业')
}
var op=new parent('黑色','鱼'); //爸爸有黑色的眼睛,喜欢的食物是鱼
var os=new son('黑色','蔬菜','小'); //儿子也是黑色的眼睛,喜欢的食物是蔬菜,嘴巴是小的
op.eye(); //黑色
op.likeFood(); //鱼
os.eye(); //黑色
os.likeFood(); //蔬菜
os.mouth(); //小
封装
function createObj(name,key,res){
var Obj=new Object();
obj.name=name;
obj.age=age;
obj.res=function(){
alert(res);
}
return obj;
}
var obj1=createObj('程序猿','你的键盘','Hello Word');
var obj2=createObj('程序猿','我的键盘','你好');
obj1.name(); //'程序猿'
obj1.key(); //你的键盘
obj2.key(); //‘我的键盘’
obj2.res(); //‘你好’
我们利用封装同时也解释了多态。