JavaScript -- 原型与原型链

简介: JavaScript -- 原型与原型链

根据视频进行整理

【https://www.bilibili.com/video/BV14s411E7qf?p=15】

视频对应资源(百度网盘):

链接:【https://pan.baidu.com/s/1q9LnJcRt5alTV67gUDqpnw】

提取码:1234

1 原型与原型链

1.1 原型 prototype

1、每个函数都有一个prototype属性

// 每个函数都有一个prototype属性
    function myfunc() {
    }
    console.log(myfunc.prototype)
    console.log(Date.prototype)

2、函数的prototype属性,其类型为object

// 每个函数都有一个prototype属性
    function myfunc() {
    }
    console.log( typeof myfunc.prototype)
    console.log( typeof Date.prototype)

3、函数的prototype属性默认指向一个Object空对象(即称为: 原型对象)

Object空对象:

是指该对象上没有我们自定义的属性

console.dir( myfunc.prototype)
    console.log(new Object())

4、函数的prototype属性指向的对象为原型对象

5、原型对象中有一个属性constructor, 它指向函数对象

console.log(myfunc.prototype.constructor === myfunc)
    console.log(Date.prototype.constructor === Date)

6、可以通过prototype给原型对象添加属性(一般是方法)

作用:

可以使函数的所有实例对象都自动拥有原型中的属性(方法)

通过prototype给原型对象添加属性,添加的属性供实例对象使用

// 构造函数
      function Fun() {}
      // 向函数的原型对象上添加属性
      Fun.prototype.test = function() {
        console.log('Fun.prototype.test')
      }
      // 实例化对象
      const fun1 = new Fun()
      console.log(fun1)
      fun1.test()

1.2 显示原型与隐式原型

1、每个函数function都有一个prototype,即显式原型(属性)

2、每个实例对象都有一个__proto__,可称为隐式原型(属性)

// 每个函数function都有一个prototype,即显式原型(属性)
    function Fun() {}
    console.log(Fun.prototype)
    // 每个实例对象都有一个__proto__,可称为隐式原型(属性)
    var fun = new Fun()
    console.log(fun.__proto__)

3、实例化出来的对象的隐式原型的值为其对应构造函数的显式原型的值

显示原型属性指向一个没有我们自定义属性的对象,隐式原型属性指向显示原型属性指向的对象。

// 实例化出来的对象的隐式原型的值为其对应构造函数的显式原型的值
    console.log(fun.__proto__ === Fun.prototype)

// 通过函数的prototype给原型添加属性
    Fun.prototype.test = function() {
      console.log('test')
    }
    // 实例对象调用添加的属性
    fun.test()

函数向原型中添加属性通过显示原型属性

实例对象使用新添加的属性通过隐式原型属性进行查找

输出结果:

小结

  • 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个没有自定义属性的Object对象
  • 对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
  • 程序员能直接操作显式原型, 但不要直接操作隐式原型(ES6之前)

1.3 原型链

function Fn() {
        this.test1 = function () {
          console.log('test1()')
        }
      }
      Fn.prototype.test2 = function () {
        console.log('test2()')
      }
      var fn = new Fn()
      fn.test1()
      fn.test2()
      console.log(fn.toString())
      fn.test3()

访问一个对象的属性时:

  • 先在自身属性中查找,找到返回
  • 如果没有, 再沿着__proto__这条链向上查找, 找到返回
  • 如果最终没找到, 返回undefined

原型链的尽头为Object的原型对象。

原型链:

  • 本质上是隐式原型链
  • 作用: 查找对象的属性(方法)

fn.test3() 会在对象的属性和其原型链中查找

test3() 函数变量,会在作用域链中进行查找

所有函数的隐式原型都相等,因为所有函数都是函数构造器函数Function()的实例对象,所以所有函数对象的隐式原型属性都相等,都等于函数构造器函数Function()的显示原型属性

补充:

1、函数的显示原型指向的对象默认是空Object实例对象(但Object函数的原型对象不满足)

空:对于程序员来说,没有放任何的属性方法到对象中

Object的显示原型对象为null

Object函数:对象的构造函数 Object()

console.log(Fn.prototype instanceof Object) // true
      // Object的显示原型对象再向上就没了
      console.log(Object.prototype instanceof Object) // false
      console.log(Function.prototype instanceof Object) // true

2.、所有函数都是Function的实例(包含Function)

// 自身的实例,隐式原型的指向和现实原型的指向相等
      console.log(Function.__proto__ === Function.prototype)

3、Object的原型对象是原型链尽头

console.log(Object.prototype.__proto__) // null

1.4 原型链_属性问题

1、读取对象的属性值时: 会自动到原型链中查找

2、设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值

function Fn() {}
      // 在原型上设置一个属性 a 值为 xxx
      Fn.prototype.a = 'xxx'
      // Fn实例化对象 fn1
      var fn1 = new Fn()
      console.log(fn1.a, fn1)
      // Fn实例化对象 fn2
      var fn2 = new Fn()
      // 给 fn2 对象设置属性 a 值为 yyy
      // fn2 中没有 a 属性,会给 fn2 添加一个 a 属性
      fn2.a = 'yyy'
      console.log(fn1.a, fn2.a, fn2)

