목차
객체 프로토타입
原型链
使用原型
原型继承
🎜프로토타입 상속🎜
修改原型
ES6 的 Class
总结
웹 프론트엔드 JS 튜토리얼 JavaScript의 객체 프로토타입 및 프로토타입 체인 이해

JavaScript의 객체 프로토타입 및 프로토타입 체인 이해

Nov 20, 2020 pm 05:26 PM
javascript 프로토타입 체인

이 글에서는 JavaScript의 객체 프로토타입과 프로토타입 체인을 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.

JavaScript의 객체 프로토타입 및 프로토타입 체인 이해

객체 프로토타입

모두가 다음과 같이 map을 사용했다고 생각합니다. map

let arr = [0, 1, 2]
let doubleArr = arr.map(c => c * 2)
console.log(doubleArr) // 0, 2, 4
로그인 후 복사

不知道你有没有想过, arr 本身并没有设定 map 属性,那为什么可以用 map 这个函数呢?

把它打印出来看看:

console.log(arr)
// 0: 0
// 1: 1
// 2: 2
// length: 3
// __proto__: Array(0)
로그인 후 복사

出现了一个名为 __proto__ 的对象,如果再将其展开,就会看到所有 Array 对象可以使用的函数;当然我们也可以在其中找到 map 函数,而这也正是例子中所调用的 arr.map 这个函数:

console.log(arr.map === arr.__proto__.map) // true
로그인 후 복사

这里出现的 __proto__ 对象,也就是所谓的 原型对象(Prototype)

不同于 Java、C# 等基于类(Class) 的面向对象语言,通过定义类、创建实例、指定继承等方式来传递属性及方法;Javascript 则是个基于原型(Prototype)的对语言 ,通过预先建立出的原型对象,当新对象建立时指定对象的原型要参照哪个原型对象。

而当我们调用对象的属性或方法时,若对象本身没有这个属性或方法,JavaScript 会自动寻找它原型中的方法,这也就是为什么可以直接调用 arr.map 而不会出错的原因。

原型链

你可能已经发现在前面的例子中,__proto__ 对象里仍然有 __proto__ 属性:

console.log(arr.__proto__) // Array 的 Prototype
console.log(arr.__proto__.__proto__) // Object 的 Prototype
console.log(arr.__proto__.__proto__.__proto__) // null
로그인 후 복사

在上述机制中,每当对象建立时都会绑定原型,既然对象都有原型,对象原型本身也是对象,自然也不例外;由这个例子中我们可以看出:

  • arr 是数组实例,原型是 Array
  • arr.__proto__ 是数组的原型,原型是 Object
  • arr.__proto__.__proto__ 是对象的原型,原型是 null
  • arr.__proto__.__proto__.__proto__ 是 null,没有任何属性

由于每个对象都有原型,这样就形成了一个关联一个、层层相互依赖的从属关系,我们把它们叫做原型链(Prototype Chain) ;通过这种机制,让对象得以使用原型中的属性和方法,并凭借原型链一层一层的按顺序继承,让对象能拥有原型链上所有原型的功能,这就是 JavaScript 对象背后的运作机制。

补充:在 JavaScript 中,几乎每个原型链的末端都会是 Object,并最后指向到  null

使用原型

说了这么多,该来点代码了,接下来就来练习一下原型的建立、设定及修改吧。

先来创建一个新的对象构造函数:

function Person(name) {
  this.name = name
}Person.prototype.hello = function () {
  console.log(`Hello ${this.name}.`)
}let gary = new Person('Gary')
gary.hello() // Hello Gary.Object.getPrototypeOf(gary) // {hello: ƒ, constructor: ƒ}
로그인 후 복사

上面的例子创建了一个简单的对象构造函数 Person(),并在构造函数中设定对象属性。对象的方法中,由于方法不需要让每个对象都独自拥有一份,以避免造成冗余的内存消耗,应该要像前面 Array.prototype.map 的例子那样把对象的方法设定给原型对象(Person.prototype),让这个构造函数创建出来的对象都可以共用这些方法。最后建立一个新的 Person 对象,并通过 getPrototypeOf(obj) 获取新产生对象的原型。

Q:为什么不直接用 __proto__ 获取原型对象?
A:因为虽然 __proto__ 被几乎所有的浏览器支持,但它是非标准属性;通过 getPrototypeOf 取得对象的原型是正确的方法。

提醒:Person.prototype 不是 Person 的原型,而是构造函数执行后所建立的新对象的原型;千万不要把构造函数的 prototype 属性对象的原型搞混!

原型继承

接着再创建新的对象原型,并继承 Person

