JavaScript原型链,闭包closures,面向对象编程,对象的继承

18-原型链

var f=new Object( );

  • f对象实例上有一个_ _proto__属性指向Object原型对象
  • Object原型对象上有一个constructor属性指向Object
  • Object上有一个prototype属性指向原型对象

除null之外所有的对象都有_ _proto__属性,这个属性指向当前对象的内部原型对象。

见笔记 js对象

构造函数的原型,构造函数都有_ proto_

所有函数的原型的_ _proto__都指向Object.prototype(除掉Function)

  • 构造函数的原型上的_ _proto__指向Object.prototype

  • Object的原型上的_ _proto__指向null

  • 构造函数上的_ _proto__指向Function.prototype(这是一个空函数)

  • Function原型上的_ _proto__指向Object.prototype

在这里插入图片描述

Function.prototype是所有函数的根

Object对象的_ _proto__属性指向Function.prototype

*19-闭包(closures)

闭包引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。

闭包是一个函数和函数所声明的词法环境的结合。

<script>
        function f1(x)
        {
            var tmp=3;
            return function(y)
            {
                console.log(x+y+tmp);
            }
        }

        //调用f1方法,并把匿名函数返回给bar
        //bar中有f1函数的x变量  tmp变量     匿名函数
        //f1函数执行完成 tmp和x也不会释放
        var bar=f1(5);  //此时bar指向匿名函数。bar是一个闭包。
        bar(10);
    </script>
闭包的相关应用

1. 匿名自执行函数(匿名函数模拟块级作用域)

注意,尽量少定义全局变量。

;(function (a)
        {
            var m=10;   //这里定义的变量只能在函数体内使用
            console.log(a);
        })(6);          //立即执行

        //也可以这样写,但是不推荐
 ;(function(a)
        {
            console.log(a);
        }(5))

;(匿名函数)(传入的参数)

2.循环注册dom事件

var aLi=document.getElementsByTagName("li");

             for(var i=0;i<aLi.length;i++)
            {
                aLi[i].onclick=function()
                {
                    console.log(i);     //因为循环事件先发生,所以打印的结果都是5
                }
            } 



            //利用闭包解决
            for(var i=0;i<aLi.length;i++)
            {
                ;(function (a){
                    aLi[a].onclick=function()
                    {
                        console.log(a);
                    }
                })(i);              //将i作为参数传入到自执行的函数中 0-4,传的参数是值的赋值
            }

3.定时器中闭包的应用

//利用闭包解决问题
        for(var i=0;i<5;i++)
        {
            (function(a)
            {
                setTimeout(function(){
                    console.log(a);
                },1000*a)
            })(i);          //i只传入了0-4
        } 


//利用let解决问题
        for(var i=0;i<5;i++)
        {
            let k=i;
            setTimeout(function()
            {
                console.log(k);
            },1000*k);
        }
闭包缺点
  • 闭包会导致JavaScript执行效率下降。(目前V8引擎已经对闭包做了很多性能优化,基本不用考虑)
  • 闭包导致内存会驻留,如果是大量对象的闭包环境注意内存消耗。
闭包模拟私有变量/获取设置私有变量
 //方法1
        function creat()
        {
            var age=0;
            this.getAge=function()
            {
                return age;
            }
            this.setAge=function(a)
            {
                age=a;
            }
        }

        var p=new creat();
        p.setAge(10);
        console.log(p.getAge());

        //方法2
        function creat2()
        {
            var age=0;
            return{
                getAge:function()
                {
                    return age;
                },
                setAge:function(a)
                {
                    age=a;
                }
            }
        }

        var p2=creat2();
        p2.setAge(20);
        console.log(p2.getAge());

20-面向对象编程

工厂模式创建对象
function CreatCat(age,name)
        {
            var a=new Object();
            a.name=name;
            a.age=age;
            a.run=function()
            {
                console("cat is running");
            }
            return a;
        }

        var cat=CreatCat(10,'pink');
		cat instanceof CreatCat;	//false
		cat instanceof Object;		//true

工厂模式是标准化的生成默认对象的函数

优点:

  1. 可以进行批量创建,都有公共默认值和属性的对象

缺点:

  1. 对象的方法不能跟其他对象共享,多占内存
  2. 不能识别对象的原型以及构造函数
构造函数创建对象
function CreatCat()
        {
            this.age=10;
            this.name='cat';
            this.run-function()
            {
                console.log("is running");
            }
        }

        var cat1=new CreatCat();
        var cat2=new CreatCat();

        cat1.age=20;
        console.log(cat1.age);
        console.log(cat2.age);

		cat1 instanceof CreatCat;	//true
        cat1 instanceof Object;		//true

