JavaScript的闭包与继承

全局变量所有函数都能调用,容易对其造成污染(改变其值造成逻辑混乱),局部变量又只能在函数体里使用,不能为全局服务重复使用,要想解决此类问题闭包是个不错的选择。

对闭包的理解:闭包能在全局函数里面操控另一个作用域的局部变量

完成闭包的三步

1.外层函数嵌套内层函数

2.内层函数使用外层函数的局部变量

3.把内层函数作为外层函数的返回值

function numCompany(){
var n=1;
function getNum(){
return n++;
};
return getNum;
}
var fn=numCompany();
console.log(fn());

 

 以上是闭包的全部过程!!!

 

继承

继承通俗来说就是子承父业,为什么要使用继承,一个字就是懒,能继承父业还奋斗个啥?

当然面向对象的语言都有继承的方法,像强语言类型的Java,C++等,但是JavaScript的面向对象是通过构造函数来实现的,所以有些许不同,但是目的都是一样的,继承父类的属性和方法。

JavaScript也有封装和多态(重写和重载),JavaScript本来就是弱语言类型,不像java那样严格,所以重写和重载会相当方便,这里不再赘述。

 

那么JavaScript是怎么实现继承的呢?     子类共享父类的属性和方法,js的继承都是基于原型实现的!!!!

JavaScript实现继承的方法有有六种 以下面的例子介绍!

//定义一个动物类

function Animal (name) {
    // 属性
    this.name = name;
    // 实例方法
    this.say= function(){
      console.log("My name is "+this.name);
    }
}
// 原型方法
Animal.prototype.eat = function(food) {
    console.log(this.name + '正在吃:' + food);
};

1.原型链继承:子类的原型指向父类的实例

function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';


var cat = new Cat();
console.log(cat.name);
cat.say();
cat.eat('fish');
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true

结论:能较好的继承,实例是子类的实例也是父类的实例,父类新增的原型方法属性子类都能访问到,但是必须要在new Animal()这样的语句之后执行,不能放到构造器中,不能实现多继承,来自原型对象的引用属性是所有实例共享的,创建子类实例时无法向构造函数传参

2.构造继承(call,apply继承)

function Cat(name){
    Animal.call(this,name);
}

var cat = new Cat("Tom");
console.log(cat.name);
cat.say();
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

结论:解决1中子类实例共享父类引用属性的问题,可以向父类传递参数,可以实现多继承(call多个父类对象),但是并不是父类的实例,而是子类的实例,只能继承父类的实例属性和方法不能继承原型上的属性和方法,无法实现函数的复用,每个子类都有父类实例函数的副本,影响性能

3.拷贝继承

 

function Cat(name){
    var animal = new Animal(name);
    for(var key in animal){
        Cat.prototype[key] = animal[key];
    }
}
// Test Code
var cat = new Cat("Tom");
console.log(cat.name);
cat.say();
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

结论:支持多继承,但是这相当于直接复制的父类的属性,效率低,内存占用高,无法获取父类的不可枚举方法(不可枚举方法,不能使用for  in访问到) 

4.组合继承(原型链和构造函数的组合)

function Cat(name){
    Animal.call(this,name);
}

Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;

// Test Code
var cat = new Cat();
console.log(cat.name);
cat.say();
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

结论:弥补2的缺陷,实例和原型都能继承,不存在引用属性共享问题,可传参,函数可复用,唯一不足就是调用了两次构造函数,生成了两份实例(子类实例将子类原型上那一份屏蔽了)

5.寄生组合继承

function Cat(name){
    Animal.call(this);
    this.name = name;
}
(function(){
    // 创建一个没有实例方法的类
    var Super = function(){};
    Super.prototype = Animal.prototype;
    //将实例作为子类的原型
    Cat.prototype = new Super();
})();

// Test Code
var cat = new Cat();
console.log(cat.name);
cat.say();
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

结论:就很完美,看起来比较复杂,实际也复杂

6.ES6继承(语法糖)

class Animal{
    constructor(name){
        this.name = name;
    }
    say(){
        alert("My name is "+this.name);
    }
    eat(food){
        alert(this.name+" is eating "+food);
    }
}
class Cat extends Animal{
    constructor(name){
        super(name);
    }
}

var  tom = new Cat("Tom");
tom.say();
tom.eat("apple");
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

结论:就用这个!!!

 学习一门语言就要熟悉它的底层原理,到时候使用岂不是信手拈来?

tips:你我山巅自相逢  

 

posted @ 2020-08-24 23:58  dabfranklin  阅读(196)  评论(0编辑  收藏  举报