> 웹 프론트엔드 > JS 튜토리얼 > Javascript 객체지향 프로그래밍(coolshell)_js 객체지향

Javascript 객체지향 프로그래밍(coolshell)_js 객체지향

WBOY
풀어 주다: 2016-05-16 17:55:08
원래의
1286명이 탐색했습니다.

지난 이틀 동안 전 동료가 나에게 Javascript의 객체지향 프로그래밍에 대해 문의해 왔습니다. 그래서 나는 그가 읽을 수 있도록 기사를 작성하고 싶습니다. 이 기사는 주로 Javascript의 객체지향 프로그래밍을 전반적인 관점에서 설명하고 싶습니다. . (급하게 쓴 글이라 부정확한 내용이나 오류가 있을 수 있습니다. 비판과 정정 부탁드립니다.)
또한 이 글은 주로 ECMAScript 5를 기반으로 하며 새로운 기술을 소개하는 것을 목표로 하고 있습니다. 호환성에 대해서는 마지막 섹션을 참조하세요.

사전 연구
Javascript에서 변수의 정의는 기본적으로 다음과 같다고 알고 있습니다.

코드 복사 코드는 다음과 같습니다.

var name = 'Chen Hao';;
var email = 'haoel(@)hotmail.com'
var website = 'http ://jb51.net ';

객체로 작성하려면 다음과 같습니다.

코드 복사 코드는 다음과 같습니다.

var chenhao = {
name :'Chen Hao',
email : 'haoel(@) hotmail.com',
웹사이트 : ' http://jb51.net'
};

다음과 같이 접속할 수 있습니다:

코드 복사 코드는 다음과 같습니다.

//회원으로서
chenhao.name; >chenhao.email;
chenhao.website;

//해시 맵 형식
chenhao["email"]; ["website"];


함수와 관련하여 Javascript 함수는 다음과 같습니다.




코드 복사 코드는 다음과 같습니다. var doSomething = function(){ alert('Hello World.')

그래서 이렇게 할 수 있습니다:




코드 복사
코드는 다음과 같습니다.var sayHello = function(){ var hello = "안녕하세요. 저는 " this.name "입니다. 제 이메일 주소는 " this.email
"이며, 제 웹사이트는 " this입니다. website;
alert(hello)
};

//직접 할당, 이는 C/C 함수 포인터와 매우 유사합니다.
chenhao.Hello = sayHello; 🎜>chenhao.Hello();


저는 이러한 것들이 상대적으로 간단하다고 믿습니다. 모두가 이해합니다. 자바스크립트 객체 함수를 직접 선언하고, 직접 할당하고, 직접 사용하는 것을 볼 수 있습니다. 런타임을 위한 동적 언어.

보다 표준화된 작성 방법도 있습니다.




코드 복사

this.website = 웹사이트; sayHello = function(){
var hello = "안녕하세요, 저는 " this.name ", n"
"내 이메일은 " this.email ", n"
"내 웹사이트는 다음과 같습니다: " this.website;
alert(hello);
};
};

var chenhao = new Person("Chen Hao", "haoel@hotmail.com",
"http://jb51.net");
chenhao.sayHello();


그런데 개체의 속성을 삭제하는 방법은 매우 간단합니다.

1 delete chenhao['email']

위의 예에서 다음 사항을 확인할 수 있습니다.

Javascript의 데이터 및 멤버 캡슐화는 매우 간단합니다. 어떤 클래스도 전적으로 객체 작업이 아닙니다. 순수한 역학!
Javascript 함수에서 this 포인터가 중요합니다. 그렇지 않은 경우 로컬 변수이거나 로컬 함수입니다.
자바스크립트 객체 멤버 함수는 사용 시 임시로 선언할 수 있으며, 전역 함수를 직접 할당할 수도 있습니다.
Javascript 멤버 함수는 인스턴스에서 수정될 수 있습니다. 즉, 다른 인스턴스에서 동일한 함수 이름의 동작이 동일하지 않을 수 있습니다.
속성 구성 – Object.defineProperty
먼저 다음 코드를 살펴보세요.





