最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 轻松搞懂构造函数,new,实例对象,原型,原型链,ES6中的类 | 技术点评

    正文概述 掘金(辉夜真是太可爱啦)   2021-03-08   565

    前言

    本文主要讲的就是函数,方法,构造函数,new操作符,实例对象,原型,原型链,ES6类。因为这几个知识点都是有互通的关系的,所以一起讲,方便大家疏通整个关于这方面的知识体系。希望对大家有帮助,看完能有一种醍醐灌顶的感觉。当然,文中如有错误的,也请评论指出。

    你的收获:
    • 函数和方法的区分
    • 函数和构造函数的区分
    • new 操作符到底做了哪些事情
    • 如何自己实现一个 new
    • 什么是实例对象
    • new 的缺点以及为什么需要继承
    • Javascript 是如何实现继承的
    • 什么是原型
    • prototype 以及 __proto__constructor
    • 什么是原型链
    • ES6 class 只是一种语法糖,以及它的实现方式

    构造函数

    在讲构造函数之前,先来讲下函数和方法

    • 函数

      • 函数是可以执行的 javascript 代码块,由 javascript 程序定义或 javascript 实现预定义
      function fn(){
        //to do something
      }
      
    • 方法

      • 通过对象调用的 javascript 函数
      obj = {
        fn(){
          //to do something
        }
      }
      

    总结而言,独立执行的 JS代码块 就是所谓的函数,而在对象中,需要通过对象调用的函数,就是所谓的方法。

    再来讲一下这部分的主题,那就是构造函数, show you code

    • 构造函数
    function Fn(){
      //to do something
    }
    

    构造函数与函数的异同

    1. 命名方式不同

      构造函数使用大驼峰方式,而普通函数使用小驼峰方式,虽然没有强制要求,但是一般书写方式都这样子,便于区分

    2. 是否通过 new 操作符来调用的

      通过 new 操作符来调用就是构造函数,反之,不通过 new 操作符就是普通函数

    3. this 指向不同

      普通函数中 this 指向为 window ,而构造函数中 this 指向的是实例,当然,这也与 new 操作符所做的事情有关,在下一个板块中我们来说一说 new 操作符

    new 操作符

    从上面我们也大概知道了,就是构造函数需要使用 new 操作符进行调用,也就是相当于, new 操作符就是区分函数和构造函数的钥匙。

    但是,不知道大家有没有想过一个问题,那就是 Fn 明明是一个构造函数,为什么经过 new 以后,就能返回一个实例对象

    那么,我们就来说一说 new 操作符,到底做了哪些事情

    那么,接下来我们可以自己实现一个 new 方法

    // const xxx = _new(Person,'cooldream',24)  ==> new Person('cooldream',24)
    function _new(fn,...args){
        // 新建一个对象 用于函数变对象
        const newObj = {};
        // 将空对象的原型地址 `_proto_` 指向构造函数的原型对象
        newObj.__proto__ = fn.prototype;
        // this 指向新对象 
        fn.apply(newObj, args);
        // 返回这个新对象
        return newObj;
    }
    

    实例对象

    前面介绍完了 new 操作符以及构造函数,接下来就是他们的生产物,实例对象

    比方说 let person = new Person(); ,那么, person 就是所谓的实例对象,实例对象就是通过构造函数配合 new 生成的,而这个过程,我们也称之为实例化

    new 操作符的缺点

    通过上面对于 new 实例化过程的学习,我们大概也知道,每一个实例对象的内存都是独立的,也就是所谓的深拷贝,关于深浅拷贝,不懂的可以移步到我的这一篇博客 一文搞懂JS系列(二)之JS内存生命周期,栈内存与堆内存,深浅拷贝

    因为每一次 new 操作,都会开辟新的内存,所以每一个实例对象,都有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费。

    毕竟大家都知道,一般设计模式讲究区分变与不变,具体的大意就是将变与不变分离,达到使变化的部分灵活、不变的地方稳定的目的。将所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。

    上面这段话可能有点绕,我们还是来讲个例子吧。就像数组都有一个自带的属性,叫 length ,用来描述数组的长度,毕竟,只要是一个数组,它就会有长度,大不了就是空数组,长度为0。而这个 length ,就是上面实例对象需要共享的属性。就是所谓不变的地方,大家都互通。而这个共享的属性和方法,就叫做原型。例如,可以看下图的 Arrayprototype 。而这个,就是 Javascript 的继承机制。下面我们就来看看为什么,Javascript 要采用这种继承机制,而不是 Java 的"类"。

    轻松搞懂构造函数,new,实例对象,原型,原型链,ES6中的类 | 技术点评

    Javascript 独特的继承

    先让我们来了解一下 JS 独特的继承方式。以下的内容参考于阮一峰的 Javascript继承机制的设计思想,当然,你也不需要去看这篇文章,我会在下面来描述这方面的知识。

    我们都知道,JS 的设计初衷知识用于网页脚本语言,他觉得,没必要设计得很复杂,这种语言只要能够完成一些简单操作就够了,比如判断用户有没有填写表单。

    正是因为设计初衷就比较简易,其实不需要有"继承"机制。但是,Javascript 里面都是对象,必须有一种机制,将所有对象联系起来。所以,JS作者 最后还是设计了"继承"。

    至于为什么打上引号,我想学过 Java 的都应该知道类,但是, Javascript 并没有引入"类", 因为一旦有了"类",Javascript就是一种完整的面向对象编程语言了,这好像有点太正式了,而且增加了初学者的入门难度。

    他考虑到,C++和Java语言都使用new命令,生成实例,他也将 new 引入了 JS 的设计之中。但是,Javascript没有"类",怎么来表示原型对象呢?

    这时,他想到C++和Java使用new命令时,都会调用"类"的构造函数(constructor)。他就做了一个简化的设计,在Javascript语言中,new命令后面跟的不是类,而是构造函数。

    总结而言,Java 中通过 new 类,生成实例对象,那么, Javascript 是通过 new 构造函数(constructor)来生成实例对象。这些概念在上面都已经有所提及。

    原型

    所有 JavaScript 对象都从原型继承属性和方法

    先来一段贯穿整个原型板块的代码

    function Person(){
    
    }
    
    let person = new Person();
    

    根据上面的学习,可以看出来,构造函数 Person 和 实例对象 person

    • prototype

      每个函数都有一个 prototype 属性。

      每一个 JavaScript 对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。

      所以,上面代码用 prototype 所指向的原型,就是 Person.prototype

      轻松搞懂构造函数,new,实例对象,原型,原型链,ES6中的类 | 技术点评

    • __proto__

      每一个 JavaScript 对象(除了 null )都具有的一个属性,叫 __proto__ ,这个属性会指向该对象的原型

      所以,上面代码用 __proto__ 所指向的原型,就是 person.__proto__

      既然上下都指向原型,可以得出 person.__proto__ === Person.prototype

      轻松搞懂构造函数,new,实例对象,原型,原型链,ES6中的类 | 技术点评

    • constructor

      每个原型都有一个 constructor 属性指向关联的构造函数 原型指向构造函数

      Person === Person.prototype.constructor

      轻松搞懂构造函数,new,实例对象,原型,原型链,ES6中的类 | 技术点评

    了解了三个基础概念之后,下面我们来看一个例子

    function Person() {  
    
    }
    
    Person.prototype.name = 'Kevin';    
    
    var person = new Person();
    
    person.name = 'Daisy';
    console.log(person.name) // Daisy
    
    delete person.name;
    console.log(person.name) // Kevin
    

    我们来分析下代码的运行过程

    原型链

    原型链的概念呢,其实有点类似于作用域链,也类似于 Promise ,一层套一层,仿佛又回想起了那天被 Promise 回调地狱支配的恐惧,哈哈哈哈。

    当然,插个广告,都2021年了,连作用域链都不知道的话,那就快点击我的这篇博客吧 一文搞懂JS系列(一)之编译原理,作用域,作用域链,变量提升,暂时性死区

    当然,扯回原型链,其实概念也很简单,就是原型组成的链

    经过上面的学习,我们都知道对象的 __proto__ 就是所谓的原型,而原型又是一个对象,它又有自己的 __proto__,原型的 __proto__ 又是原型的原型,就这样可以一直通过 __proto__ 向上找,这就是原型链,当向上找找到 Object 的原型的时候,这条原型链就算到头了。如下图,找到了 Object.__proto__ 就算到头了。

    轻松搞懂构造函数,new,实例对象,原型,原型链,ES6中的类 | 技术点评

    如下图,打印 person.__proto__.__proto__ ,原型链查找就算到头了,也就是再无 __proto__,一个简单的 person 实例对象,也有两层原型

    轻松搞懂构造函数,new,实例对象,原型,原型链,ES6中的类 | 技术点评

    ES6中的类

    通过上面的学习,我们学会了原型,原型链,以及了解到了 Javascript 实现继承方式的根基,那就是原型。

    可能很多人会说,都什么年代了,明明 ES6 也有类啊,但是,这些人都被表象所迷惑了,来看一段 MDN 的官方解释。

    那么,既然是语法糖,肯定有它的相应实现方式,我们先用 class 的方式来实现一个 Person 类,相当于一个构造函数

    class Person {
      constructor(name ,age) {
       this.name = name
       this.age = age
      }
      
      sayHello() {
        console.log('你好啊!')
      }
    }
    

    其实,上面的方式等价于下面:

    function Person(name, age) {
      this.name = name
      this.age = age
    }
    Dog.prototype.sayHello = function() {
      console.log('你好啊!')
    }
    

    所以,虽然在 ES6 中有更新类,但是,它只是一种语法糖,真正实现继承的方式还是原型

    本文参考如下:

    js的原型和原型链

    Javascript继承机制的设计思想


    起源地下载网 » 轻松搞懂构造函数,new,实例对象,原型,原型链,ES6中的类 | 技术点评

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元