JavaScript难点:原型、原型链、继承、new、prototype和constructor

简介: JavaScript 不像 Java、C++ 这种纯面向对象的语言,可以通过类实现继承,JavaScript中的继承是通过原型实现的,即使 ES6 中新增的 class 类也只是原型的语法糖而已

原型

原型(prototype)是 JavaScript 中对象的一个特殊属性,它用于实现属性和方法的继承。

实例对象的原型属性可以用 __proto__ 访问到,推荐用 Object.getPrototypeOf() 去获取。

原型链

任何一个实例,通过原型链,都能找到它上面的原型,该原型对象中的方法和属性,可以被所有的原型实例共享,原型对象中依然有它自身的原型,当我们访问一个实例属性或方法时,如果自身没有,就会一级一级地去原型对象上找,这样就构成一个原型链。

继承

JavaScript 不像 Java、C++ 这种纯面向对象的语言,可以通过类实现继承,JavaScript中的继承是通过原型实现的,即使 ES6 中新增的 class 类也只是原型的语法糖而已。

new

构造函数只能通过 new 关键字才能调用创建实例,class 类必须要加 new 否则会报错。当我们 new 的时候实际会调用内部的 constructor 构造函数,会做以下4步:

  • 新建一个对象
  • 将对象的原型指向构造函数的 prototype
  • 绑定 this,执行构造函数中的代码
  • 返回对象

prototype

JavaScript 规定,每一个构造函数都有一个 prototype 属性(其实普通函数也有的,构造函数本身就是一个普通函数),指向另一个对象。注意这个 prototype 就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有,注意实例是没有 prototype 属性。

  • prototype:显示原型,函数才有的
  • __proto__:隐式原型,实例对象才有的,在浏览器中可以通过这个访问对象的原型,不过 Mozilla 推荐使用 Object.getPrototypeOf 去访问
  • [[prototype]]:和 __proto__ 一样,一般出现在一些书籍和规范中,在浏览器控制台打印也会显示这个,但我们没法用代码访问

constructor

constructor 构造函数,原型对象 prototype 中有 constructor,指向该原型的构造函数。

为什么通过 prototype 修改原型实现继承后要重置 custructor?

我们可以通过将一个构造函数的 prototype 指向另一个构造函数来实现继承父类的属性和方法,但是往往还会额外加一个 Child.prototype.constructor = Child,这是因为直接通过 prototype 修改了原型后,当前子类原型里的 constructor 实际上还是指向的父类构造函数(因为 prototype 本来就是父类的),这不就和我们上面说的 "原型对象 prototype 中有 constructor,指向该原型的构造函数" 相矛盾了。

function Person(username, age) {
   
  this.username = username
  this.age = age || 0
  this.say = function() {
   
    console.log('Hello, 我是' + username)
  }
}

function Boy(gender) {
   
  this.gender = gender
}

Boy.prototype = new Person('小明')
// 重置 constructor
// Boy.prototype.constructor = Boy
const ming = new Boy()
ming.say()

// 直接通过调实例原型上的构造函数去新建实例
const hua = new ming.constructor()
console.log(hua)

// 打印 2 个实例上的构造函数名都是父类的 Person
console.log(ming.__proto__.constructor.name) // Person
console.log(hua.constructor.name) // Person

当我们不重置 constructor 的时候,通过 constructor.name 可以看到此时都是指向父类的,加上 Boy.prototype.constructor = Boy 重置后就能正确指向子类了。

其实这一点对于我们正常使用、实例化对象、继承都是没啥影响的,不过建议是按照规范重置成正确的。

相关文章
|
6天前
|
JavaScript 前端开发
js开发:请解释原型继承和类继承的区别。
JavaScript中的原型继承和类继承用于共享对象属性和方法。原型继承通过原型链实现共享,节省内存,但不支持私有属性。
19 0
|
6天前
|
JavaScript 前端开发 安全
JavaScript原型链的使用
【4月更文挑战第22天】JavaScript中的原型链是理解继承的关键,它允许对象复用属性和方法,减少代码冗余。示例展示如何通过原型链实现继承、扩展内置对象、构造函数与原型链的关系以及查找机制。应注意避免修改`Object.prototype`,使用安全方式设置原型链,并谨慎处理构造函数和副作用。
|
3天前
|
前端开发 JavaScript
前端 js 经典:原型对象和原型链
前端 js 经典:原型对象和原型链
14 1
|
4天前
|
JavaScript 前端开发
探索JavaScript中的New操作符:原理与使用
探索JavaScript中的New操作符:原理与使用
|
5天前
|
JavaScript 前端开发
JavaScript 原型链继承:掌握面向对象的基础
JavaScript 原型链继承:掌握面向对象的基础
|
6天前
|
JavaScript 前端开发
在JavaScript中,函数原型(Function Prototype)是一个特殊的对象
【5月更文挑战第11天】JavaScript中的函数原型是一个特殊对象,它为所有函数实例提供共享的方法和属性。每个函数在创建时都有一个`prototype`属性,指向原型对象。利用原型,我们可以向所有实例添加方法和属性,实现继承。例如,我们定义一个`Person`函数,向其原型添加`greet`方法,然后创建实例`john`和`jane`,它们都能调用这个方法。尽管可以直接在原型上添加方法,但推荐在构造函数内部定义以封装数据和逻辑。
18 2
|
6天前
|
JavaScript 前端开发 开发者
【专栏】JavaScript 中的 prototype 和__proto__是关乎对象继承和属性查找的关键概念
【4月更文挑战第29天】JavaScript 中的 prototype 和__proto__是关乎对象继承和属性查找的关键概念。prototype 是函数属性,用于实现对象继承,方法和属性定义在其上可被所有实例共享。__proto__是对象属性,实现属性查找机制,当对象自身找不到属性时,会沿原型链向上查找。两者关系:__proto__指向构造函数的 prototype,构成对象与原型的桥梁。虽然 prototype 可直接访问,但__proto__由引擎内部维护,不可见。理解两者区别有助于深入学习 JavaScript。
|
6天前
|
JavaScript 前端开发
javascript中new关键字的本质是什么
javascript中new关键字的本质是什么
|
6天前
|
JavaScript 前端开发
JavaScript原型链:工作原理与深入探究
【4月更文挑战第22天】JavaScript原型链是对象属性查找的关键,它通过对象间的链接形成链式结构。当访问属性时,JS从对象自身开始查找,若未找到则沿原型链向上搜索,直至`null`。原型链用于继承、扩展内置对象和实现多态,但要注意避免修改内置对象原型、控制链长度及使用`Object.create()`创建对象。理解并合理运用原型链能深化JS面向对象编程的理解。
|
6天前
|
JavaScript
什么是js的原型链
什么是js的原型链