function Engineer(name, skill) {
  Person.call(this, name)
  this.skill = skill
}
Engineer.prototype = Object.create(Person.prototype)
Engineer.prototype.constructor = Engineerlet alice = new Engineer('Alice', 'JavaScript')
alice.hello() // Hello Alice.
console.log(alice.skill) // JavaScriptObject.getPrototypeOf(alice) 
// Person {constructor: ƒ}
로그인 후 복사

这里建立了新的对象 Engineer 的原型,并通过 Engineer.prototype 的指定,让它的原型继承自 Person.prototype,最后再重新设定 Engineer.prototype.constructor

Object.defineProperty(Vue.prototype, '$date', { value: dateTimeFormat })
// 之后就可以这样用
vm.$date(dateObj)
로그인 후 복사
로그인 후 복사
생각해보셨는지 모르겠지만 arr 자체에는 map 속성이 설정되어 있지 않은데 왜 map 함수를 사용할 수 있습니까? 🎜🎜인쇄하여 확인하세요. 🎜
Person.prototype.hello = function () {
  console.log(`Bye ${this.name}.`)
}gary.hello() // Bye Gary.
alice.hello() // Bye Alice.
로그인 후 복사
로그인 후 복사
🎜__proto__라는 개체가 나타납니다. 확장하면 Array 개체에서 사용할 수 있는 모든 기능을 볼 수 있습니다. map 함수가 포함되어 있으며 이것이 바로 예제에서 호출된 arr.map 함수입니다. 🎜
class Person {
  constructor (name){
    this.name = name
  }
  // 方法会自动放到 Person.prototype
  hello() {
    console.log(`Hello ${this.name}.`)
  }
}class Engineer extends Person {
  constructor (name, skill){
    super(name) // 调用 Person 的构造函数
    this.skill = skill
  }
}let alice = new Engineer('Alice', 'JavaScript')
alice.hello() // Hello Alice.Object.getPrototypeOf(alice) 
// Person {constructor: ƒ}
로그인 후 복사
로그인 후 복사
🎜__proto__가 여기에 나타납니다. 객체라고도 함 🎜프로토타입 🎜으로. 🎜🎜클래스 정의, 인스턴스 생성, 상속 지정 등을 통해 속성과 메서드를 전달하는 Java, C# 및 기타 🎜클래스 기반 객체 지향 언어와는 다릅니다. Javascript는 🎜프로토타입 기반 언어🎜입니다. 확립된 프로토타입 객체는 새로운 객체가 생성될 때 객체의 프로토타입이 어떤 프로토타입 객체를 참조해야 하는지 지정합니다. 🎜🎜객체의 속성이나 메소드를 호출할 때 객체 자체에 이 속성이나 메소드가 없으면 JavaScript는 자동으로 프로토타입에서 메소드를 찾습니다. 이것이 바로 arr.map을 호출할 수 있는 이유입니다. code>를 직접적으로 설명하고 잘못될 수 없는 이유를 설명합니다. 🎜🎜🎜프로토타입 체인🎜🎜🎜이전 예에서 __proto__ 개체에 여전히 __proto__ 속성이 있다는 것을 발견했을 수 있습니다. 🎜rrreee🎜위 메커니즘에서는 언제든지 프로토타입은 생성될 때 객체에 바인딩됩니다. 객체 프로토타입 자체도 객체이므로 당연히 이 예제에서 볼 수 있습니다. 🎜
  • arr는 Array 인스턴스이고 프로토타입은 Array입니다.
  • arr.__proto__는 배열의 프로토타입이고 프로토타입은 Object입니다.
  • arr .__proto__.__proto__ 객체의 프로토타입입니다. 프로토타입은 null
  • arr.__proto__.__proto__.__proto__입니다. null이며 속성이 없습니다
