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   对

 

 

 

 

 

 

posted @ 2019-08-17 15:51  hongdou_hh  阅读(388)  评论(0编辑  收藏  举报