JavaScript高级 构造函数和原型

概述

在典型的OOP的语言中 (如java),都存在类的概念 ,类就是对象的模板 ,但是在ES6(2015年发布的ECMAscript6.0)之前 JS中并没有引入类的概念
在这之前 对象不是基于类创建的 而是用一种被称为 构造函数 的特殊函数来定义对象和他们的特征
构造函数基本介绍:
构造函数

案例

 function Zwjs(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.jn = function () {
      console.log("睡觉");
    };
  }
  let x = new Zwjs('shaco',18,'男');
  console.log(x);
  x.jn()

在这里插入图片描述

成员

javascr的构造函数中可以添加一些成员 可以在构造函数本身上添加 也可以在构造函数内部的this上进行添加 通过这两个方法添加的成员 我们分别称之为 静态成员 和 实例成员
静态成员: 在构造函数本身添加的成员称之为静态成员,只能由构造函数本身来访问

实例成员:在构造函数内部创建的对象成员称为实例成员 , 只能由实例化的对象来访问

  function Zwjs(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.jn = function () {
      console.log("睡觉");
    };
  }
  let x = new Zwjs('shaco',18,'男');
  // 实例成员就是构造函数内部通过this添加的成员
  // 如上面的 name age sex jn就是实例成员
  // 实例成员只能通过实例化的对象来访问
  // 如
  console.log(x.name);
  // 我们不可以通过构造函数来访问实例成员
  //如
  // console.log(zwjs.name); 报错
  
  // 静态成员 在构造函数本身上添加的成员
  Zwjs.lol = '白银';
  // 因为js是动态语言 我们可以动态添加语言 所以我们可以添加属性
  // 这类添加的对象就是静态成员
  // 静态成员只能通过构造函数来访问
  console.log(Zwjs.lol);
  // 不可以通过实例化的对象来访问
  //  console.log(x.lol0);//undefined

构造函数的问题

构造函数虽然很好用 但还是有问题的存在
在这里插入图片描述

我们使用构造函数的时候 会开辟一个新的内存空间
但是因为我们的对象中常常有函数作为方法使用 而函数是复杂数据类型 当我们多次使用构造函数的时候 都会开辟一个新的内存空间来存放同一个函数
案例如下 我们用构造函数创建两个对象

function Zwjs(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.jn = function () {
      console.log("睡觉");
    };
  }
  let x = new Zwjs('shaco',18,'男');
  let y = new Zwjs('yasuo', 18 ,'男');
   
  console.log(x.jn===y.jn);

在这里插入图片描述

但是他们的方法不相等 因为复杂数据类型的 存储方式是将地址放在栈中 而实际的对象放在堆中 所以他们不相等
简单的说 构造函数大量使用 就会不停的开辟很多空间来存放同一个函数 造成内存浪费 对性能造成很大的影响
所以这时候我们可以用到原型对象来解决

原型对象 prototype

在js中 每一个构造函数都有一个prototype属性 指向另外一个对象
需要注意的是 prototype自己就是一个对象
而这个对象的所有方法和属性 都会被构造函数拥有
我们可以把公共的方法放到原型对象中
构造函数通过原型分配的函数是所有对象共享的
在这里插入图片描述

因此我们可以把一些不变的方法 直接定义到prototype对象上 这样所有对象的实例都可以共享这些方法

      function Zwjs(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
  
      }
      // console.dir(Zwjs);
   Zwjs.prototype.jn = function (){
       console.log('恰饭');
   }
   let shaco =new Zwjs('shaco',18,'男');
   let yasuo =new Zwjs('yasuo',19,'男');
   shaco.jn();
   yasuo.jn()

如上列代码 我们利用原型对象创建了jn这个方法
然后实例化俩个对象
并让他们使用这个方法 我们来看看结果如何
在这里插入图片描述
说明我们实现了方法的共享

