闭包和继承

1.什么是闭包?

闭包的概念:闭包就是函数嵌套时,让局部变量变成自由变量的环境,是一种让局部变量进化的方式

定义在一个函数内部的函数

垃圾回收机制:用过一次的东西,先放在一个内存中,不立即删掉,可以随时进行还原或再次使用,直到没有任何作用的时候再清除

如家用电器,电脑回收站

2.闭包的应用场景

一、for循环之中:
for循环之中的i变量会因为for的循环次数被覆盖,所以在for循环内部存在函数时,而且这个函数内会调用i变量,这种情况下就需要用到闭包。

    for (var i = 0; i < 10; i++) {
        console.log(i);        //可以访问到每次的i
    }

必须满足两个条件:
1.在for循环内存在函数
2.函数内会调用这个变量

    var ali = document.getElementsByTagName("li");
    for(var i=0;i<10;i++){
        ali[i].onclick = function(){
            console.log(i);        //在函数内部就无法访问到外部变量
        }
    }
    
    //如何形成闭包
    var ali = document.getElementsByTagName("li");
    for(var i=0;i<10;i++){
        (function(a){
            ali[a].onclick = function(){
                console.log(a);
            }
        })(i)
    }

一旦内部函数调用外部函数的局部变量,那么这个时候,这个局部变量就会变成内部函数的私有变量

二、当需要给setTimeout的回调函数传参时

    setTimeout(function (a){
        console.log(a); //两秒后,undefined
    }, 2000);
    //或
    setTimeout(fn(10), 2000);
    function fn(a){
        console.log(a); //没有延迟,直接打印10
    }
    
    //使用闭包:

    function fn(a){
        return function(){
            console.log(a); //两秒后,10
        }
    }
    var f = fn(10);
    setTimeout(f, 2000);

3.闭包的特点

闭包是将函数内部和函数外部连接起来的桥梁
可以读取函数内部的变量

让这些变量的值,始终保存在内存中,不会在调用结束后被系统回收
避免全局变量命名空间的污染

内存消耗很大,不能滥用
闭包会在父函数外部,改变父函数内部变量的值

1.构造函数继承

在构造函数中,同样属于两个新创建的函数,也是不相等的

    function Fn(name){
        this.name = name;
        this.show = function(){
            alert(this.name);
        }
    }
    var obj1 = new Fn("AAA");
    var obj2 = new Fn("BBB");
    obj1.show()
    obj2.show()

此时,任何一个new出来的实例上都有了show方法,可以视为最基础的继承。

2.call/apply继承

    function Father(skill){
        this.skill = skill;
        this.show = function(){
            alert("我会"+this.skill);
        }
    }
    function Son(abc){
        //这里的this指向函数Son的实例化对象
        //将Father里面的this改变成指向Son的实例化对象,当相遇将father里面所有的属性和方法都复制到了son身上
        //Father.call(this,abc);//继承结束,call适合固定参数的继承
        //Father.apply(this,arguments);//继承结束,apply适合不定参数的继承
    }
    var f = new Father("绝世木匠”);
    var s = new Son("一般木匠");
    f.show()
    s.show();

优点:
创建子类实例时,可以向父类的构造器传参;

缺点:
只能继承构造器中定义的属性和方法,不能继承原型上定义的属性和方法

3.原型对象继承(注意深浅拷贝)

原型对象继承:继承原型
优点:简单,方便,可以继承原型身上的方式和属性
缺点:只能继承原型,不方便传参

 function Parent(n){
        this.name = n;
    }
    Parent.prototype.skill = function(){
        console.log(this.name + "是鉴定师");
    }

    function Child(n){}

    // 注意:对象的深浅拷贝
    // Child.prototype = Parent.prototype;
    for(var i in Parent.prototype){
        Child.prototype[i] = Parent.prototype[i];
    }

    // Child.prototype.skill = function(){
    //     console.log("采矿");
    // }

    var p = new Parent("大老王");
    console.log(p)
    p.skill();

    var c = new Child("小老王");
    console.log(c)
    c.skill();

4.原型链继承

原型链继承:通过给Child设置原型为Parent的实例的方式,给Child添加了一层原型链的方式
优点:既能继承原型,又能继承构造函数
缺点:复杂,不方便传参

function Parent(n){
        this.name = n;
    }
    Parent.prototype.skill = function(){
        console.log(this.name + "是鉴定师");
    }

    function Child(){}
    Child.prototype = new Parent("小老王");

    Child.prototype.skill = function(){
        console.log(12312312)
    }

    var p = new Parent("大老王");
    console.log(p)
    p.skill();
    // p是实例(对象),有__proto__属性,指向Parent.prototype

    var c = new Child();
    console.log(c);
    c.skill();

c是实例(对象),有__proto__属性,指向Child.prototype,是Parent的实例(对象),有__proto__属性,指向Parent.prototype

5.混合继承1

混合继承:构造函数继承+原型对象继承
优点:既能继承构造函数又能继承原型,方便传参,多继承
缺点:复杂

常用的继承方式之一

function Parent(n){
        this.name = n;
    }
    Parent.prototype.skill = function(){
        console.log(this.name + "是鉴定师");
    }

    function P2(){
        this.a = 10;
    }
    P2.prototype.init = function(){
        console.log("hello")
    }

    function Child(n){
        Parent.call(this,n)
        P2.call(this)
    }
    for(var i in Parent.prototype){
        Child.prototype[i] = Parent.prototype[i]
    }
    for(var i in P2.prototype){
        Child.prototype[i] = P2.prototype[i]
    }

    Child.prototype.skill = function(){
        console.log(123)
    }
   

    var p = new Parent("大老王");
    console.log(p)
    p.skill();

    var c = new Child("小老王");
    console.log(c)
    c.skill();
    c.init();

6.混合继承2

ES6的class继承:原理↓↓↓
混合继承:构造函数+原型链

优点:简单方便易操作,语法层面的继承,属性和方法都能继承,参数很好处理
缺点:兼容性

忽略兼容,常用的继承方式之一

class Parent{
        constructor(n) {
            this.name = n
        }
        skill(){
            console.log(this.name + "是鉴定师")
        }
    }

    class Child extends Parent{
        constructor(n){
            super(n)
        }
    }

    var p = new Parent("大老王");
    console.log(p)
    p.skill();

    var c = new Child("小老王");
    console.log(c)
    c.skill();

构造函数,原型,实例之间的关系:

1.构造函数Fn身上有属性prototype为原型对象,原型对象内有constructor属性指向当前prototype所在的构造函数Fn

2.在new执行构造函数Fn时,创造了一个实例对象f,实例对象f的__proto__指向构造函数Fn的原型prototype

3.因为实例对象f的__proto__指向构造函数Fn的原型prototype,所以实例对象f可以间接访问到Fn原型prototype的方法

在这里插入图片描述

查看实例对象f是否有指针指向构造函数Fn的原型:

isPrototypeOf()用于检测两个对象之间似乎否存在这种关系,使用方法如下:

Fn.prototype.isPrototypeOf(f) // 查看 Fn 的 prototype 对象,是否是 f 原型

类似的还有instanceof运算符,使用方法如下:
console.log(f instanceof Fn) // 查看 f 对象是否是构造函数 Fn 的实例
console.log(f instanceof Object)

两种使用,如果是返回ture,如果不是返回false

注意:instanceof运算符右侧为构造函数,并且js中所有原型都来自Object构造函数

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值