闭包
闭包就是函数中的函数实现外层函数中的变量不释放。
先来看看这个代码
function a(){
var o=1
function b(){
console.log(o++)
}
b()
}
a() //输出1
a() //还是输出1
a() //仍然输出1
//继续调用a(),得到的结果还是1
为什么会出现这样的结果,原因是每次调用完a后,o会+1,但是这个o是函数b中的o,而且没有返回到a中,所以当下一次再调用a时,o仍然是1。这就是外层函数的变量释放。那么怎么才能使o累加呢,这就要用到闭包了。在看看下面的代码。
function a(){
var o=1
function b(){
console.log(o++)
}
return b
}
var c = a() //只调用一次a
c(); c(); c(); //通过调用c就可以实现多次调用b,实现累加
原型链
在javascript中创建对象有三种方法
//第一种
new Object()
//第二种,是第一种的简写
{a:1}
//第三种,通过构造函数,然后new一个对象
function a(){}
new a()
为一个对象添加属性和方法则是有“ . ”来实现
一个对象.属性或方法,例:
a = {b:1}
则a.b = 1
那如果要为一堆对象添加属性和方法,就要使用到原型。原型(prototype)就是一次性给一堆对象添加属性和方法的对象。
一堆对象.prototype.属性或方法,例:
a.prototype = {b:1}
则:a.prototype.b = 1
这样,所有的对象都有相同的属性或者方法
那什么是原型链?
一个构造函数可以实例出一个对象,而此构造函数通过prototype又可以被一个对象赋值,构造函数+原型+对象,周而复始,直到最后没有原型,就构成了原型链。
对于原型链,我们只需要记住如果javascript在当前对象中,找不到属性和方法,就会沿着原型链一直找下去,直到找到。
继承
通过复用其他类的属性或方法,来扩展自己的属性或方法。
在javascript中就是通过原型链进行继承的,例:
function a(){
this.a = 1
}
function b(){
this.b = 2
}
a.prototype = new b() //使用原型,a既有自己创建的属性,也扩展了b的属性
var o = new a()
console.log(o.a) //输出1
console.log(o.b) //输出2
但这是存在一些问题的
1、无法通过实例化子类对象向父类中传递参数
解决方案:使用父类.call(this,参数) 传递参数。例:
function a(c){
b.call(this,c)
this.a = 1
}
function b(c){
this.b = c
}
a.prototype = new b()
var oa = new a(2)
console.log(oa.a)
console.log(oa.b)
2、如果只使用call方法,则通过原型给父类中添加属性和方法子类无法继承
解决方案:子类.prototype = new 父类,例:
function a(c){
b.call(this,c)
this.a = 1
}
function b(c){
this.b = c
}
b.prototype.d = 4 //为父类添加新的属性
a.prototype = new b() //必须使用prototype和call子类才能继承父类新添加的属性
var oa = new a(2)
console.log(oa.a)
console.log(oa.d)
3、子类对象的构造函数指向的都是父类的构造函数
解决方案:子类.prototype.constructor = 子类,例:
function a(c){
b.call(this,c) //1、通过call方法向父类中传参
this.a = 1
}
function b(c){
this.b = c
}
b.prototype.d = 4
a.prototype = new b() //2、通过原型让子类可以使用父类新添加的属性
a.prototype.constructor = a //3、把子类对象的构造函数指向子类
var oa = new a(2)
console.log(oa.constructor)