JavaScript高级学习笔记 1

构造函数和原型

概述

在典型的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()

JavaScript高级学习笔记 1

成员

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

构造函数的问题

构造函数虽然很好用 但还是有问题的存在
JavaScript高级学习笔记 1

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

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);

JavaScript高级学习笔记 1

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

原型对象 prototype

在js中 每一个构造函数都有一个prototype属性 指向另外一个对象
需要注意的是 prototype自己就是一个对象
而这个对象的所有方法和属性 都会被构造函数拥有
我们可以把公共的方法放到原型对象中
构造函数通过原型分配的函数是所有对象共享的
JavaScript高级学习笔记 1

因此我们可以把一些不变的方法 直接定义到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这个方法
然后实例化俩个对象
并让他们使用这个方法 我们来看看结果如何
JavaScript高级学习笔记 1
说明我们实现了方法的共享

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

对象原型__proto__

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

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

原型constructor 构造函数

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

JavaScript高级学习笔记 1
我们打印他们的constructor属性 都是指向我们一开始的构造函数
JavaScript高级学习笔记 1

作用

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

 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
JavaScript高级学习笔记 1

发现他并没有指向我们的构造函数 而是指向了 一个对象
为了避免可能发生的错误 我们可以调用constructor属性 使原型对象指向我们原来的构造函数
JavaScript高级学习笔记 1
JavaScript高级学习笔记 1

原型链

JavaScript高级学习笔记 1
因为每个对象都有自己的对象原型(prototype) 那么我们的原型对象(proto)的对象原型是什么呢

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

结果如下 我们可以理解为内置对象
JavaScript高级学习笔记 1
所以我们吧原型链升级
JavaScript高级学习笔记 1
我们在打印内置对象的构造函数

console.log(Object.constructor);

JavaScript高级学习笔记 1

得到一个构造函数
由此我们可以再次完事原型链
JavaScript高级学习笔记 1
顺藤摸瓜 我们在试试内置对象的原型对象的对象原型是什么

console.log(Object.prototype.__proto__);

得到
JavaScript高级学习笔记 1
由此 原型链完成
JavaScript高级学习笔记 1

JavaScript的成员查找机制

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

我们在注释Zwjs.prototype.sex =‘女’
JavaScript高级学习笔记 1
最后我们注释掉 Object.prototype.sex = ‘人妖’;
JavaScript高级学习笔记 1

原型对象的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);

JavaScript高级学习笔记 1

上一篇:2022年全球市场液力变矩器总体规模、主要生产商、主要地区、产品和应用细分研究报告


下一篇:全球及中国直接耦合执行器市场需求及未来发展规划建议报告2022-2027年