코드 복사


코드 다음과 같습니다:
//객체 생성
var chenhao = Object.create(null);

//속성 설정
Object.defineProperty( chenhao,
'name', { value : 'Chen Hao',
쓰기 가능: true,
구성 가능: true,
열거 가능: true })

//여러 속성 설정
Object.defineProperties( chenhao,
{
'이메일' : { 값: 'haoel@hotmail.com',
쓰기 가능: true,
구성 가능: true,
열거 가능: true },
'웹사이트': { 값: 'http://jb51.net',
쓰기 가능: true,
구성 가능: true,
열거 가능: true }
}
)

이러한 속성 구성이 무엇을 의미하는지 이야기해 보겠습니다.

쓰기 가능: 이 속성의 값을 변경할 수 있는지 여부입니다.
configurable: 이 속성의 구성을 변경할 수 있는지 여부입니다.
열거 가능: 이 속성을 for...in 루프에서 탐색할 수 있는지 아니면 Object.keys에서 열거할 수 있는지 여부입니다.
값: 속성 값.
get()/set(_value): 접근자를 가져오고 설정합니다.
Get/Set 접근자
get/set 접근자는 get/set을 사용하여 값을 바꾸는 것을 의미합니다(값과 함께 사용할 수 없음). 예는 다음과 같습니다.

코드 복사 코드는 다음과 같습니다.
var age = 0
Object.defineProperty( chenhao,
' age', {
get: function() {return age 1;},
set: function(value) {age = value;}
enumerable : true,
configurable : true
}
);
chenhao.age = 100; //set 호출
alert(chenhao.age) //get을 호출하고 101을 출력합니다.

보다 실용적인 예를 살펴보겠습니다. 기존 속성(나이)을 사용하여 get 및 set을 통해 새 속성(birth_year)을 구성합니다.

복사 code 코드는 다음과 같습니다.

Object.defineProperty( chenhao,
'birth_year',
{
get: function() {
var d = new Date();
var y = d.getFullYear();
return ( y - this.age )
},
set: 함수(연도) {
var d = new Date();
var y = d.getFullYear();
this.age = y - 연도
}
) >
alert (chenhao.birth_year);
chenhao.birth_year = 2000;
alert(chenhao.age);


이건 좀 귀찮은 것 같아요. 이렇게 쓰는거 아닌가요? :



코드 복사 코드는 다음과 같습니다. var chenhao = {
이름: "Chen Hao",
이메일: "haoel@hotmail.com",
웹사이트: "http://jb51.net",
나이: 100,
getbirth_year() {
var d = new Date();
var y = d.getFullYear()
return ( y - this.age ),
setbirth_year(연도) {
var d = new Date();
var y = d.getFullYear()
this.age = y
}

};
alert(chenhao.birth_year) ;
chenhao.birth_year = 2000;
alert(chenhao.age)


네, 할 수 있습니다. DefineProperty()를 통해 다음 작업을 수행합니다.
1) 쓰기 가능, 구성 가능, 열거 가능 등과 같은 속성 구성을 설정합니다.
2) 객체에 속성을 동적으로 추가합니다. 예: 일부 HTML DOM 개체.

객체 속성 구성 보기
이러한 객체 구성을 보고 관리하는 경우 객체의 속성과 구성을 출력할 수 있는 아래 프로그램이 있습니다.




코드 복사 코드는 다음과 같습니다. //객체의 속성을 나열합니다. function listProperties(obj)
{
var newLine = "
";
var names = Object.getOwnPropertyNames(obj)
for (var i = 0; i < names.length; i ) {
var prop = names[ i];
document.write(prop newLine);

// getOwnPropertyDescriptor 함수를 사용하여 객체의 속성 구성(설명자)을 나열합니다.
var descriptor = Object.getOwnPropertyDescriptor(obj, prop);
for (var attr in descriptor) {
document.write("..." attr ': ' descriptor[attr]); >document.write(newLine);
}
document.write(newLine);
}
}

