JavaScript---原型

本文探讨了JavaScript中原型的概念,包括原型何时产生、原型链的作用以及如何通过原型实现数据共享和继承。讲解了`prototype`和`__proto__`的区别,以及它们在创建函数对象和实例对象中的角色。此外,还涉及了函数对象的原型属性和实例对象的隐式原型,以及原型链在查找属性和`instanceof`操作中的运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原型

原型什么时候产生的?

执行函数定义的时候,prototype 显示原型就创建出来了,由于函数本身也是对象(实例对象),里面的隐式原型proto也产生了

原型的理解

原型就是对象,JS 中原型一共有两个,一个是 prototype,一个是proto属性

  • prototype:浏览器的标准属性,程序员使用的,显示原型,存在于函数中
  • __proto__:浏览器的非标准属性,浏览器使用的,隐式原型,存在于实例对象中
  • 函数中有 prototype,实例对象中有proto
  • 实例对象也是对象,里面就有proto
  • 实例对象的proto与对应函数的 prototype 都指向原型对象
  • 无论是构造函数还是普通函数,或者是方法,只要是函数,内部就有 prototype

原型的作用

一、共享数据,节省内存空间

1、实例对象一般都是通过构造函数进行创建的,实例化对象的时候做的四件事:

	- var per = new Person('illion',20)
    1) 申请一块空闲的空间,用来存储当前的实例对象
    2) 设置this为当前的实例对象(修改this的指向)
    3) 初始化实例对象中的属性和方法的值
    4) 把this作为当前对象进行返回

2、 在构造函数中定义的属性及方法,仅仅是编写代码进行定义而已,而实际上里面定义的属性及方法是属于每个实例对象的,所以,创建多个对象,就会开辟多个空间,每个空间中的每个对象都有自己的属性及方法,大量创建对象,对象的方法都不是同一个方法(方法也是函数,函数代码也占用空间),为了节省内存空间,那么可以使用原型的方式,实现数据共享,节省内存空间。

二、通过改变原型实现 JS 中的继承

1). 通过改变原型指向实现继承
2). 借用构造函数显示继承
3). 组合继承
4). 拷贝继承:浅拷贝和深拷贝

原型对象上有一个constructor属性指向对应的构造函数

function Fn () {}

const fn = new Fn()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G9XMEbwb-1634543943926)(../image/显示原型与隐式原型.png)]

区别执行函数定义执行函数

  • 执行函数定义: 也就是去创建函数对象, 只是有可能被 JS 引擎提升预处理执行
    • 执行函数: 执行函数体中所有语句
    • 先有函数定义的执行,才有执行函数
    • 常见的回调
      • DOM 事件的回调 btn.onClick=function(){}
      • 定时器中的回调
      • ajax 回调函数
      • 生命周期的回调
      1. 立即执行函数(Immediately-Invokey Function Expression) 匿名函数自调用
      • 作用:隐藏内部实现,减少命名空间的污染
;(function(){
    var num = 20;
})();
var num = 10;

说说函数对象上的prototype属性?

(prototype什么时候出现,执行函数定义的时候)

  • 执行函数定义(有可能被提升执行)创建函数对象

    • 给函数对象添加prototype属性, 属性值为空的Object实例对象, 也就是原型对象

    • 给原型对象添加constructor属性, 值为函数

    • 伪代码:

      // 给函数对象添加prototype属性, 属性值为空的Object实例对象, 也就是原型对象
      function Fn(){}
      console.dir(Fn)
      var obj ={}
      console.log(obj.__proto__===Object.prototype) //true
      console.log(Fn.prototype.__proto__===Object.prototype) //true
      // 伪代码
      this.prototype = {}  // this就是函数对象
      this.prototype.constructor = Fn
      

说说实例对象上的__proto__属性?

(_proto-什么时候出现,实例化对象的时候)

JS引擎在创建实例对象时内部自动执行时, 会自动给实例对象添加__proto__属性, 值为构造函数的 prototype属性的值

this.__proto__ = Fn.prototype  // this是实例对象

原型链