3、方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上

对象的属性一般在构造函数中进行设置

function Person(name, age) {
    this.name = name
    this.age = age
  }
  Person.prototype.setName = function (name) {
    this.name = name
  }

属性在自身身上(每个对象的属性值会有所不同),方法在原型上

var p1 = new Person('Tom', 12)
  p1.setName('Bob')
  console.log(p1)
  var p2 = new Person('Jack', 12)
  p2.setName('Cat')
  console.log(p2)

1.5 instanceof

instanceof是如何判断的?

表达式: A instanceof B

如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false

// Object这里为构造器函数,是Function的一个实例对象
  // Object => Object.__proto__ === Function.prototype
  console.log(Object instanceof Function) // true
  // Object作为对象的显示原型属性为Object.prototype
  // Object作为构造函数是Function的实例对象,Function是Object的实例(函数是特殊的对象)
  // Object => Object.__proto__ === Function.prototype => Object
  console.log(Object instanceof Object) // true
  console.log(Function instanceof Function) // true
  // 函数是特殊的对象
  console.log(Function instanceof Object) // true
  function Foo() {}
  // 函数类型的数据对象
  // Foo.prototype
  // Object.__proto__ => Function.prototype => Object.prototype 
  console.log(Object instanceof  Foo) // false

1.6 面试题

function A () {
  }
  A.prototype.n = 1
  var b = new A()
  A.prototype = {
    n: 2,
    m: 3
  }
  var c = new A()
  console.log(b.n, b.m, c.n, c.m)

function F (){}
  Object.prototype.a = function(){
    console.log('a()')
  }
  Function.prototype.b = function(){
    console.log('b()')
  }
  var f = new F()
  // f是一个对象
  // f => Object => Object.prototype
  // F是一个函数,Function的实例
  // F => Function => Object => Object.prototype
  f.a()
  // f.b() // 不存在,会报错
  F.a()
  F.b()
  // console.log(f)
  // console.log(Object.prototype)
  // console.log(Function.prototype)


相关文章
|
3天前
|
JavaScript 前端开发
js开发:请解释原型继承和类继承的区别。
JavaScript中的原型继承和类继承用于共享对象属性和方法。原型继承通过原型链实现共享,节省内存,但不支持私有属性。
19 0
|
3天前
|
JavaScript 前端开发
谈谈对 JavaScript 中的原型链的理解。
JavaScript中的原型链是实现继承和共享属性的关键机制,它通过对象的`prototype`属性连接原型对象。当访问对象属性时,若对象本身没有该属性,则会查找原型链。此机制减少内存占用,实现代码复用。例如,实例对象可继承原型对象的方法。原型链也用于继承,子类通过原型链获取父类属性和方法。然而,原型属性共享可能导致数据冲突,且查找过程可能影响性能。理解原型链对JavaScript面向对象编程至关重要。如有更多问题,欢迎继续探讨😊
16 3
|
3天前
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(三)
深入JS面向对象(原型-继承)
31 0
|
3天前
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(一)
深入JS面向对象(原型-继承)
32 0
|
3天前
|
JavaScript 前端开发 安全
JavaScript原型链的使用
【4月更文挑战第22天】JavaScript中的原型链是理解继承的关键,它允许对象复用属性和方法,减少代码冗余。示例展示如何通过原型链实现继承、扩展内置对象、构造函数与原型链的关系以及查找机制。应注意避免修改`Object.prototype`,使用安全方式设置原型链,并谨慎处理构造函数和副作用。
|
3天前
|
JavaScript
JS数组增删方法的原理,使用原型定义
JS数组增删方法的原理,使用原型定义
|
1天前
|
前端开发 JavaScript
前端 js 经典:原型对象和原型链
前端 js 经典:原型对象和原型链
11 1
|
2天前
|
JavaScript 前端开发
JavaScript 原型链继承:掌握面向对象的基础
JavaScript 原型链继承:掌握面向对象的基础
|
3天前
|
JavaScript 前端开发
在JavaScript中,函数原型(Function Prototype)是一个特殊的对象
【5月更文挑战第11天】JavaScript中的函数原型是一个特殊对象,它为所有函数实例提供共享的方法和属性。每个函数在创建时都有一个`prototype`属性,指向原型对象。利用原型,我们可以向所有实例添加方法和属性,实现继承。例如,我们定义一个`Person`函数,向其原型添加`greet`方法,然后创建实例`john`和`jane`,它们都能调用这个方法。尽管可以直接在原型上添加方法,但推荐在构造函数内部定义以封装数据和逻辑。
18 2
|
3天前
|
JavaScript 前端开发
JavaScript原型链:工作原理与深入探究
【4月更文挑战第22天】JavaScript原型链是对象属性查找的关键,它通过对象间的链接形成链式结构。当访问属性时,JS从对象自身开始查找,若未找到则沿原型链向上搜索,直至`null`。原型链用于继承、扩展内置对象和实现多态,但要注意避免修改内置对象原型、控制链长度及使用`Object.create()`创建对象。理解并合理运用原型链能深化JS面向对象编程的理解。