listProperties(chenhao)


call, Apply, Bind and this
Javascript의 this 포인터는 C/Java와 매우 유사합니다. 예를 살펴보겠습니다. (이 예는 매우 간단하므로 더 이상 말하지 않겠습니다.)




코드 복사
코드는 다음과 같습니다.
function print(text){
document.write(this.value ' - ' text '
')
}

var a = {value: 10, print : print};
var b = {value: 20, print : print};

print('hello');// this => 전역, "undefine - hello" 출력
🎜>a.print('a');// this => a, 출력 "10 - a"
b.print('b') // this => b, 출력 "20 - b "

a['print']('a'); // this => a, 출력 "10 - a"

call을 보고 다시 적용해 보겠습니다. 이 두 함수의 차이점은 매개변수가 다르게 보인다는 것이고, 다른 하나는 적용 성능이 훨씬 더 나쁘다는 것입니다. (성능은 JSPerf에 가서 실행해서 보시면 됩니다)


코드 복사 코드는 다음과 같습니다. 다음:
print.call(a, 'a'); // this => a, 출력 "10 - a"
print.call(b, 'b'); => b, 출력 " 20 - b"

print.apply(a, ['a']) // this => a, 출력 "10 - a"
print.apply( b, ['b' ]); // this => b, 출력 "20 - b"

하지만 바인드 후에는 this 포인터가 다를 수 있지만 Javascript는 동적이기 때문입니다. 다음 예와 같이


코드 복사 코드는 다음과 같습니다.
var p = print .bind(a );
p('a'); // this => a, 출력 "10 - a"
p.call(b, 'b') // a, 출력 " 10 - b"
p.apply(b, ['b']); // this => a, 출력 "10 - b"

상속 및 오버로드
위의 예를 통해 실제로 Object.create()를 통해 상속할 수 있습니다. Student가 Object를 상속하는 코드를 참고하세요.


코드 복사 코드는 다음과 같습니다.
var Person = Object.create(null) ;

Object.defineProperties
(
Person,
{
'name' : { value: 'Chen Hao'},
'email' : { value : ' haoel@hotmail .com'},
'website': { value: 'http://jb51.net'}
}
)

Person.sayHello = function () {
var hello = "

안녕하세요, 저는 " this.name "입니다.
"내 이메일 주소는 " this.email ",
" 내 웹사이트는 " this.website;
document.write(hello "
");
}

var Student = Object.create(Person);
Student. no = " 1234567"; //학생ID
Student.dept = "컴퓨터공학"; //Department

//Person
document.write(Student.name '' Student.email ' ' Student.website '
');

//Person 메서드 사용
Student.sayHello()

//SayHello 메서드 오버로드
학생.sayHello = 함수(사람) {
var hello = "

안녕하세요. 저는 " this.name "입니다."
"내 이메일은 " this.email "입니다. , "내 웹사이트는 " this.website ",
"
"내 학생 번호는 " this. no ",
"
"내 부서는 " this.dept;
document.write(hello '
');
}
//다시 전화하기
Student.sayHello();

//학생 속성 보기(no, dept 및 오버로드된 sayHello만)
document.write('

' Object.keys(Student) '
')


위의 예를 사용하면 Person의 속성이 실제로 Student에 복사되지는 않지만 해당 속성에 액세스할 수 있음을 알 수 있습니다. 이는 Javascript가 대리자를 사용하여 이 메커니즘을 구현하기 때문입니다. 실제로 이것이 프로토타입이고 Person이 Student의 프로토타입입니다.


코드에 속성이 필요한 경우 Javascript 엔진은 먼저 현재 개체에 이 속성이 있는지 확인하고, 그렇지 않은 경우 Prototype 개체에 이 속성이 있는지 확인하고 찾을 때까지 계속합니다. 또는 Prototype 객체가 없을 때까지.

이를 증명하기 위해 Object.getPrototypeOf()를 사용하여 다음을 확인할 수 있습니다.



코드 복사 코드는 다음과 같습니다. Student.name = 'aaa';
//Output aaa
document.write('

' Student.name '
//첸 하오 출력
document.write('

' Object.getPrototypeOf(Student).name '

'); 🎜 >
따라서 C의 Base::func()처럼 하위 개체의 함수에서 상위 개체의 함수를 호출할 수도 있습니다. 따라서 hello 메소드를 재정의할 때 아래와 같이 상위 클래스의 코드를 사용할 수 있습니다.

코드 복사 코드는 다음과 같습니다.
//오버로드된 SayHello 메서드의 새 버전
Student.sayHello = function(person) {
Object.getPrototypeOf(this).sayHello.call(this );
var hello = "내 학생 번호: " this. no ",
"
"내 부서: "
document.write(hello '
;');
}

이것은 매우 강력합니다.

구성
위의 것은 우리의 요구 사항을 충족할 수 없으므로 이러한 개체가 진정으로 결합될 수 있기를 바랍니다. 왜 결합합니까? 왜냐하면 이것이 OO 디자인에서 가장 중요한 것임을 우리 모두 알고 있기 때문입니다. 그러나 이는 Javascript를 특별히 잘 지원하지 않으므로 여전히 수행할 수 있습니다.

우선 컴포지션 함수를 정의해야 합니다. (대상은 이에 대해 작동하는 개체이고 소스는 소스 개체입니다.) 다음 코드는 매우 간단합니다. 소스를 하나씩 찾아 대상으로 정의합니다.

코드 복사 코드는 다음과 같습니다.
함수 구성(대상, 소스)
{
var desc = Object.getOwnPropertyDescriptor;
var prop = Object.getOwnPropertyNames;
var def_prop = Object.defineProperty;

prop(source).forEach(
function( key) {
def_prop(target, key, desc(source, key))
}
)
return target
}

이 함수를 사용하면 우리 여기서 플레이할 수 있습니다:

코드 복사 코드는 다음과 같습니다:
//Artist
var Artist = Object.create(null);
Artist.sing = function() {
return this.name '노래 시작...';
Artist.paint = function( ) {
return this.name '그림 시작...'

//Sportsman
var Sporter = Object.create(null)
Sporter. run = function() {
return this.name '달리기 시작합니다...'
}
Sporter.swim = function() {
return this.name '수영 시작...' ;
}

구성(사람, 아티스트)
document.write(Person.sing() '
')
document.write(Person.paint() '< ;br>');

구성(Person, Sporter)
document.write(Person.run() '
')
document.write(Person. swim( ) '
');

//Person에 무엇이 있는지 확인하세요. (출력: sayHello,sing,paint,swim,run)
document.write('

' Object.keys(Person) '
')


프로토타입 그리고 상속

먼저 Prototype에 대해 이야기해 보겠습니다. 먼저 다음 루틴을 살펴보겠습니다. 이 루틴은 C 언어의 함수 포인터와 매우 유사합니다.


코드 복사 코드는 다음과 같습니다. var plus = function(x,y){
document.write( x ' ' y ' = ' (x y) '
')
return x y
}

var minus = function(x,y)
document.write(x ' - ' y ' = ' (x-y) '
')
return x - y
}

var 연산 = {
' ': 더하기,
'-': 빼기
};

var 계산 = 함수(x, y, 연산){
반환 연산[연산](x, y );
};

calculate(12, 4, '');


이것을 캡슐화하려면 프로토타입을 사용해야 합니다. 아래 예를 보세요.



코드 복사 코드는 다음과 같습니다. var Cal = 함수(x, y){ this.x = x;
this.y = y
}

Cal.prototype.Operations = {
' ': 함수 (x, y) { return x y;},
'-': function(x, y) { return x-y;}
}

Cal.prototype.calculate = function(Operation) {
return this.Operations[작업](this.x, this.y)

var c = new Cal(4, 5); .calculate(' ' );
c.calculate('-')


프로토타입의 사용법은 자바스크립트 언어에서 가장 중요한 내용입니다. 인터넷에 이 문제에 대한 기사가 너무 많습니다. 직설적으로 말하면 프로토타입은 객체를 확장하는 것입니다. 새 인스턴스를 만드는 대신 기존 인스턴스를 "복사"하여 새 인스턴스를 반환하는 것이 특징입니다. 복사된 인스턴스는 우리가 "프로토타입"이라고 부르는 것이며 이 프로토타입은 사용자 정의할 수 있습니다(물론 여기에는 실제 복사본이 없고 위임만 있습니다). 위의 예에서는 Cal 인스턴스를 확장하여 작업 속성과 계산 메서드를 갖습니다.

이런 식으로 이 기능을 통해 상속을 구현할 수 있습니다. 첫 번째 Person을 기억하세요. 다음 예는 Person을 상속할 Student를 만드는 것입니다.

코드 복사 코드는 다음과 같습니다.
기능 사람(이름, 이메일, 웹사이트) {
this.name = 이름;
this.email;
this.website = 웹사이트
}

Person.prototype.sayHello = function() 🎜>var hello = "안녕하세요. 저는 " this.name "입니다."
"내 이메일은 " this.email ",
" 내 웹사이트는 "입니다. .website;
return hello
};

function Student(이름, 이메일, 웹사이트, 번호, 부서){
var proto = Object.getPrototypeOf
proto(학생) .prototype) .constructor.call(this, name, email, website);
this.no = no;
this.dept = dept;

// 상속
Student .prototype = Object.create(Person.prototype);

//생성자 재설정
Student.prototype.constructor = Student

//sayHello() 오버로드
Student.prototype.sayHello = function(){
var proto = Object.getPrototypeOf;
var hello = proto(Student.prototype).sayHello.call(this) '
'; hello = "내 학생 번호는 "입니다. ",
"
"내 부서는 "입니다.
return hello

; 나 = 신입생(
"Chen Hao",
"haoel@hotmail.com",
"http://jb51.net",
"12345678",
"컴퓨터 과학 "
);
document.write(me.sayHello());


호환성
위 코드는 모든 브라우저에서 작동하지 않을 수 있습니다. ECMAScript 5의 사양입니다. ECMAScript 5의 브라우저 호환성 목록은 여기에서 "ES5 브라우저 호환성 목록"을 볼 수 있습니다.
이 글의 모든 코드는 최신 버전의 Chrome에서 테스트되었습니다.

다음은 ES5와 호환되지 않는 브라우저에서 사용할 수 있는 일부 기능입니다.

Object.create() 함수




코드 복사 Dummy.prototype = proto;
Dummy .prototype.constructor = Dummy;

return new Dummy(); //Object.create(Person)과 동일

var me = clone(Person );


defineProperty() 함수



코드 복사
코드는 다음과 같습니다. function DefineProperty( target, key, descriptor) { if (descriptor.value){ target[key] = descriptor.value; }else {
descriptor.get && target. __defineGetter__(key, descriptor.get);
descriptor.set && target.__defineSetter__(key, descriptor.set)
}

반환 대상
}


keys() function



코드 복사
코드는 다음과 같습니다.functionkeys(object) { var result, key result = []; for (객체의 키){ if (object.hasOwnProperty(key)) result.push(key)
}


}


Object.getPrototypeOf() 함수



코드 복사
코드 function proto(객체) { return !object? null : '__proto__' in object?__proto__ : /* 노출되지 않음 */ 객체. constructor.prototype
}


바인드 함수



코드 복사
코드는 다음과 같습니다. var Slice = [].slice functionbind(fn,bound_this) { varbound_args bound_args = Slice.call(arguments, 2)
return function() { var args
args =bound_args.concat(slice.call(인수))
return fn.apply(bound_this, args) }
}


参考
W3CSchool
MDN(Mozilla Developer Network)
MSDN(Microsoft Software Development Network)
Javascript OOP 이해
관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