一般情况下 我们的公共属性定义到构造函数里面
(如上面代码中的 name,age等属性)
公共的方法我们定义到原型对象身上
(如我们通过原型对象定义的jn方法)

对象原型__proto__

也可以写为[[Prototype]]
实例化对象都会有一个属性__proto__指向构造函数中的原型对象prototype,
之所以我们可以用构造函数prototype 原型对象的属性和方法 就是因为实例化对象有 proto 对象原型的存在

简单的说 实例化对象的__proto__(对象原型) 和构造函数的原型对象 prototype 是一样的
在这里插入图片描述
对象原型__proto__的意义就是给对象的查找机制提供一个方向 或者说是一条路线 但是对象原型是一个非标准的属性 所以在我们实际开发的过程中 不可以使用这个属性
它的作用只是从对象的内部指向原型对象 prototype
在这里插入图片描述

原型constructor 构造函数

对象原型prototype和原型对象__proto__中 都有一个属性constructor
我们称constructor为构造函数 因为它指回构造函数本身

在这里插入图片描述
我们打印他们的constructor属性 都是指向我们一开始的构造函数
在这里插入图片描述

作用

举个例子 当我们使用对象原型来存放多个我们的方法函数的时候,经常会以对象的方式来书写使结构更加清晰

 function Zwjs(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
 
  }
  Zwjs.prototype = {
    sleep: function () {
      console.log('睡觉');
    },
    eat: function () {
      console.log('恰饭');
    }
  }

然后我们再次打印 构造函数的的原型对象的constructor
在这里插入图片描述

发现他并没有指向我们的构造函数 而是指向了 一个对象
为了避免可能发生的错误 我们可以调用constructor属性 使原型对象指向我们原来的构造函数
在这里插入图片描述
在这里插入图片描述

原型链

在这里插入图片描述
因为每个对象都有自己的对象原型(prototype) 那么我们的原型对象(proto)的对象原型是什么呢

function Zwjs(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
          }
        console.log(Zwjs.prototype.__proto__);

结果如下 我们可以理解为内置对象
在这里插入图片描述
所以我们吧原型链升级
在这里插入图片描述
我们在打印内置对象的构造函数

console.log(Object.constructor);

在这里插入图片描述

得到一个构造函数
由此我们可以再次完事原型链
在这里插入图片描述
顺藤摸瓜 我们在试试内置对象的原型对象的对象原型是什么

console.log(Object.prototype.__proto__);

得到
在这里插入图片描述
由此 原型链完成
在这里插入图片描述

JavaScript的成员查找机制

当我们访问一个对象的属性或者方法的时候 首先先查找这个对象本身有没有这种属性或者方法
如果没有的话 旧查找他的对象原型(也就是实例化对象使用原型对象__proto__取对象原型prototype中查找)
如果还没有 就去查找内置对象的原型(内置对象的原型对象)
最后如果还没找到就返回underfind或者null
案例如下
在这里插入图片描述
我们注释x.sex
在这里插入图片描述

我们在注释Zwjs.prototype.sex =‘女’
在这里插入图片描述
最后我们注释掉 Object.prototype.sex = ‘人妖’;
在这里插入图片描述

原型对象的this指向

首先我们需要理解的是
在构造函数中 里面的this指向的是对象实例

我们创建一个变量x 但不赋值

然后加入方法中 使他等于this 于是我们实例化对象调用原型对象中的方法使
x 就等于this
然后分别打印
this的代表(得到构造函数 然后因为构造函数指向对象实例)
所以我们打印this是否等于实例对象 得到true

       function Zwjs(name, age, sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
  
      }
  
      let x ;
   Zwjs.prototype.jn = function (){
       console.log('恰饭');
       x=this;
   }
   let shaco =new Zwjs('shaco',18,'男');
   let yasuo =new Zwjs('yasuo',19,'男');
    
   shaco.jn()
   console.log(x);
   console.log(x===shaco);

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值