javaScript中的闭包,继承,创建对象
一.闭包在javaScript中呢也是比较难理解的一个知识点
1.代码检测
2.预编译
<1.函数在执行前的一瞬间,会生成一个AO对象
<2.函数的形参作为AO对象的属性名,实参作为ao对象的属性值
<3.分析var声明,变量名作为AO对象的属性名,值为undefined,如果遇到和参数同名,不去做任何改变
<4.分析函数声明,函数名作为AO对象的属性名,值为函数体,如果遇到同名,直接覆盖
3.逐行执行(预编译基础之上)
首先,大家都知道javaScript解析代码,是从上往下执行的,在我们写好程序后系统会自动代码检测,检测写的代码有没有语法错误
代码检测之后,函数在执行之前会预编译。
例如1:
function fun(a){
console.log(a)
var a = 100
console.log(a)
}
fun(10)
在这个函数中,代码执行前,首先会生成一个AO对象
fun.AO={
形参作为属性名,实参作为属性值
a = 10;
分var声明,如果遇到和参数同名,不做任何改变
}
例如2:
function fun(a){
console.log(a)
function a (){
}
console.log(a)
var a = 100;
console.log(a)
var a = function(){
}
console.log(a)
a = 10
console.log(a)
}
fun(100)
fun.AO={
形参作为属性名,实参作为属性值
a=function
分var声明,如果遇到和参数同名,不做任何改变
分析函数声明,函数名作为AO对象的属性名,值为函数体,如果遇到同名,直接覆盖
所以输出结果为function a (){ } ,function a(){ },100,function(){ },10
}
二.js中的call,aplly,bind方法
call( ) 改变this指向,借用别人的方法,完成自己的事情,需要把实参按照形参的个数传进去
apply 需要创一个arguments 里面需要注意实参和形参的顺序
bind( ) 基于一个现有函数,创建一个新函数,并永久绑定this不但可以永久绑定this,还可以永久绑定部分参数
他们三个之间的区别?
call和apply:临时借用一个函数,并替换this为指定对象;不同之处,传参的方式不一样,使用后立即执行
bind:基于现有函数,创建一个新函数,并永久绑定this为指定对象,可以绑定参数只创建函数,不执行
三.继承
父类:
function person(name){
this.name = name;
}
person.prototype.age = 10;
1.原型链继承
function per(){
this.name = Tom;
}
per.prototype = new person();
var per1 = new per();
让per1继承了person的属性
重点:让新实例的原型等于父类的实例。
特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
2.借用构造函数继承
function fun( ){
person.call(this,"jerry");
this.age = 12;
}
var fun1 = new fun();
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
3.组合继承(组合原型链继承和借用构造函数继承)(常用)
function fun(name){
person.call(this,name);
}
fun.prototype = new person();
var fun1 = new fun("mary");
重点:结合了两种模式的优点,传参和复用
特点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
4.原型式继承
先封装一个函数容器,用来输出对象和承载对象的原型
function fun (obj){
function f( ){};
f.prototype = obj; 继承了传入的参数
return new f(); 返回函数对象
}
var a = new person();
var a1 = fun(a);拿到父类的实例
重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:1、所有实例都会继承原型上的属性。
2、无法实现复用。(新实例属性都是后面添加的)
5.寄生式继承
function fun (obj){
function f( ){};
f.prototype = obj; 继承了传入的参数
return new f(); 返回函数对象
}
var a = new person();
function sub(obj){
var sub1 = fun(obj);
var sub1.name= "Tom";
return sub1;
}
var a1 = sub(a); 这个函数经过声明之后就成可增添属性的对象
重点:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
缺点:没用到原型,无法复用。
6.寄生组合式继承(常用)
寄生:在函数内返回对象然后调用
组合:1、函数的原型等于另一个实例。2、在函数中用apply或者call引入另一个构造函数,可传参
function fun (obj){
function f( ){};
f.prototype = obj; 继承了传入的参数
return new f(); 返回函数对象
}
var fun1 = fun.(prototype); fun1的原型继承了父类函数的原型
组合
function sub(){
person.call(this)
}
sub.prototype = fun1; 继承fun1的实例
fun1.constructor = sub; 修复实例
var sub1 = new sub(); sub的实例就继承了构造函数的属性,父类实例,fun的函数属性
四.创建函数
1、直接量
var obj = {} //--> new Object()
2、构造函数创建对象的方式 批量创建
function F() {}
var obj1 = new F();
3、使用new关键字
var obj2 = new Object();
所有对象都继承自Object.prototype 不对
绝对多数的对象都继承自Object.prototype 对