Javascript는 객체 지향입니다. js에 내장된 각 객체는 객체에서 파생되므로 상속, 다형성 및 재구성이라는 세 가지 객체 지향 기능이 있습니다. 현재 js는 프로토타입의 의사 상속을 기반으로 하지만 일반적으로 아이디어는 객체 지향 언어입니다.
이 튜토리얼의 운영 환경: Windows 7 시스템, JavaScript 버전 1.8.5, Dell G3 컴퓨터.
다른 언어와 비교할 때 JavaScript의 "객체"는 항상 그다지 복잡해 보이지 않습니다. 일부 신규 이민자들은 JavaScript 객체 지향을 배울 때 종종 의구심을 갖습니다. 왜 JavaScript(ES6까지)에는 객체 개념이 있지만 다른 언어처럼 클래스 개념이 없습니까? JavaScript 개체에는 속성을 자유롭게 추가할 수 있지만 다른 언어에는 추가할 수 없는 이유는 무엇입니까?
일부 논쟁에서도 JavaScript는 "객체 지향 언어"가 아니라 "객체 기반 언어"라는 점을 강조하는 사람들도 있었습니다. 사실 저는 지금까지 이것을 주장하는 사람들을 만났습니다. "객체지향과 객체기반을 어떻게 정의할 것인가"라는 질문에 답할 수 있는 사람은 아무도 없습니다.
실제로 객체 기반과 객체 지향이라는 두 가지 형용사는 다양한 버전의 JavaScript 표준에 등장했습니다. 먼저 JavaScript 표준의 객체 기반 정의를 살펴보겠습니다. 이 정의의 구체적인 내용은 다음과 같습니다. "언어와 호스트의 인프라는 객체에 의해 제공되며 ECMAScript 프로그램은 서로 통신하는 객체의 모음입니다. ." 여기서의 의미는 전혀 약화된 객체지향적 의미를 표현하는 것이 아니라 언어에 있어서 객체의 중요성을 표현하는 것이다.
그래서 이번 글에서는 객체지향이 무엇인지, 자바스크립트에서 객체지향이 무엇인지에 대해 알려드리고자 합니다.
먼저 객체가 무엇인지부터 이야기해 보겠습니다. 번역상의 이유로 중국어 문맥에서는 '객체'의 진정한 의미를 이해하기 어렵습니다. 실제로 Object는 영어의 모든 것을 가리키는 일반적인 용어로, 객체지향 프로그래밍의 추상적인 사고와 공통점이 있습니다. 중국어의 "객체"는 프로그래밍을 배우는 과정에서 이러한 보편성을 갖지 않습니다.
그러나 어쨌든 우리는 객체가 컴퓨터 분야의 허공에서 만들어진 개념이 아니라는 점을 깨달아야 합니다. 객체는 인간의 사고 패턴을 따르는 추상화입니다. 따라서 객체 지향 프로그래밍도 인간의 사고 패턴에 더 가까운 것으로 간주됩니다. ) 프로그래밍 패러다임).
그러면 먼저 인간의 사고 모델에서 객체가 정확히 무엇인지 살펴보겠습니다.
객체의 개념은 인간의 어린 시절에 형성되었으며, 이는 프로그래밍 논리에서 일반적으로 사용되는 가치, 프로세스 및 기타 개념보다 훨씬 이전입니다. 어린 시절에 우리는 항상 특정 사과를 먹을 수 있다는 것을 먼저 깨닫고(여기서 특정 사과는 객체이다) 모든 사과를 먹을 수 있다는 것을 깨닫고(여기 있는 모든 사과는 클래스이다) 나중에 우리는 오직 그때만이 먹을 수 있다는 것을 깨닫는다. 사과 세 개와 배 세 개 사이의 연결을 깨닫고 숫자 "3"(가치)의 개념을 생성합니다.
Grady Booch는 "객체 지향 분석 및 설계"라는 책에서 이를 요약했습니다. 그는 인간의 인지적 관점에서 객체는 다음 중 하나여야 한다고 믿습니다.
만질 수 있는 객체 또는 그 어떤 것
인간의 지능으로 이해할 수 있는 것
생각이나 행동을 안내할 수 있는 것(상상하거나 행동을 수행하는 것)
객체의 자연스러운 정의를 통해 프로그래밍 언어로 객체를 설명할 수 있습니다. 다양한 프로그래밍 언어에서 디자이너는 다양한 언어 기능을 사용하여 객체를 추상적으로 설명합니다. 가장 성공적인 학교는 "클래스"를 사용하여 C++ 및 Java와 같은 인기 있는 프로그래밍 언어를 탄생시킨 것입니다. 초창기에 JavaScript는 더 인기가 없는 방법인 프로토타입을 선택했습니다. (나는 다음 기사에서 프로토타입에 초점을 맞출 것이며 여기에 인상을 남길 수 있습니다.) 이것이 앞서 제가 비사교적이라고 말한 이유 중 하나입니다.
안타깝게도 회사의 정치적인 이유로 JavaScript는 출시 당시 경영진으로부터 Java를 모방하라는 명령을 받았습니다. 따라서 JavaScript 창립자 Brendan Eich는 "프로토타입 런타임"을 기반으로 하는 새로운 언어 기능을 도입하여 " Java와 더 유사해 보입니다."
ES6가 등장하기 전에 많은 JavaScript 프로그래머는 JavaScript를 프로토타입 시스템 기반의 클래스 기반 프로그래밍에 더 가깝게 만들려고 시도했으며 그 결과 PrototypeJS 및 Dojo와 같은 소위 "프레임워크"가 많이 탄생했습니다. 사실, 그들은 일종의 이상한 JavaScript 방언이 되었고, 심지어 상호 호환되지 않는 일련의 커뮤니티를 탄생시켰습니다. 분명히 지금까지의 이익이 손실보다 더 컸습니다.
런타임 관점에서 객체에 대해 이야기한다면 JavaScript의 실제 실행 모델을 논의하는 것입니다. 이는 모든 코드 실행이 런타임 객체 모델을 피해서는 안 되기 때문입니다. 그러나 다행히도 런타임 관점에서는 그렇지 않습니다. 클래스의 개념이 모든 언어 런타임에서 희석되기 때문에 이러한 "클래스 기반 기능"에 신경 쓸 필요가 없습니다.
먼저 JavaScript가 객체 모델을 설계하는 방법을 이해해 봅시다.
제 생각에는 어떤 프로그래밍 언어를 사용하든 먼저 객체의 본질적인 특성을 이해해야 합니다(Grandy Booch의 "객체 지향 분석 및 설계" 참조). 요약하면, 객체는 다음과 같은 특징을 가지고 있습니다.
객체는 고유하게 식별 가능합니다. 심지어 완전히 동일한 두 객체라도 동일한 객체는 아닙니다.
객체에는 상태가 있습니다. 객체에는 상태가 있으며 동일한 객체가 다른 상태에 있을 수 있습니다.
객체에는 동작이 있습니다. 즉, 동작으로 인해 객체의 상태가 변경될 수 있습니다.
첫 번째 특징을 먼저 살펴보겠습니다. 개체는 고유하게 식별 가능합니다. 일반적으로 다양한 언어의 개체에 대한 고유한 식별은 메모리 주소에 반영됩니다. 따라서 JavaScript 프로그래머는 서로 다른 JavaScript 개체가 실제로 서로 동일하지 않다는 것을 알고 있습니다. 먼저 다음 코드를 볼 수 있습니다. 얼핏 보면 두 개의 동일한 개체이지만 인쇄된 결과는 거짓입니다.
var o1 = { a: 1 }; var o2 = { a: 1 }; console.log(o1 == o2); // false
객체의 두 번째와 세 번째 특성인 "상태와 동작"에 대해서는 언어마다 추상적으로 설명하기 위해 다른 용어를 사용합니다. 예를 들어 C++에서는 "멤버 변수", "멤버 함수"라고 합니다. 멤버 함수"를 Java로 호출합니다. 그런 다음 "속성"과 "메서드"라고 부릅니다.
JavaScript에서는 상태와 동작이 "속성"으로 통합되어 추상화되어 있습니다. JavaScript의 함수는 특수 객체로 설계되어 있다는 점을 고려하면(이에 대해서는 나중에 자세히 설명할 것이므로 여기에서는 자세히 설명할 필요가 없습니다.) JavaScript의 동작과 상태는 속성을 사용하여 추상화할 수 있습니다.
다음 코드는 실제로 일반적인 속성과 속성으로서의 함수의 예를 보여줍니다. 여기서 o는 객체, d는 속성, 함수 f도 속성입니다. 작성 방법은 동일하지 않지만 JavaScript의 경우 d입니다. f는 두 가지 공통 속성입니다.
var o = { d: 1, f() { console.log(this.d); } };
요컨대, JavaScript에서는 객체의 상태와 동작이 실제로 속성으로 추상화됩니다. Java를 사용해 본 적이 있다면 놀라지 마십시오. 디자인 아이디어에는 일정한 차이가 있지만 둘 다 객체의 기본 특성인 ID, 상태 및 동작을 잘 표현합니다.
객체의 기본 특성을 이해한 것을 바탕으로 JavaScript의 객체 고유 기능은 객체가 매우 동적이라는 것입니다. 이는 JavaScript가 사용자에게 런타임 시 객체의 상태와 동작을 추가하고 수정할 수 있는 기능을 제공하기 때문입니다. .
예를 들어, JavaScript를 사용하면 런타임에 객체에 속성을 추가할 수 있는데, 이는 대부분의 클래스 기반 정적 객체 디자인과는 완전히 다릅니다. 자바나 다른 언어를 사용해보신 분들이라면 분명 저와 같은 느낌을 받으실 겁니다.
다음 코드는 런타임에 객체에 속성을 추가하는 방법을 보여줍니다. 처음에는 객체 o를 정의한 후 해당 속성 b를 추가했습니다. 당신은 이것을 이해해야합니다.
var o = { a: 1 }; o.b = 2; console.log(o.a, o.b); //1 2
추상화 기능을 향상시키기 위해 JavaScript 속성은 다른 언어보다 더 복잡하게 설계되었습니다. 두 가지 유형의 데이터 속성과 접근자 속성(getter/setter)을 제공합니다.
JavaScript의 경우 속성은 단순한 이름과 값이 아닙니다. JavaScript는 일련의 특성을 사용하여 속성을 설명합니다.
첫 번째 속성 유형인 데이터 속성에 대해 먼저 이야기해 보겠습니다. 다른 언어의 속성 개념에 더 가깝습니다. 데이터 속성에는 네 가지 특성이 있습니다.
value: 속성의 값입니다.
writable: 속성에 값을 할당할 수 있는지 여부를 결정합니다.
enumerable: for in이 이 속성을 열거할 수 있는지 여부를 결정합니다.
configurable: 속성을 삭제할 수 있는지 또는 특성 값을 변경할 수 있는지 결정합니다.
대부분의 경우 데이터 속성의 값에만 관심이 있습니다.
두 번째 유형의 속성은 접근자(getter/setter) 속성으로, 이 속성에도 4가지 특성이 있습니다.
getter: 함수 또는 정의되지 않음, 속성 값을 가져올 때 호출됩니다.
setter: 함수 또는 정의되지 않음, 속성 값을 설정할 때 호출됩니다.
enumerable: for in이 이 속성을 열거할 수 있는지 여부를 결정합니다.
configurable: 속성을 삭제할 수 있는지 또는 특성 값을 변경할 수 있는지 결정합니다.
접근자 속성을 사용하면 속성을 읽고 쓸 때 코드가 실행될 수 있습니다. 이를 통해 사용자는 속성을 쓸 때와 읽을 때 완전히 다른 값을 얻을 수 있습니다.
우리가 일반적으로 속성을 정의하는 데 사용하는 코드는 데이터 속성을 생성하며, 그 중 쓰기 가능, 열거 가능 및 구성 가능은 모두 기본값이 true입니다. 다음 코드에 표시된 대로 내장 함수 Object.getOwnPropertyDescripter를 사용하여 이를 볼 수 있습니다.
var o = { a: 1 }; o.b = 2;//a和b皆为数据属性 Object.getOwnPropertyDescriptor(o,\u0026quot;a\u0026quot;) // {value: 1, writable: true, enumerable: true, configurable: true} Object.getOwnPropertyDescriptor(o,\u0026quot;b\u0026quot;) // {value: 2, writable: true, enumerable: true, configurable: true}
여기서는 속성을 정의하기 위해 두 가지 구문을 사용하고, 이 속성을 보기 위해 JavaScript API를 사용합니다. 를 찾을 수 있으며, 이렇게 정의된 속성은 모두 데이터 속성이며, writeable, enumerable 및 configurable의 기본값은 true입니다.
속성의 특성을 변경하거나 접근자 속성을 정의하려면 Object.defineProperty를 사용하면 됩니다.
var o = { a: 1 }; Object.defineProperty(o, \u0026quot;b\u0026quot;, {value: 2, writable: false, enumerable: false, configurable: true});//a和b都是数据属性,但特征值变化了 Object.getOwnPropertyDescriptor(o,\u0026quot;a\u0026quot;); // {value: 1, writable: true, enumerable: true, configurable: true} Object.getOwnPropertyDescriptor(o,\u0026quot;b\u0026quot;); // {value: 2, writable: false, enumerable: false, configurable: true}o.b = 3;console.log(o.b); // 2
这里我们使用了Object.defineProperty来定义属性,这样定义属性可以改变属性的writable和enumerable,我们同样用Object.getOwnPropertyDescriptor来查看,发现确实改变了writable和enumerable特征。因为writable特征为false,所以我们重新对b赋值,b的值不会发生变化。
在创建对象时,也可以使用 get 和 set 关键字来创建访问器属性,代码如下所示:
var o = { get a() { return 1 } }; console.log(o.a); // 1
访问器属性跟数据属性不同,每次访问属性都会执行getter或者setter函数。这里我们的getter函数返回了1,所以o.a每次都得到1。
这样,我们就理解了,实际上JavaScript 对象的运行时是一个“属性的集合”,属性以字符串或者Symbol为key,以数据属性特征值或者访问器属性特征值为value。对象是一个属性的索引结构(索引结构是一类常见的数据结构,我们可以把它理解为一个能够以比较快的速度用key来查找value的字典)。我们以上面的对象o为例,你可以想象一下“a”是key。
这里{writable:true,value:1,configurable:true,enumerable:true}是value。我们在前面的类型课程中,已经介绍了Symbol类型,能够以Symbol为属性名,这是JavaScript对象的一个特色。
讲到了这里,如果你理解了对象的特征,也就不难理解我开篇提出来的问题。
你甚至可以理解为什么会有“JavaScript不是面向对象”这样的说法:JavaScript的对象设计跟目前主流基于类的面向对象差异非常大。而事实上,这样的对象系统设计虽然特别,但是JavaScript提供了完全运行时的对象系统,这使得它可以模仿多数面向对象编程范式(下一节课我们会给你介绍JavaScript中两种面向对象编程的范式:基于类和基于原型),所以它也是正统的面向对象语言。
JavaScript语言标准也已经明确说明,JavaScript是一门面向对象的语言,我想标准中能这样说正因为JavaScript的高度动态性的对象系统。
所以,我们应该在理解其设计思想的基础上充分挖掘它的能力,而不是机械地模仿其它语言。
要想理解JavaScript对象,必须清空我们脑子里“基于类的面向对象”相关的知识,回到人类对对象的朴素认知和面向对象的语言无关基础理论,我们就能够理解JavaScript面向对象设计的思路。
在这篇文章中,我从对象的基本理论出发,和你理清了关于对象的一些基本概念,分析了JavaScript对象的设计思路。接下来又从运行时的角度,介绍了JavaScript对象的具体设计:具有高度动态性的属性集合。
很多人在思考JavaScript对象时,会带着已有的“对象”观来看问题,最后的结果当然就是“剪不断理还乱”了。
【推荐学习:javascript高级教程】
위 내용은 자바스크립트는 객체 기반인가요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!