이 기사에서는 프로토타입과 이를 JS 상속에 사용하는 방법에 대해 설명합니다. 또한 프로토타입 메서드가 클래스 기반 상속과 어떻게 다른지 살펴보겠습니다.
상속은 객체 지향 프로그래밍 언어의 도입과 함께 등장한 프로그래밍 언어의 특징입니다. 이러한 언어의 대부분은 클래스 기반 언어입니다. 여기서 클래스는 청사진과 같고 객체는 해당 표현입니다. 즉, 객체를 생성하려면 먼저 클래스를 생성해야 하며, 그런 다음 클래스에서 원하는 만큼의 객체를 생성할 수 있습니다.
스마트폰을 나타내는 클래스가 있다고 상상해 보세요. 이 클래스에는 다른 스마트폰과 마찬가지로 사진 촬영, GPS 위치 확인 등의 기능이 있습니다. 다음은 C++를 사용하는 이러한 클래스에 대한 설명입니다.
class SmartPhone { public: void captureImages() {} } SmartPhone x; x.captureImages()
저희는 사진 촬영을 위한 capturePictures
라는 메서드가 있는 SmartPhone
이라는 클래스를 만들었습니다. SmartPhone
的类,它有一个名为capturePictures
的方法用来拍照。
如果我们需要一个iPhone
类,它可以捕捉图像和一些特殊的功能,比如面部ID扫描。下面是两种可能的解决方案:
将捕获图像功能与其他常见的智能手机功能,以及iPhone的特定功能一起重写到一个新类中。但是这种方法需要更多的时间和精力,并且会引入更多的bug。
SmartPhone
类中的功能,这就是继承的作用,继承也是重用其他类/对象中功能的一种方式。这里是我们如何从SmartPhone
类中继承capturePictures
方法,使用 c++ 实现如下:
class Iphone: public SmartPhone { public: void faceIDScan() {} } Iphone x x.faceIDScan() x.captureImages()
上面是一个简单的继承示例。 但是,它表明继承可以使我们以某种方式重用代码,从而使所生成的程序更不易出错,并且花费更少的时间进行开发。
以下是关于类的一些重要信息:
值得注意的是,类本身并没有做任何事情。在从类创建对象之前,实际上没有完成任何工作。我们将看到它为什么不同于JavaScript。
在 JS 中,所有对象都有一个特殊的内部属性,该属性基本上是对另一个对象的引用。 此引用取决于对象的创建方式。 在 ECMAScript/JavaScript规范中,它表示为[[Prototype]]
。
由于[[Prototype]]
链接到一个对象,所以该对象有自己的[[Prototype]]
引用。这就是建立原型链的方式。
这个[[Prototype]]
链是 JS 中继承的构建块。
__proto__
对象为了访问对象的[[Prototype]]
,大多数浏览器都提供__proto__
属性。访问方式如下:
obj.__proto__
需要注意的是,这个属性不是 ECMAScript 标准的一部分,它实际上是由浏览器实现的。
除了__proto__
属性外,还有一种访问[[Prototype]]
的标准方法:
Object.getPrototypeOf(obj);
对应的有个类似的方法来设置对象的[[Prototype]]
:
Object.setPrototypeOf(obj, prototype);
[[Prototype]]
和.prototype
属性[[Prototype]]
只不过是一种用来表示物体原型的标准符号。 许多开发人员将其与.prototype
属性混淆,这是完全不同的事情,接着我们来研究一下.prototype
属性。
在 JS 中,有许多创建对象的方法。一种方法是使用构造函数,像这样使用new
关键字来调用它:
function SmartPhone(os) { this.os = os } let phone = new SmartPhone('Android')
在控制台打印 phone
对象:
{ os: "IPhone" __proto__{ constructor: ƒ SmartPhone(os) __proto__: Object } }
现在,如果我们希望在phone
对象上有一些方法,我们可以在函数上使用.prototype
属性,如下所示:
SmartPhone.prototype.isAndroid = function () { return this.os === 'Android' || 'android' }
再次创建phone
对象时,打印 phone
对象如下:
{ os: "Android" __proto__{ isAndroid: ƒ() constructor: ƒ SmartPhone(os) __proto__: Object } }
我们可以在对象的[[Prototype]]
中看到isAndroid()
方法。
简而言之,.prototype
属性基本上就像由给定的构造函数创建的[[Prototype]]
对象的蓝图。 在.prototype
属性/对象中声明的所有内容都会在对象的[[Prototype]]
中弹出。
实上,如果将 SmartPhone.prototype 与
phone 的[[Prototype]]
iPhone
클래스가 필요한 경우. 가능한 두 가지 해결 방법은 다음과 같습니다.
SmartPhone
클래스의 함수를 재사용합니다. 상속은 다른 클래스/객체의 함수를 재사용하는 방법이기도 합니다. SmartPhone
클래스에서 capturePictures
메서드를 상속하는 방법입니다. 🎜console.log(Object.getPrototypeOf(phone) === SmartPhone.prototype); // true
[[Prototype]]
으로 표현됩니다. 🎜🎜[[Prototype]]
이 개체에 연결되어 있으므로 개체에는 자체 [[Prototype]]
참조가 있습니다. 이것이 프로토타입 체인을 구축하는 방법입니다. 🎜🎜이 [[Prototype]]
체인은 JS 상속의 구성 요소입니다. 🎜🎜__proto__
객체 🎜🎜객체의 [[Prototype]]
에 액세스하기 위해 대부분의 브라우저는 __proto__
속성을 제공합니다. 액세스 방법은 다음과 같습니다. 🎜function ObjectA() { this.methodA = function () {} } let firstObj = new ObjectA() console.log(firstObj)
__proto__
속성 외에도 [[Prototype]]
에 액세스하는 표준 방법도 있습니다. 🎜function MyObject() {} MyObject.prototype.propA = 10; // 在原型上创建属性 let myObject = new MyObject(); console.log(myObject.propA); // [[Prototype]]上的属性 // 10 myObject.propA = 20; // 对象的属性 console.log(myObject.propA); // 20
[[Prototype]]
을 설정하는 방법: 🎜let obj = {}
[[Prototype]]
및 .prototype
속성 🎜🎜[ [Prototype]]
은 객체의 프로토타입을 나타내는 데 사용되는 표준 기호에 지나지 않습니다. 많은 개발자가 이를 .prototype
속성과 혼동하는데 이는 완전히 다른 것입니다. .prototype
속성을 살펴보겠습니다. 🎜🎜JS에서는 객체를 생성하는 방법이 다양합니다. 한 가지 방법은 생성자를 사용하는 것입니다. 다음과 같이 new
키워드를 사용하여 호출합니다. 🎜let obj = new Object();
phone
개체를 인쇄합니다. 🎜let SmartPhone = { captureImages: function() {} } let Iphone = Object.create(SmartPhone) Iphone.captureImages()
phone
개체에는 몇 가지 메서드가 있으며 다음과 같이 함수의 .prototype
속성을 사용할 수 있습니다. 🎜function SmartPhone(os) { this.os = os; } SmartPhone.prototype.isAndroid = function() { return this.os === 'Android'; }; SmartPhone.prototype.isIOS = function() { return this.os === 'iOS'; };
phone
개체 만들기 다시 phone
개체를 인쇄하면 다음과 같습니다. 🎜function Iphone() { SmartPhone.call(this, 'iOS'); }
[[Prototype]]
에서 isAndroid()
메서드를 볼 수 있습니다. 🎜🎜간단히 말하면, .prototype
속성은 기본적으로 주어진 생성자에 의해 생성된 [[Prototype]]
객체에 대한 청사진과 같습니다. .prototype
속성/객체에 선언된 모든 항목은 객체의 [[Prototype]]
에 나타납니다. 🎜🎜실제로 SmartPhone.prototype을
휴대폰의 [[Prototype]]
과 비교해 보면 둘이 동일하다는 것을 알 수 있습니다. 🎜Iphone.prototype = Object.create(SmartPhone.prototype);
function ObjectA() { this.methodA = function () {} } let firstObj = new ObjectA() console.log(firstObj)
这种方法的问题是当我们初始化一个新对象时。所有实例都有自己methodA
的副本。相反,当我们在函数的原型上创建它时,对象的所有实例只共享方法的一个副本,显然使用原型的方式效率会过高。
当我们访问一个属性以获取它时,会发生以下情况:
JS 引擎查找对象上的属性,如果找到了该属性,然后返回它。否则,JS 引擎将通过查看[[Prototype]]
来检查对象的继承属性,如果找到该属性,则返回它,否则,它会查找 [[Prototype]]
的[[Prototype]]
。 找到属性或没有[[Prototype]]
时,该链结束,这意味着我们已经到达原型链的末端。
当我们设置/创建属性时,JS 总是在对象本身上进行设置。 即使[[Prototype]]
链上存在相同的属性,下面是一个例子:
function MyObject() {} MyObject.prototype.propA = 10; // 在原型上创建属性 let myObject = new MyObject(); console.log(myObject.propA); // [[Prototype]]上的属性 // 10 myObject.propA = 20; // 对象的属性 console.log(myObject.propA); // 20
在上面的示例中,我们创建了一个构造函数,该函数的[[Prototype]]
上具有属性propA
。 当我们尝试对其进行读取操作时,会在控制台中看到该值。 但是,当我们尝试在对象本身上设置相同的属性时;JS 使用给定值在对象上创建一个新属性。 现在,如果我们不能直接访问[[Prototype]]
上的属性。
值得注意的是,普通对象的[[Prototype]]
链的末尾是内置的Object.prototype
。 这就是为什么大多数对象共享许多方法(例如toString()
)的原因。 因为它们实际上是在Object.prototype
上定义的。
在 JS 中,无论我们如何创建对象,只有原型继承,但这些方式还有一些区别,来看看:
在JavaScript中创建对象的最简单方法是使用对象字面量:
let obj = {}
如果在浏览器的控制台中打印obj
,我们将看到以下内容:
基本上,所有用文字面量创建的对象都继承了Object.prototype
的属性。
需要注意的是__proto__
对象引用了创建它的构造函数。 在这种情况下,constructor
属性指向Object
构造函数。
另一种不太常见的创建对象的方法是使用对象构造函数。JS 提供了一个名为Object
的内置构造函数方法来创建对象。
let obj = new Object();
这种方法的结果与对象字面量的方式相同。它从Object.prototype
继承属性。因为我们使用Object
作为构造函数。
使用此辅助方法,我们可以创建一个带有[[Prototype]]
的对象,如下所示:
let SmartPhone = { captureImages: function() {} } let Iphone = Object.create(SmartPhone) Iphone.captureImages()
这是在 JS 中使用继承的最简单方法之一。猜猜我们如何在没有任何[[Prototype]]
引用的情况下创建对象?
与 JS 运行时提供的对象构造函数相似。 我们还可以创建自己的构造函数,以创建适合我们需求的对象,如下所示:
function SmartPhone(os) { this.os = os; } SmartPhone.prototype.isAndroid = function() { return this.os === 'Android'; }; SmartPhone.prototype.isIOS = function() { return this.os === 'iOS'; };
现在,我们想创建一个iPhone
类,它应该有'iOS'
作为它 os
属性的值。它还应该有faceIDScan
方法。
首先,我们必须创建一个Iphone
构造函数,在其中,我们应该调用SmartPhone
构造函数,如下所示:
function Iphone() { SmartPhone.call(this, 'iOS'); }
这会将Iphone
构造函数中的this.os
属性设置为’iOS‘
。
之所以调用SmartPhone.call
方法,是因为我们需要更改 this
值以引用Iphone
。 这类似于在面向对象的世界中调用父级的构造函数。
接下来的事情是,我们必须从SmartPhone
构造函数继承方法。 我们可以在此处使用Object.create
朋友,如下所示:
Iphone.prototype = Object.create(SmartPhone.prototype);
现在,我们可以使用.prototype
为Iphone
添加方法,如下所示:
Iphone.prototype.faceIDScan = function() {};
最后,我们可以使用Iphone
创建一个对象,如下所示:
let x = new Iphone(); // calling inherited method console.log(x.isIOS()): // true
使用ES6,整个过程非常简单。 我们可以创建类(它们与C ++或其他任何基于类的语言中的类不同,只是在原型继承之上的语法糖),然后从其他类派生新的类。
下面是我们如何在ES6中创建类:
class SmartPhone { constructor(os) { this.os = os; } isAndroid() { return this.os === 'Android'; } isIos() { return this.os === 'iOS'; } };
现在,我们可以创建一个派生自SmartPhone
的新类,如下所示:
class Iphone extends SmartPhone { constructor() { super.call('iOS'); } faceIDScan() {} }
我们不是调用SmartPhone.call
,而是调用super.call
。 在内部,JavaScript引擎会自动为我们执行此操作。
最后,我们可以使用Iphone
创建一个对象,如下所示
let x = new Iphone(); x.faceIDScan(); // calling inherited method console.log(x.isIos()): // true
该ES6示例与先前的构造方法示例相同。 但是阅读和理解起来要干净得多。
原文:https://javascript.info/prototype-inheritance
作者:Indermohan Sing
更多编程相关知识,请访问:编程课程!!
위 내용은 JavaScript 프로토타입에서 상속을 구현하는 방법 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!