(实际上是隐式原型链,言外之意就是和显示原型没毛关系,显示原型产生实例的一瞬间起的作用)

  • 从对象的__proto__开始, 连接的所有对象, 就是我们常说的原型链, 也可称为隐式原型链

  • 查找对象属性简单说: 先在自身上查找, 找不到就沿着原型链查找,如果还找不到返回undefined

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3RlywyH9-1634543943928)(../image/原型链.png)]

查找对象上属性的基本流程

1、 先在对象自身上查找, 如果有, 直接返回

2、如果没有, 根据__proto__在原型对象上查找, 如果有, 直接返回

3、 如果没有根据原型对象的__proto__在原型对象的原型对象上查找, 一直查找到Object原型对象为止

4、 如果找到了返回, 如果查找不到由于它的__proto__为null, 只能返回undefined

5、 查找对象属性时候,会不会读函数的prototype?(会还是不会)

  ```js
      // 简单的原型链
      function F1(){}
      F1.prototype.number =100
      function F2(){}
      F2.prototype=new F1()
      F2.prototype.number =200
      function F3(){}
      F3.prototype=new F2()
      F3.prototype.number =300
      var f3 = new F3()
      console.log(f3.number)
      console.dir(f3) //300
  ```

表达式a.b的解析流程

var a = 10 //a是一个变量,值是数字类型的,引用类型的对象可以点属性或者方法,然后使用
//a是数字类型,但是由于a.b了,此时a就变成了基本包装类型----引用类型了
// a是一个对象了,b就是一个属性,但是属性没有赋值,所以,结果就是undefined
console.log(a.b)//undefined 没有报错
  • 查看a变量: 作用域链查看
    • 不存在 ==> 报错
    • 存在, 得到它的值
      • 基本类型(var a=null/a=undefined,此时a.b报错)
        • null/undefined ===> 报错
        • number/string/boolean ==> 创建一个包含此值的包装类型对象, 进入下面流程
      • 地址值 ===> 解析.b ===> 查找b属性
        • 先在自身找, 找到了返回, 如果没有找到
        • 原型链查找
          • 找到了返回
          • 没找到, 返回undefined

a.b这个表达式中,总结知识点:数据类型(null/undefined,string/number/boolean),作用域(局部作用域/全局作用域),域解析,执行上下文环境,原型/原型链—>原型相关应用

instanceOf

  • 作用: 判断一个任意类型对象的具体类型

    • 如何判断?
      • 对于 A instanceof B
      • A是实例对象, B是构造函数
      • 如果B的prototype属性所指向的原型对象是A实例对象的原型链接上的某个对象, 返回true, 否则返回false
//  构造函数
       function Foo() { }
       // f1是实例对象---引用变量,存储的是当前的这个对象所在的空间的地址
       const f1 = new Foo()
       const f2 = new Foo()
   
       const o1 = new Object()
       const o2 = {}
       // 下面的结果
       // 所有的函数都是Function的实例对象 
       console.log(Foo instanceof Object)//true
       // 所有的函数都是Function的实例对象 
       console.log(Foo instanceof Function)//true
       console.log(Object instanceof Object)//true
       console.log(Function instanceof Function)//true
       console.log(Function instanceof Object)//true
       console.log(Object instanceof Foo)//false
       console.log(f1 instanceof Function)//false
       console.log(f1 instanceof Object)//true

原型与原型链结构图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YYC88GRI-1634543943930)(../image/原型与原型链结构图.png)]

```
  1. 对象中有__proto__,函数中有prototype
    - 实例对象中__proto__指向的是当前实例对象对应的构造函数中的prototype
    - 而每个prototype都是一个对象,所以,内部必然有__proto__,普通函数中的prototype的__proto__指向的是Object的prototype
    - 每个函数是Function的实例对象,所以,只要是函数,那么函数对象中__proto__指向的都是Function的prototype,那么这个prototype中的__proto__指向的仍然是Object的prototype
    - 但是,Object这个构造函数也是函数,所以,Object的__proto__指向的是Function的prototype
    - Function这个构造函数也是对象,所以里面的__proto__指向的是Function的prototype
```

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7LnYccoq-1634543943932)(../image/原型.jpg)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值