当使用new来调用构造函数的时候经历了以下过程

  1. 创建一个空对象cat1
  2. 把空对象赋值给this
  3. 执行构造函数里面的代码,并给this的属性赋值初始化
  4. 把新创建的对象返回(如果有返回值,简单类型:直接忽略并返回this,引用类型:直接返回引用类型)

优点:

  1. 创建对象的时候默认初始化一些属性
  2. 可以进行使用instance追溯对象的原型以及构造函数
  3. cat1.constructor===CreatCat (cat1继承了构造函数原型上的方法所以cat1可以使用constructor方法)

缺点:

  1. 对象的方法不能进行重复使用,每个对象里面都要存储一份方法对象,浪费内存。
原型创建对象

利用prototype给原型添加属性和方法。

组合模式创建对象

组合使用构造函数模式与原型模式

公共的属性和方法放到 原型上,独有的属性使用构造函数模式,放到对象自己身上。

优点:

  1. 既保证了方法等共享的属性能只在内存中保存一份,节省内存。
  2. 又可以实现每个对象有自己单独存放的属性。是一种经典的构建对象的方法
function CreatCat()
        {
            this.age=10;
            this.name='cat';
        }

        CreatCat.prototype.run=function()
        {
            console.log("is running");
        }
        
        var cat1=new CreatCat();
稳妥构造函数创建对象
function CreatCat()
        {
            var a=new Object;
            a.name='qwe';
            a.age=18;
            a.run=function()
            {
                console.log('run');
            }
            return a;
        }

        var c1=new CreatCat();
        var c2=CreatCat();

可以用new创建也可以不用new创建。

21-对象的继承

原型继承模式
function Animal(age,name)
        {
            this.go=function()
            {
                console.log('go running');
            }
        }

        Animal.prototype.run=function()
        {
            
            console.log('is running');
            
        }

        function  Cat(age,name)         //Cat和Animal有同样的属性
        {
            this.age=age;
            this.name=name;
            
        }

        //原型继承的方法
        Cat.prototype=new Animal();     //将animal的属性以及原型上的属性继承给cat的原型
        Cat.prototype.constructor=Cat;  //因为前面的代码cat原型上的constructor会指向animal,这里把它还原
        var c1=new Cat(10,'luck');
        c1.go();		//调用了Animal上的方法
        c1.run();		//调用了Animal.prototype上的方法

缺点:

  1. 子类构造函数的参数没法传递给父类的构造函数
  2. 子类的原型的constructor会被改变,需要自己改回来
  3. 所有子类共用一个父类的引用类型的属性
组合继承模式
function Animal(age,name)
        {
            this.age=age;
            this.name=name;
            this.go=function()
            {
                console.log('go running');
            }
        }

        Animal.prototype.run=function()
        {
            
            console.log('is running');
            
        }

        function  Cat(age,name)         //Cat和Animal有同样的属性
        {
            //第一次执行父类的构造函数
            Animal.call(this,age,name); //将animal的this指向为cat的this
        }

		//第二次执行父类的构造函数
        Cat.prototype=new Animal();
        Cat.prototype.constructor=Cat;

        var c1=new Cat(12,'qw');
        console.log(c1.age);
原型式继承

原型式继承是避免调用父类构造函数的一种巧妙的方式。本质就是借用对象来构造另外一个对象。

缺点:

  1. 原型对象上的引用类型的属性会造成子类对象进行共享。
function object(o)
        {
            function F(){};
            F.prototype=o;
            return new F();
        }

        var m={age:12,name:'qwe'};

        var m1=object(m);           //使空函数的prototype==m并把空函数返回给m1
        var m2=Object.create(m);    //和上面一样,ECMAScript6中已经将上面的方法封装成create
        console.log(m2.age);
        console.log(m1.age);
寄生继承(原型式继承的扩展)
function object(o)
        {
            function F(){};
            F.prototype=O;
            return new F();
        }

        function cat (c)
        {
            var p=object(c);
            p.say=function()
            {
                console.log('hi');
            }

            return p;
        }
*最终继承方案,寄生组合继承
function Animal(age,name)
        {
            this.name=name;
            this.age=age;
        }

        Animal.prototype.run=function()
        {
            console.log('is running');
        }

        function Cat(age,name)
        {
            Animal.call(this,age,name);     //将this,age,name指向animal
        }

        function inheritFrom(o)             //寄生继承
        {
            var t=Object.create(o);
            t.constructor=Cat;
            return t;
        }    


        Cat.prototype=inheritFrom(Animal.prototype); //寄生继承 
        var cat=new Cat(10,'lucy');                  //组合继承

        cat.run();
        console.log(cat.age);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值