1,什么是闭包:
闭包就是能够读取其他函数内部变量的函数。在js中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解为“定义在一个函数内部的函数”。
2,闭包的特点:
1),可以读取函数内部的变量。
2),让这些变量的值始终保存在内存中。
3,闭包的原理
理解闭包,首先必须理解js变量作用域。变量的作用域无非就是两种:全局变量和局部变量。
js语言的特殊之处,就在于函数内部可以直接读取全局变量。另一方面,函数外部自然无法读取函数内的局部变量。
4:闭包的应用场景
1:函数作为返回值。
2:函数作为参数被传递。
5:构造函数继承:
1),第一种继承
//继承的第一种方式
function Parent(username){
this.username = username;
this.hello = function(){
console.log(this.username)
}
}
function child (username,password){
//通过一下3行实现继承
//1,this.method是一个临时属性,并且指向Parent所指向对象,
//2,执行this.method方法,即执行Parent所指向的对象函数
//3,删除this.method属性,即此时Child就已经拥有了Parent所有属性和方法
this.method = Parent;
this.method(username);//最为关键的一行
delete this.method;
this.password = password
}
2),用call和apply:就是改变函数内部this的指向,二者作用完全一样,知识接受参数的方式不太一样。
call是以列表的形式传参 fn.call(obj,arg1,arg2);
apply是以数组方式传参 fn.apply(obj,[arg1,arg2])
call方法是Function类中的方法
call方法的第一个参数的值赋值给类(即方法)中出现的this
call方法的第二个参数开始依次赋值给类(即方法)所接受的参数
apply方法接受2个参数,
A、第一个参数与call方法的第一个参数一样,即赋值给类(即方法)中出现的this
B、第二个参数为数组类型,这个数组中的每个元素依次赋值给类(即方法)所接受的参数
function Parent(username){
this.username = username;
this.hello = function(){
console.log(this.username)
}
}
function child (username,password){
Parent.call(this,username)
this.password = password;
this.word = function(){
alert(this.password);
}
}
function child1 (username,passworf){
parent.apply(this,new Array(username));
this.password = password;
this.word = function(){
alert(this.password);
}
}
3),原型
构造函数的缺点:JavaScript 通过构造函数生成新对象,因此构造函数可以视为对象的模板。实例对象的属性和方法,可以定义在构造函数内部。同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费。
prototype概念:每一个构造函数都有一个prototype属性,这个属性会在生成实例的时候,成为实例对象的原型。
JavaScript 的每个对象都继承另一个对象,后者称为“原型”(prototype)对象。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。null也可以充当原型,区别在于它没有自己的原型对象。
JavaScript 继承机制的设计就是,原型的所有属性和方法,都能被子对象共享。
function Animal(name) {
this.name = name;
}
Animal.prototype.color = 'white';
var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');
cat1.color // 'white'
cat2.color // 'white'
上面代码中,构造函数Animal的prototype对象,就是实例对象cat1和cat2的原型对象。原型对象上添加一个color属性,结果,实例对象都继承了该属性。
4)原型链
对象的属性和方法,有可能定义在自身,也有可能定义在它的原型对象。由于原型本身也是对象,又有自己的原型,所以形成了一条原型链(prototype chain)。比如,a对象是b对象的原型,b对象是c对象的原型,以此类推。
如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。那么,Object.prototype对象有没有它的原型呢?回答是有的,就是没有任何属性和方法的null对象,而null对象没有自己的原型。
“原型链”的作用是,读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overriding)。
需要注意的是,一级级向上,在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。
5):原型链的继承
将一个构造函数的原型指向另一个构造函数的实例对象来实现继承。
function Box() { //Box构造
this.name = 'Lee';
}
function Desk() { //Desk构造
this.age = 100;
}
Desk.prototype = new Box(); //Desc继承了Box,通过原型,形成链条
var desk = new Desk();
alert(desk.age);
alert(desk.name); //得到被继承的属性
function Table() { //Table构造
this.level = 'AAAAA';
}
Table.prototype = new Desk(); //继续原型链继承
var table = new Table();
alert(table.name); //继承了Box和Desk
6),混合继承
组合继承就是结合使用原型链与构造函数的优点,组合而成的一个模式。实现也很简单,既然是结合,那当然结合了两方的优点
即原型链继承方法,而在构造函数继承属性。
function Box(age) {
this.name = ['Lee', 'Jack', 'Hello']
this.age = age;
}
Box.prototype.run = function () {
return this.name + this.age;
};
function Desk(age) {
Box.call(this, age); //对象冒充 继承了 name 和age 属性
}
Desk.prototype = new Box(); //原型链继承 run方法
var desk = new Desk(100);
alert(desk.run());