• 一步步了解构造函数


    一、关于对象

           在了解构造函数之前,我们需要先了解下对象,我们都听说面向对象编程,那么这当中的对象是什么,简单来说,对象是个功能模块,这个功能可以接收信息,处理信息和发送信息。从我们代码的角度看,对象是一个封装了属性和方法的容器,属性是对象的状态,方法则是对象的行为(完成某种任务)。我们可以用这个对象对现实生活中的实物进行抽象描述,比如,我们把飞机看做对象,那么可以使用“属性”记录具体是哪种机型,同时使用“方法”表示飞机的表现行为,是起飞、飞行中还是降落等。紧接着,我们把飞行员看做对象。使用“属性”记录飞行员的信息,使用“方法”表示飞行员对飞机的操作,那么飞行员对飞机的操作、飞机的表现行为之间构成的关系,可以抽象为两个对象之间的关系,这种用代码对象模拟现实情况的操作,就是面向对象编程。

    二、什么是构造函数

           使用面向对象编程,第一步就是要创造对象,在js中,构造函数是创建对象的方式之一,构造函数(简称constructor)其实就是一个普通函数的升级版函数,区别于普通函数就在于用法不同,构造函数是可以提供模板,用来生成多个对象的函数,你也可以理解为,一个普通函数可以被多次使用生成不同的对象,那么这个普通函数就是构造函数,在写法上,为了容易辨认构造函数,构造函数名字的第一个字母通常大写,构造函数中必定存在this,普通函数也可以存在this,this指向Window全局。一个简单的构造函数如下:

    var i = 0
    function
    Plane (type) { this.type = type this.state = function () { console.log(type + '起飞') }
    i ++
    console.log(i)
    console.log(this) }
    Plane()  // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …};type与state是Window对象的一个属性方法  

    三、为什么要使用构造函数

        构造函数是可以提供模板,用来生成多个对象的函数,对一个新创建的对象进行初始化,可以减少我们许多重复的代码,比如要创建许多种飞机的对象,我们可以通过构造函数先初始所有飞机共用的属性和行为表现,之后传值调用构造函数即可,无需每个飞机种类都去声明一个对象。

    四、如何使用构造函数

      直接调用构造函数,则相当于是调用一个普通函数,要使构造函数得到复用,则需要结合new,通过new调用构造函数来实例化创建新的对象,比如创建波音飞机和枭龙战机的对象,调用上述构造函数,为:

      var boyin = new Plane('波音'); // 构造函数执行一遍,输出 Plane {type: "波音", state: ƒ},1

      boyin.state(); // 波音起飞

      var xiaolong = new Plane('枭龙')  // 构造函数再执行一遍,输出 Plane {type: "枭龙", state: ƒ},2

      xiaolong.state(); // 枭龙起飞

    五、为什么new可以实现调用构造函数实例化创建新的对象

     通过new调用构造函数来实例化创建新的对象,这个过程中,发生了一下五个步骤:

     1、建立一个名为变量的空变量

     2、将新对象的_proto_属性指向构造函数的prototype原型

     3、将构造函数中的this指向新对象

     4、执行一遍构造函数中的代码

     如果使用代码来模拟这个过程,如下:

     new Plane("波音") = {
        var obj= {}; // 声明空对象
        obj.__proto__ = Plane.prototype; // 设置对象的_proto_属性来链接到函数的prototype属性
        var result = Plane.call(obj,"波音"); // 通过call改变this指向,同时执行Plane方法和传值
        return typeof result === 'object'? result : obj;  // 将结果返回
    }

      其中,关于obj._proto_ = Plane.prototype,是设置对象的_proto_属性来链接到函数的prototype属性,当我们访问新构建的对象的属性和方法时,会先在构造函数上找,找不到就沿着原型链向上追溯。

      在这里可以说下关于_proto_和prototype。

      _proto_是一个对象拥有的内置属性(请注意:每个对象都有一个_proto_属性,_proto_是对象的内置属性),是JS内部继承和使用构造函数以及寻找函数原型链上的属性和方法的属性。

      prototype是函数的一个属性((请注意:每个函数都有一个prototype属性,prototype是函数的内置属性),这个属性是一个指针,指向一个对象。这个对象你可以理解为包含构造函数以及其原型上的属性和方法,同时包含其他内容的大对象。有趣的是,prototype是个对象,也具有_proto_

     

       回归obj._proto_ = Plane.prototype,从上面打印出来的a对象的_proto_以及b函数的prototype,可以看出共同拥有constructor属性,每一个对象实例都可以通过 constrcutor 对象访问它的构造函数,因此obj._proto_ = Plane.prototype就将obj对象与Plane函数关联起来了。拥有了Plane函数的属性和方法。

       我们在构造函数Plane的原型上添加属性和方法,在new实例化后通过对象访问,结果对象是能访问到的:

         

    、多用途构造函数,关于构造函数中的return

            一个构造函数内部使用了return,就可以成为一个多用途构造函数,具体可看下例子:

    function C2(a, b){
        this.p = a + b;
        this.alertP = function(){
            alert(this.p);
        }
        return this.p;//此返回语句在C2作为构造函数时没有意义
    }
    var c2 = new C2(2,3);
    c2.alertP();//结果为5
    alert(C2(2, 3)); //结果为5

           构造函数中如果加入了return的话,需要注意分两种情况

         1. return的是五种简单数据类型:String,Number,Boolean,Null,Undefined,则new实例化构造函数时,return回来的是空对象

         2、如果return的是对象,则new实例化构造函数时,return回来的是对象

    、es6中构造函数的写法

         我们用es6写法来改上面的es5写法构造函数:

    let i = 0
    class Plane {
       constructor(type) {
          this.type = type
       }
       state () {
         console.log(this.type + '起飞')
         i ++
         console.log(i)
         console.log(this) 
       }
    }

          上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,里面存放属性值,而this关键字则代表实例对象。至于函数方法,需要注意,定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。还有,不能在类里面添加多余代码,比如把“i++”和“console”等放到state方法之外。这也严格限制了在构造函数中添加多余代码。

           class做了什么呢,就是将所有方法都写在构造函数的prototype属性上,上面的写法实际等于,所以在类的实例上面调用方法,其实就是调用原型上的方法。

      Plane.prototype = {
        constructor(type) {this.type = type},
        state (type) {console.log(type + '起飞')}
      }

          使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致,不同的是调用方法需要传参了。

      var boyin = new Plane('波音');
      boyin.state(); // 波音起飞

          关于es6的class类,还有很多东西可以了解,且看下会分解~~~

  • 相关阅读:
    PHP的这些基础知识你应该熟知
    PHP版的猴子选大王算法
    Linux常用命令,面试常考
    PHP中常见的数字掐头去尾操作方法
    永久重定向301与临时重定向302区别
    WordPress子模板继承
    双系统引导设置
    OpenCv
    SpringBoot后端跨域问题
    存储式参数校验
  • 原文地址:https://www.cnblogs.com/ahao68/p/9430791.html
Copyright © 2020-2023  润新知