🎜각 개체에는 프로토타입이 있으므로 서로 관련되고 계층별로 종속되는 종속 관계가 형성됩니다. 이 메커니즘을 통해 객체는 프로토타입의 속성과 메서드를 사용할 수 있으며 프로토타입 체인의 계층별 순차적 상속을 사용하여 객체가 프로토타입 체인의 모든 프로토타입 기능을 가질 수 있도록 합니다. JavaScript 객체 뒤에 숨은 메커니즘. 🎜
추가: JavaScript에서는 거의 모든 프로토타입 체인의 끝이 Object이고 마지막으로 null을 가리킵니다.
🎜🎜프로토타입 사용하기🎜🎜🎜 지금까지 설명을 마쳤으니 이제 코드를 작성해 보겠습니다. 다음으로 프로토타입 생성, 설정 및 수정을 연습해 보겠습니다. 🎜🎜먼저 새 개체 생성자를 만듭니다. 🎜rrreee🎜위의 예에서는 간단한 개체 생성자 Person()을 만들고 생성자에서 개체 속성을 설정합니다. 객체의 메소드에서는 중복된 메모리 소모를 방지하기 위해 객체별로 별도의 복사본을 가질 필요가 없으므로 이전의 Array.prototype.map 예시와 같이 객체를 사용해야 합니다. 메소드는 프로토타입 객체(Person.prototype)로 설정되므로 이 생성자에 의해 생성된 객체는 이러한 메소드를 공유할 수 있습니다. 마지막으로, 새로운 Person 객체를 생성하고 getPrototypeOf(obj)를 통해 새로 생성된 객체의 프로토타입을 얻습니다. 🎜
Q: 프로토타입 객체를 얻기 위해 __proto__를 직접 사용하면 어떨까요?
A: __proto__는 거의 모든 브라우저에서 지원되지만 이는 비표준 속성이기 때문에 getPrototypeOf를 통해 객체의 프로토타입을 얻는 것이 올바른 방법입니다. . 🎜알림: Person.prototypePerson의 프로토타입이 아니지만 생성자가 실행된 후 생성된 새 객체의 프로토타입은 절대 🎜를 대체하지 않습니다. 생성자 프로토타입 속성 🎜이 🎜 객체의 프로토타입 🎜과 혼동됩니다! 🎜

🎜프로토타입 상속🎜

🎜그런 다음 새 개체 프로토타입을 만들고 Person을 상속합니다. 🎜rrreee🎜새 개체 Engineer의 프로토타입을 <code>Engineer.prototype으로 지정하여 해당 프로토타입이 Person.prototype에서 상속되도록 하고 마지막으로 Engineer.prototype 생성자를 재설정합니다. > 생성자가 자신을 다시 가리키도록 하면 가장 기본적인 프로토타입 상속이 완료됩니다. 🎜
Q:为什么需要重新设定 constructor
A:这边功过 Object.create 复制了 Person.prototype 的全部属性,连同 constructor 属性都会被覆盖掉,如果 constructor 属性错误,在做 instanceof 判断时会产生错误的结果;因此这边设定继承时需要再次将 constructor 重新指定回构造函数本身。

修改原型

原型的引用、继承是直接参照到原型对象上,并非是在每个对象都复制一份原型;因此可以利用这个特性,在原型上增加自定义的属性和方法,让所有该类型的对象都能得到新方法;许多针对旧版浏览器的 Polyfill 就是这样实现的。

例如我们在写 Vue 项目的时候,可能都有做过类似的操作,把共用性高的属性方法放到  Vue.prototype 中:

Object.defineProperty(Vue.prototype, '$date', { value: dateTimeFormat })
// 之后就可以这样用
vm.$date(dateObj)
로그인 후 복사
로그인 후 복사

这样的确很方便,但也要提醒开大家,当我们在做原型修改的时候要特别小心。接着刚才的例子,如果尝试对 Person 原型中的方法做个修改:

Person.prototype.hello = function () {
  console.log(`Bye ${this.name}.`)
}gary.hello() // Bye Gary.
alice.hello() // Bye Alice.
로그인 후 복사
로그인 후 복사

如结果所示,当对象原型做修改时,所有原型链上有这个原型的对象,通通都会受到影响,不管对象是在修改前还是修改后创建的。

建议大家除非是 Polyfill,否则应该要极力避免对原生对象的原型进行修改,防止造成可能的意外结果。

ES6 的 Class

看完前面这一大段,是不是觉得心很累?别担心,从 ES6 开始添加了 Class 语法糖,使开发者体验提升了很多。下面把前面的例子用  Class 重构一下:

class Person {
  constructor (name){
    this.name = name
  }
  // 方法会自动放到 Person.prototype
  hello() {
    console.log(`Hello ${this.name}.`)
  }
}class Engineer extends Person {
  constructor (name, skill){
    super(name) // 调用 Person 的构造函数
    this.skill = skill
  }
}let alice = new Engineer('Alice', 'JavaScript')
alice.hello() // Hello Alice.Object.getPrototypeOf(alice) 
// Person {constructor: ƒ}
로그인 후 복사
로그인 후 복사

很方便,同样的功能,代码的可读性却提高了不少,繁琐的设定也都能交给语法自动帮你完成。不过方便的语法背后,底层仍然是对象原型及原型链。

总结

以上是 JavaScript 中关于对象原型的说明,希望能帮你理解对象原型,在这个什么都是对象的语言中,充分理解并掌握对象原型,是成为专业码农必须要突破的关卡之一。

更多编程相关知识,请访问:编程课程!!

위 내용은 JavaScript의 객체 프로토타입 및 프로토타입 체인 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 Dec 17, 2023 pm 02:54 PM

