JS闭包与继承

1、什么叫js闭包?
       首先要知道js的特性:函数内部可以直接读取全局变量,但是函数的外部无法直接读取函数的内部变量。
ps:注意点:在函数内部声明变量的时候,一定要使用var命令。如果不用的话,你实际上声明的是一个全局变量!
      “闭包”就是我们在函数内的私有属性能够在外部访问,闭包可以简单理解成“定义在一个函数内部的函数“。
       JS中,提供了一种”闭包”的概念:在函数内部,定义一个子函数,可以用子函数访问父函数的私有变量。执行完操作以后,将子函数通过return返回。
代码:

function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}

2、“闭包”的作用:
(1)、访问函数的私有变量
(2)、让函数的变量始终存在于内存中而不被释放

3、使用“闭包”的注意点
(1)、闭包有一个非常严重的问题,那就是内存浪费问题,这个内存浪费不仅仅因为它常驻内存,更重要的是,对闭包的使用不当会造成无效内存的产生
解决方法是,在退出函数之前,将不使用的局部变量全部删除。
(2)、闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

4、什么叫js继承?
       一般OOP语言都支持俩种继承方式:接口继承和实现继承。
Javascript是只支持实现继承,主要依靠原型链来实现的,一般实现的方法都是通过写prototype的方式,继承后的子对象会拥有父对象的属性和方法。
构造函数,原型和实例的关系:每一个函数都有一个原型对象, 每一个原型对象都有一个指向构造函数的指针,而实例包含了一个指向原型对象的内部(不可见的)指针

5、如何实现js继承?
第一种:prototype方法

//父类
function person(){
    this.hair='black';
    this.eye='black';
    this.skin='yellow';
    this.view=function(){
    return this.hair+','+this.eye+','+this.skin;
    }
    }
//子类    
function man(){
    this.feature=['bread','strong'];
    }
//继承
man.prototype=new person();
var one=new man();

document.write(one.feature);    
document.write(one.hair);
document.write(one.eye);
document.write(one.skin);
document.write(one.view());

第二种:aaply方法

//父类
function person(){
    this.hair='black';
    this.eye='black';
    this.skin='yellow';
    this.view=function(){
    return this.hair+','+this.eye+','+this.skin;
    }
    }
//子类    
function man(){
    // person.apply(this,new Array()); 
  person.apply(this,[]); 
  this.feature=['bread','strong'];
    }
//继承

var one=new man();

document.write(one.feature);    
document.write(one.hair);
document.write(one.eye);
document.write(one.skin);
document.write(one.view());

注意:如果apply参数为空,即没有参数传递,则通过 new Array() 、[] 来传递,null 无效。

第三种:call+prototype的方法

//父类
function person(){
    this.hair='black';
    this.eye='black';
    this.skin='yellow';
    this.view=function(){
    return this.hair+','+this.eye+','+this.skin;
    }
    }
//子类    
function man(){
    // person.apply(this,new Array()); 
  person.call(this,[]); 
  this.feature=['bread','strong'];
    }
//继承
man.prototype=new person();
var one=new man();

document.write(one.feature);    
document.write(one.hair);
document.write(one.eye);
document.write(one.skin);
document.write(one.view());

ps:call方式的实现机制却要多一条 man.prototype = new person(); 为啥呢?
因为call方法只实现了方法的替换而没有作对象属性的复制操作。

6、三种继承方法的优缺点:
如果构造函数带有参数,比如说function person(hair,eye,skin){…}
那么就只能用apply方法或call方法了

//apply方法
function man(hair,eye,skin){
  person.apply(this,[hair,eye,skin]); 
  this.feature=['bread','strong'];
}
//call方法
function man(hair,eye,skin){
  person.apply(this,hair,eye,skin); 
  this.feature=['bread','strong'];
}

apply的缺点:在apply方法继承后,上述中的one实例就不属于person函数了,即(one instanceof person)的值为false。
第三种继承方式也有缺陷:子类new对象时要传一遍父类所需的参数,而且会重现父类中的属性和方法
最好的方法:

function Person(name){   
  this.name = name; 
} 

Person.prototype.getName = function() { 
  return this.name; 
} 

function Chinese(name, nation) { 
  Person.call(this, name); 
  this.nation = nation; 
} 

//继承方法 
function inherit(subClass, superClass) { 
  function F() {} 
  F.prototype = superClass.prototype; 
  subClass.prototype = new F(); 
  subClass.prototype.constructor = subClass.constructor; 
} 

inherit(Chinese, Person); 

Chinese.prototype.getNation = function() { 
  return this.nation; 
}; 

var p = new Person('shijun'); 
var c = new Chinese("liyatang", "China"); 

console.log(p); // Person {name: "shijun", getName: function} 
console.log(c); // Chinese {name: "liyatang", nation: "China", constructor: function, getNation: function, getName: function} 


console.log(p.constructor); // function Person(name){} 
console.log(c.constructor); // function Chinese(){} 

console.log(c instanceof Chinese); // true 
console.log(c instanceof Person); // true

猜你喜欢

转载自blog.csdn.net/dj_fairy/article/details/78549106