WebSocket 및 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 소개: 지속적인 기술 개발로 음성 인식 기술은 인공 지능 분야의 중요한 부분이 되었습니다. WebSocket과 JavaScript를 기반으로 한 온라인 음성 인식 시스템은 낮은 대기 시간, 실시간, 크로스 플랫폼이라는 특징을 갖고 있으며 널리 사용되는 솔루션이 되었습니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법을 소개합니다.

WebSocket 및 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 WebSocket 및 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 Dec 17, 2023 pm 05:30 PM

WebSocket과 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 서론: 인터넷 기술의 급속한 발전과 함께 실시간 모니터링 시스템이 다양한 분야에서 널리 활용되고 있다. 실시간 모니터링을 구현하는 핵심 기술 중 하나는 WebSocket과 JavaScript의 조합입니다. 이 기사에서는 실시간 모니터링 시스템에서 WebSocket 및 JavaScript의 적용을 소개하고 코드 예제를 제공하며 구현 원칙을 자세히 설명합니다. 1. 웹소켓 기술

WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 Dec 17, 2023 am 09:39 AM

WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 오늘날의 디지털 시대에는 점점 더 많은 기업과 서비스에서 온라인 예약 기능을 제공해야 합니다. 효율적인 실시간 온라인 예약 시스템을 구현하는 것이 중요합니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. WebSocket이란 무엇입니까? WebSocket은 단일 TCP 연결의 전이중 방식입니다.

JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 Dec 17, 2023 pm 12:09 PM

JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 소개: 인터넷의 대중화와 기술의 발전으로 점점 더 많은 레스토랑에서 온라인 주문 서비스를 제공하기 시작했습니다. 실시간 온라인 주문 시스템을 구현하기 위해 JavaScript 및 WebSocket 기술을 사용할 수 있습니다. WebSocket은 TCP 프로토콜을 기반으로 하는 전이중 통신 프로토콜로 클라이언트와 서버 간의 실시간 양방향 통신을 실현할 수 있습니다. 실시간 온라인 주문 시스템에서는 사용자가 요리를 선택하고 주문을 하면

JavaScript와 WebSocket: 효율적인 실시간 일기예보 시스템 구축 JavaScript와 WebSocket: 효율적인 실시간 일기예보 시스템 구축 Dec 17, 2023 pm 05:13 PM

JavaScript 및 WebSocket: 효율적인 실시간 일기 예보 시스템 구축 소개: 오늘날 일기 예보의 정확성은 일상 생활과 의사 결정에 매우 중요합니다. 기술이 발전함에 따라 우리는 날씨 데이터를 실시간으로 획득함으로써 보다 정확하고 신뢰할 수 있는 일기예보를 제공할 수 있습니다. 이 기사에서는 JavaScript 및 WebSocket 기술을 사용하여 효율적인 실시간 일기 예보 시스템을 구축하는 방법을 알아봅니다. 이 문서에서는 특정 코드 예제를 통해 구현 프로세스를 보여줍니다. 우리

간단한 JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법 간단한 JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법 Jan 05, 2024 pm 06:08 PM

JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법, 특정 코드 예제가 필요합니다. 서문: 웹 개발에서는 서버와의 데이터 상호 작용이 종종 포함됩니다. 서버와 통신할 때 반환된 HTTP 상태 코드를 가져와서 작업의 성공 여부를 확인하고 다양한 상태 코드에 따라 해당 처리를 수행해야 하는 경우가 많습니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법과 몇 가지 실용적인 코드 예제를 제공합니다. XMLHttpRequest 사용

JavaScript에서 HTTP 상태 코드를 쉽게 얻는 방법 JavaScript에서 HTTP 상태 코드를 쉽게 얻는 방법 Jan 05, 2024 pm 01:37 PM

JavaScript에서 HTTP 상태 코드를 얻는 방법 소개: 프런트 엔드 개발에서 우리는 종종 백엔드 인터페이스와의 상호 작용을 처리해야 하며 HTTP 상태 코드는 매우 중요한 부분입니다. HTTP 상태 코드를 이해하고 얻는 것은 인터페이스에서 반환된 데이터를 더 잘 처리하는 데 도움이 됩니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. HTTP 상태 코드란 무엇입니까? HTTP 상태 코드는 브라우저가 서버에 요청을 시작할 때 서비스가

자바스크립트에서 insertBefore를 사용하는 방법 자바스크립트에서 insertBefore를 사용하는 방법 Nov 24, 2023 am 11:56 AM

사용법: JavaScript에서 insertBefore() 메서드는 DOM 트리에 새 노드를 삽입하는 데 사용됩니다. 이 방법에는 삽입할 새 노드와 참조 노드(즉, 새 노드가 삽입될 노드)라는 두 가지 매개 변수가 필요합니다.

See all articles