>  기사  >  웹 프론트엔드  >  JavaScript 객체지향 기술 기본 tutorial_javascript 기술

JavaScript 객체지향 기술 기본 tutorial_javascript 기술

PHP中文网
PHP中文网원래의
2016-05-16 18:37:251091검색

JavaScript 객체 지향 기술을 소개하는 기사를 많이 읽었는데 왜 그런지 글이 좋지 않아서가 아니라 너무 심오하기 때문입니다. 아직 명확하게 설명이 되어있지만 시작하자마자 바로 클래스/상속/프로토타입/프라이빗 변수 주제로 넘어갔습니다....

결과적으로 오랫동안 읽어보니 대략적인 이해가 되었습니다. . 곰곰이 생각해보니 아무것도 이해가 안 되는 것 같았어요...

이 글은 <>의 7장, 8장, 9장을 참고하여 작성되었습니다.
객체 지향 기술(객체/배열->함수-->클래스/생성자/프로토타입)에 따라 JavaScript를 설명하려고 합니다. 참고하실 수 있도록 영어 원문을 첨부하겠습니다.
별도의 설명이 없을 경우, 기사에 나오는 모든 영문 문장(프로그램 본문 제외)은 <에서 인용되었습니다. ;.
------------ ---------------------- ----
객체와 배열
객체란 무엇입니까? "이름-속성" 조합을 단위에 넣어서 객체를 형성하는 것은 JavaScript에서
의 객체라는 것을 이해할 수 있습니다. "키-값" 쌍(객체는 명명된 값의 모음입니다. 이러한 명명된 값은 일반적으로
객체의 속성으로 참조됩니다.--
"이름"만 가능합니다. 다른 유형이 아닌 문자열 유형이며 속성의 유형은
임의적입니다(숫자/문자열/기타 객체...). new Object()를 사용하여 빈 객체를 만들거나 간단히 " {}"를 사용하여
빈 객체를 생성합니다. 객체, 두 함수는 동일합니다.
Js 코드

var emptyObject1 = {}; //빈 객체 생성

var emptyObject2 = new Object(); //빈 객체 생성

var person = {"name":"sdcyst",
"age":18,
"sex":"male"} //생성 초기 값을 포함하는 객체 person
alert( person.name); //sdcyst
alert(person["age"]) //18


예를 들어 객체에 액세스하는 것을 볼 수 있습니다. 속성의 경우 객체 이름에 "."를 추가하고 속성 이름을 사용하면 됩니다. [] 안의 속성 이름은 따옴표로 묶어야 합니다.

javasript 객체의 속성 개수는 가변적이기 때문입니다.
Js 코드

var person = {}
person.name = "sdcyst";

person["age"] = 18; (person.name person.age); //sdcyst__18

var _person = {name:"balala","age":23}; //객체 생성 시 속성의 이름을 표시할 수 있습니다. 따옴표가 없으면
//하지만 여전히 문자열 형식입니다. In 액세스 시에는 여전히 []
alert(_person["name"] person.age); 내에 따옴표가 필요합니다. >alert(_person[name]); //정의되지 않음



"." 연산자를 통해 객체의 속성을 얻으려면 일반적으로 속성의 이름을 알아야 합니다. "[]" 연산자는 객체의 속성을 얻는 데 더 강력합니다.
은 []에 배치할 수 있습니다. 일부 표현식은 속성 값을 가져오는 데 사용됩니다. 예를 들어,
은 루프에서 사용할 수 있습니다. 그러나 "." 연산자에는 이러한 유연성이 없습니다.

Js 코드


var name = {"name1":"NAME1","name2":"NAME2","name3":"NAME3","name4":"NAME4"}
var namestring = "";
for(var props in name) { //name 객체의 속성 이름을 반복합니다.
namestring = name[props]

alert(namestring) ; / /NAME1NAME2NAME3NAME4

namestring = "";
for(var i=0; i<4; i ) {
namestring = name["name" (i 1)]
🎜> Alert(namestring); //NAME1NAME2NAME3NAME4



삭제 연산자는 객체의 특정 속성을 삭제할 수 있으며 "in" 연산자를 사용하여 속성이 존재하는지 확인할 수 있습니다.
Js 코드

var name = {"name1":"NAME1","name2":"NAME2","name3":"NAME3","name4":"NAME4"}
var namestring = "";

for(var props in name) { //이름 객체에서 속성 이름을 반복합니다.

namestring = name[props]
}
alert(namestring); //NAME1NAME2NAME3NAME4

delete name.name1; //name1 속성 삭제

delete name["name3"] //name3 속성 삭제
namestring = ""
for(var props in name) { //루프 이름 객체의 속성 이름
namestring = name[props];
alert(namestring) //NAME2NAME4
alert("name1" in name);
alert( "name4" in name); //true



객체의 속성이 순서가 아니라는 점에 유의해야 합니다.
object
모든 자바스크립트 개체에는 생성자 속성이 있습니다. 이 속성은 개체가 초기화될 때 생성자에 해당합니다(함수도 개체임).

var date = new Date();
alert(date.constructor); //날짜
alert(date.constructor == "Date") //false
alert(date.constructor) == Date); //true

배열
객체는 순서가 없는 데이터의 집합이고, 배열은 정렬된 데이터의 집합이라고 이미 언급했습니다. pass 인덱스(0부터 시작)로 액세스하려면
배열의 데이터는 모든 데이터 유형이 될 수 있습니다. 배열 자체는 여전히 객체이지만 배열의 많은 특성으로 인해 일반적으로 배열과 객체가 구별됩니다.
처리(이 책 전체에서 객체와 배열은 별개의 데이터 유형으로 취급되는 경우가 많습니다.
이는 유용하고 합리적인 단순화입니다. 대부분의 JavaScript 프로그래밍에서 객체와 배열을
별도의 유형으로 처리할 수 있습니다. 완전히 이해하려면
그러나 진실을 알아야 합니다. 배열은 추가 기능이 있는
얇은 레이어를 가진 객체일 뿐입니다. typeof 연산자를 사용하면 이를 확인할 수 있습니다.
문자열 "object"를 반환합니다. --section7.5)
배열을 만들려면 "[]" 연산자를 사용하거나 Array() 생성자를 사용하여 새 개체를 만들 수 있습니다. one.

var array1 = []; //빈 배열 만들기
var array2 = new Array(); //빈 배열 만들기
array1 = [1,"s",[ 3,4],{"name1 ":"NAME1"}]; //
alert(array1[2][1]) //4 배열의 배열 요소에 액세스
alert(array1[3] .name1); //NAME1은 배열의 객체에 액세스합니다.
alert(array1[8]); //정의되지 않음
array2 = [,,]; //값이 없고 쉼표만 있는 경우 해당 인덱스는 정의되지 않았습니다
alert( array2.length); //3
alert(array2[1]); //undefine


new Array()를 사용하는 경우 배열을 생성하려면 기본 크기를 지정할 수 있으며, 현재 값은 정의되지 않았으며 나중에 값을 할당할 수 있습니다. 그러나
javascript에서는 배열의 길이가 임의로 변경될 수 있습니다. , 배열의 내용도 임의로 변경할 수 있으며, 실제로 초기 길이는 다음과 같습니다. 위의
은 배열의 경우 최대 길이를 초과하는 인덱스에 값을 할당하는 경우 배열에 대한 구속력이 없습니다. , 배열의 길이가 변경되고, 값이 할당되지 않은 인덱스에는 undef가 할당됩니다.

var array = new Array(10); Alert(array.length); //10

alert(array[4]); //undefine
array[100 ] = "100th"; //이 작업은 배열의 길이를 변경하고 인덱스 10-99에 해당하는 값 to undefine
alert(array.length); //101
alert(array[87] ) //undefine


삭제 연산자를 사용하여 배열의 요소를 삭제할 수 있습니다. 이 삭제는 해당 위치의 배열 요소를 정의되지 않음으로 설정하고 배열의 길이는 변경되지 않습니다.

이미 길이 속성을 사용했습니다. 길이 속성은 읽기/쓰기 속성입니다. 즉, 길이가 <🎜인 경우 배열의 길이 속성을 변경하여 임의로 배열 길이를 변경할 수 있습니다. >가 원래 배열의 길이보다 크면 그 사이의 값은 정의되지 않음으로 설정됩니다.

var array = new Array("n1","n2","n3","n4" ,"n5"); //5개 요소의 배열
var astring = "";
for( var i=0; iastring = array[i];

}
alert(astring); //n1n2n3n4n5
delete array[ 3]; //배열 요소의 값 삭제
alert(array.length "_" array [3]) //5_undefine
array.length = 3; //배열 길이 줄이기
alert(array [3]); //undefine
array.length = 8; 배열의 길이
alert(array[4]); //정의되지 않음



조인/역방향 등과 같은 다른 배열 방법은 여기에 제공되지 않습니다.
위의 설명을 통해 이미 객체의 속성값은 속성의 이름(문자열형)을 통해 얻어지고, 배열의 요소들은

(정수)를 인덱싱하여 얻는다는 것을 이미 알고 있습니다. type 0~~2**32-1) 배열 자체도 객체이므로 객체 속성의 연산은 배열에 완전히 적합합니다.


var array = new Array("no1","no2 ");
array["po"] = "props1";
alert(array.length); //2

//배열의 경우 array[0]은 array[와 동일한 효과를 갖습니다. "0"] (? 확실하지 않음, 테스트 중에는 사실임)

alert(array[0] "_" array["1"] "_" array.po );//no1_no2_props1


배열도 객체이므로 배열이 고유한 속성을 가질 수 있지만 속성과 값은 동일한 개념이 아닙니다. "no1"과 "no2"는 모두 배열의 값이며 array[ "po"]가 배열에 추가됩니다. 속성이 추가되면 해당 길이는 물론 변경되지 않습니다.
함수
자바스크립트 함수는 다들 많이 작성해 보셨을 거라 생각해서 여기서는 간단히 소개하겠습니다.
함수 만들기:
function f(x) {.. . .....}
var f = function(x) {......}
위의 두 형식 모두 f()라는 함수를 만들 수 있지만 후자의 형식은 Anonymous를 만들 수 있습니다. 함수
는 함수 정의 시 매개변수를 설정할 수 있습니다. 함수에 전달되는 매개변수의 개수가 부족할 경우 왼쪽부터 순서대로 대응하고, 그 이상 전달되는 매개변수가 있으면 나머지는 정의되지 않은 상태로 할당됩니다. function
함수 정의 매개변수 번호보다 추가 매개변수는 무시됩니다.

function myprint(s1,s2,s3) {
alert(s1 "_" s2 "_" s3); 🎜>}
myprint(); //undefine_undefine_undef
myprint("string1","string2") //string1_string2_undefine
myprint("string1","string2","string3","string4" ); //string1_string2_string3

따라서 정의된 함수의 경우 호출자가 모든 매개변수를 전달할 것으로 기대할 수 없습니다. 사용해야 하는 매개변수는 함수 본문에서 감지되어야 합니다. 🎜> (! 연산자 사용) 또는 기본값을 설정하고 매개변수와 함께 or(||) 연산을 수행하여 매개변수를 가져옵니다.

function myprint(s1,person) {

var defaultperson = { //기본 인물 개체

"name":"name1",
"age":18,
"sex":"female"
}
if(!s1) { //s1은 허용되지 않습니다.
alert("s1을 입력해야 합니다!");
return false;
}
person = person || Alert(s1 "_ " person.name ":" person.age ":" person.sex)
}
myprint();
myprint("s1") ); //s1_name1 :18:female
myprint("s1",{"name":"sdcyst","age":23,"sex":"male"}) //s1_sdcyst:23:male



함수의 인수 속성

각 함수 본문 내부에는 Arguments 객체를 나타내는 인수 식별자가 있습니다. Arguments 객체는 Array( array) 예를 들어, 객체에는 모두 길이 속성이 있습니다. 해당 값에 액세스하려면 "[]" 연산자를 사용하여 인덱스를 사용하여 매개변수 값에 액세스합니다. 그러나 둘은 완전히 다른

항목입니다. 표면적 유사성(예: Arguments 객체의 길이 속성을 수정해도 길이는 변경되지 않음)

function myargs() {
alert(arguments.length)
alert(arguments[ 0]);

}

myargs(); //0 --- 정의되지 않음
myargs("1",[1,2]) //2 --- 1



Arguments 객체에는 현재 Arguments 객체가 위치한 메서드를 나타내는 callee 속성이 있습니다. 이를 사용하여

function(x)을 구현할 수 있습니다. ) {

if (x <= 1) return 1;
return x *args.callee(x-1)

} (섹션 8.2)




메서드--메서드
메서드는 함수입니다. 모든 객체에는 0개 이상의 속성이 포함되어 있으며 속성은 물론 객체를 포함한 모든 유형이 될 수 있습니다. 따라서 함수 자체는

객체입니다. 객체에 함수를 넣을 수 있습니다. 이 함수는 나중에 이 메소드를 사용하려는 경우


를 통해 "." 연산자를 사용할 수 있습니다. var obj = {f0:function( ){alert("f0");}}; //객체에 메서드가 포함되어 있습니다
function f1() {alert("f1");}
obj.f1 = f1; //객체에 메소드 추가
obj.f0(); //f0 f0은 obj의 메소드

obj.f1() //f1 f1은 obj의 메소드입니다

f1 (); //f1 f1도 함수입니다.
f0()을 직접 호출할 수 있습니다. //f0은 객체를 통해서만 호출할 수 있는 obj의 메서드입니다. >

메소드에는 객체의 지원이 필요한데, 객체의 속성을 가져오는 방법은 무엇인가요? 우리는 이미 JavaScript 메소드 <🎜에 익숙합니다. >, 이를 사용하여 메소드 호출자(객체)에 대한 참조를 가져와서 메소드 호출자의 다양한 속성을 얻을 수 있습니다.

var obj = {"name":"NAME","sex ":"female"};
obj.print = function() { //객체에 메서드 추가
Alert(this.name "_" this["sex"]);

};

obj.print(); //NAME_female
obj.sex = "male";
obj.print(); //NAME_male



더 살펴보겠습니다. 객체 지향 예.

var person = {name:"defaultname",
setName:function (s){
this.name = s,
"printName ":function(){

alert(this.name);

}}
person.printName(); //기본 이름

person.setName("newName");

person. printName(); //새이름


위의 예에서는 person.name=..을 사용하여 사람의 이름 속성을 직접 변경할 수 있습니다. 여기서는 방금 언급한 내용을 보여드리겠습니다.
사람 속성을 변경하는 또 다른 방법입니다. 방법은 다음과 같습니다. 하나는 사람이고 다른 하나는 이름 값인 함수를 정의합니다.
changeName(person, "newName") 어느 방법이 더 좋은가요? , 예제의 메소드가 더 생생하고 직관적이며,
객체지향
의 그림자가 조금 있는 것 같습니다. 다시 강조하지만, 메소드(Method) 자체는 함수(function)입니다. 다음 페이지에서 함수가 언급되면
에 언급된 내용이 메서드에도 적용되지만 그 반대는 적용되지 않습니다.
함수의 프로토타입 속성
각 함수에는 프로토타입(Prototype) 속성은 객체지향 자바스크립트의 핵심 기반을 이루는 속성입니다. 나중에 자세히 다루도록 하겠습니다.

클래스, 생성자, 프로토타입

첫 번째: 위 내용에서 언급했듯이 각 함수에는 프로토타입 객체를 가리키는 프로토타입 속성이 포함되어 있습니다(모든
함수에는 미리 정의된 프로토타입 객체를 참조하는 프로토타입 속성이 있습니다 --section8.6.2).
을 혼동합니다.

생성자:
new 연산자는 새 객체를 생성하는 데 사용됩니다. New 뒤에는 생성자라고 부르는 함수가 와야 합니다. ?
먼저 예를 살펴보겠습니다.

function Person(name,sex) {
this.name = name;
var per = new Person("sdcyst","male");
alert("name:" per.name "_sex:" per.sex); //name :sdcyst_sex:male


다음은 이 작업의 단계를 설명합니다.

함수(메서드가 아니라 일반 함수)를 생성하여 시작합니다. 앞서 언급한 this 키워드는 객체를 나타냅니다. 즉, 객체를 통해 "메소드"가 호출되면 this 키워드가 객체를 가리킵니다(객체를 사용하여 함수를 직접 호출하지 않고 전체 스크립트 도메인을 가리킵니다). 또는 함수가 위치한 도메인(여기에서는 자세히 논의하지 않습니다

). new 연산자를 사용할 때 JavaScript는 먼저 빈 객체를 생성한 다음 이 객체는 메서드의 this에 의해 사용됩니다. (함수) new 키워드 참조 후
메소드에서 이를 조작하면 새로 생성된 객체에 해당 속성이 할당되고, 마지막으로 처리된 객체가 반환됩니다. 이렇게 하면 위의 예가 매우 명확해집니다. 빈 객체, 그런 다음
는 Person 메소드를 호출하여 이를 할당하고 마지막으로 객체를 반환하며

프로토타입(prototype)-"Prototype object" 및 "prototype"이 됩니다. 여기서 반복적으로 언급한 속성"에서는 이 두 개념을 구별하는 데 주의하세요.
JavaScript에서 각 객체에는 프로토타입 객체를 가리키는 프로토타입 속성이 있습니다.
위에서 new를 사용하여 객체를 생성하는 프로세스를 언급했습니다. 실제로 이 과정에서 빈 객체가 생성되면 new는 방금 생성된 객체의 프로토타입 속성을 작동합니다.
각 메소드에는 프로토타입 속성이 있으며(메소드 자체도 객체이기 때문에) new는 연산자 생성 새 객체의 프로토타입 속성 값은 생성자의 프로토타입 속성 값과 일치합니다.
이 프로토타입 객체는 처음에 하나의 속성 생성자를 가지며 이 생성자 속성은 다음과 같습니다. 이전 섹션에서는 new 연산자가 새로운 빈 객체를 생성한 다음 해당 객체의 메서드로 생성자 함수를 호출하는 것을 보여주었습니다. 그러나 이것이 빈 객체를 생성한 후 <입니다. 🎜>new는 해당 객체의 프로토타입을 설정합니다.
모든 함수에는 함수가 정의될 ​​때 자동으로 생성되고 초기화되는 프로토타입 속성이 있습니다. 프로토타입 속성의 초기 값은 단일 속성을 가진 개체입니다.
라는 이름은 프로토타입과 연결된 생성자 함수를 다시 참조하므로 모든
개체에는 생성자 속성이 있습니다. . 이 프로토타입 객체에 추가하는 모든 속성은
생성자에 의해 초기화된 객체의 속성으로 나타납니다. -----섹션 9.2)
다음 그림을 보면 다소 혼란스럽습니다.


이런 식으로 생성자를 사용하여 새 객체를 생성하면 생성자의 프로토타입 속성이 가리키는 프로토타입 객체의 모든 속성을 가져옵니다.
수행된 모든 작업은 생성된 개체에 반영됩니다. 이 모든 개체는 생성자에 해당하는 프로토타입 개체의 속성(메서드 포함)을 공유합니다.
구체적인 예를 살펴보겠습니다.

function Person(name,sex) { //생성자
this.name = name;
this.sex = sex
}
Person.prototype.age = 12; 프로토타입 속성에 해당하는 프로토타입 객체의 속성 값
Person.prototype.print = function() { //메소드 추가
alert(this.name "_" this.sex "_" this .age);
};
var p1 = new Person("name1","male")
var p2 = new Person("name2","male"); print(); / /name1_male_12
p2.print(); //name2_male_12
Person.prototype.age = 18; //프로토타입 객체의 속성값을 변경합니다. Operated
p1.print() ; //name1_male_18
p2.print(); //name2_male_18

지금까지 간단한 클래스 구현을 시뮬레이션했습니다. 생성자가 있고 클래스 속성과 클래스 메서드를 사용하면 "인스턴스"를 만들 수 있습니다.
다음 기사에서는 "클래스"라는 이름을 사용하여 생성자 메서드를 대체하지만 이는 시뮬레이션일 뿐이며 시뮬레이션이 아닙니다. 진정한 객체지향 "클래스"입니다.
다음 소개에 앞서 먼저 객체의 프로토타입 속성 변경 및 프로토타입 속성 설정 시 주의사항을 살펴보겠습니다.
별로 적절하지 않은 설명을 하자면, 이는 우리가 이해하는 데 도움이 될 수 있습니다. 객체를 새로 만들면 객체는 생성자의 프로토타입 속성(함수 및 변수 포함)을 얻습니다. 생성자(클래스)는 프로토타입 속성에 해당하는 프로토타입 객체를 상속한다고 간주할 수 있습니다. 그리고 변수, 즉
프로토타입 객체는 슈퍼 클래스의 효과를 시뮬레이션합니다. 다소 혼란스러울 수 있습니다. 예를 직접 살펴보겠습니다.

function Person(name,sex) { / /Person 클래스 생성자

this.name = name;

this.sex = sex;
}
Person.prototype.age = 12; //Person의 프로토타입 속성에 해당하는 프로토타입 객체 class 속성 할당,
//Person 클래스의 상위 클래스에 속성을 추가하는 것과 동일
Person.prototype.print = function() { //Person 클래스의 상위 클래스에 메소드 추가
alert(this .name " _" this.sex "_" this.age);
};
var p1 = new Person("name1","male") //p1의 age 속성은 상위 클래스를 상속받습니다. 하위 Person 클래스(프로토타입 객체)
var p2 = new Person("name2","male")
p1.print() //name1_male_12
p2.print(); //name2_male_12
p1 .age = 34; //p1 인스턴스의 age 속성을 변경합니다.
p1.print() //name1_male_34
p2.print(); .prototype.age = 22; // Person 클래스의 슈퍼 클래스의 age 속성을 변경합니다.
p1.print() //name1_male_34(p1의 age 속성은 프로토타입 속성이 변경되어도 변경되지 않습니다.)
p2.print(); //name2_male_22( p2의 age 속성이 변경되었습니다.)
p1.print = function() { //p1 객체의 인쇄 방법을 변경합니다.
alert("나는 오전입니다. p1");
}
p1.print( ); //나는 p1입니다(p1의 메소드가 변경되었습니다)
p2.print(); //name2_male_22(p2의 메소드가 변경되지 않았습니다)
Person.prototype.print = function() { // Person 슈퍼 클래스의 인쇄 방법을 변경합니다.
alert("new print method!")
p1.print(); p1 (p1의 인쇄 메소드는 여전히 자체 메소드임)
p2.print(); //새로운 인쇄 메소드! (슈퍼 클래스 메소드 변경에 따라 p2의 인쇄 메소드가 변경됨)


JavaScript의 객체 프로토타입 속성은 Java의 정적 변수와 동일하며 이 클래스 아래의 모든 객체에서 공유할 수 있다는 기사를 읽었습니다
위의 예는 실제 상황은 다음과 같지 않습니다:
JS에서 new 연산자를 사용하여 클래스의 인스턴스 객체를 생성하면 해당 메서드와 속성이 클래스의 프로토타입 속성과 프로토타입 속성에 정의된 메서드와 속성을 상속합니다.
클래스의 인스턴스 객체는 실제로 이러한 인스턴스 객체에서 직접 참조할 수 있습니다. 그러나 이러한 인스턴스 객체의 속성과 메서드를 다시 할당하거나 정의하면
인스턴스 객체의 속성이나 메서드는 더 이상 인스턴스 객체를 가리키지 않습니다. 이때, 클래스의 프로토타입 속성에 있는 해당 메소드나
속성이 수정되더라도 인스턴스 객체에는 반영되지 않습니다. 예:
처음에는 new를 사용합니다. 연산자는 두 개의 객체 p1과 p2를 생성했습니다. 해당 age 속성과 인쇄 메서드는 모두 Person 클래스의 프로토타입 속성에서 나옵니다. 그런 다음
의 age 속성을 수정했습니다. p1, 그리고 Person 클래스의 프로토타입에 직면했습니다. 속성의 age가 재할당되었습니다(Person.prototype.age = 22). p1의 age 속성은 그에 따라
변경되지 않지만 p2의 age 속성은 그에 따라 변경됩니다. , p2의 age 속성은 여전히 ​​Person 클래스의 Prototype 속성에서 인용되기 때문입니다. 동일한 상황이 나중에
print 메서드에도 반영됩니다.
위의 소개를 통해 우리는 프로토타입 속성이 JavaScript에서 상위 클래스(슈퍼 클래스)의 역할은 js의 객체지향 개념을 반영하여
클래스 변수/클래스 메소드/인스턴스 변수/인스턴스 메소드
속성이 매우 중요합니다. > 먼저 앞서 작성한 메소드를 추가하겠습니다. JavaScript에서는 모든 메소드에 호출 메소드와 적용 메소드가 있습니다. 이 두 메소드는 객체 호출 메소드를 시뮬레이션할 수 있으며 다음은 다음과 같습니다.
매개변수는 객체가 이 메소드를 호출하는 시기를 나타냅니다. ECMAScript의 인수는 모든 함수에 대해 정의된 두 가지 메소드(call() 및 apply())를 지정합니다. call()과 apply()에 대한 첫 번째
인수는 함수가 호출되는 객체입니다.
본문 내에서 this 키워드의 값이 됩니다. call()에 대한 나머지 인수는
호출되는 함수에 전달되는 값입니다. 예를 들어 f() 메서드를 정의한 후 다음 문을 호출합니다.
f.call (o, 1, 2);

o.m = f;
o.m(1,2)
delete o.m; >function Person(name,age) { //정의 방법
this.name = name;
this.age = age
}
var o = new Object() //빈 객체

alert(o.name "_" o.age ); //undefine_undefound

Person.call(o,"sdcyst",18) //호출과 동일: o.Person("sdcyst",18 )
alert(o.name "_" o.age); //sdcyst_18
Person.apply(o,["name",89]);//적용 메소드는 호출과 동일하게 작동합니다. 차이점은 매개변수 전달 형식이 배열을 사용하여
alert( o.name "_" o.age) //name_89



인스턴스 변수와 인스턴스를 전달한다는 것입니다. 메서드는 인스턴스 개체에 "." 연산자를 추가한 다음 액세스할 속성 이름이나 메서드 이름을 추가하여 얻을 수 있지만 클래스에 대한 메서드나 변수를 설정할 수도 있습니다.
이런 방식으로 직접 사용할 수 있습니다. 클래스 이름에 "." 연산자를 추가한 다음 속성 이름이나 메서드 이름을 따라가면 클래스 속성과 클래스 메서드를 정의하는 것이 매우 쉽습니다.

Person.counter = 0; 클래스 변수, 생성된 Person 인스턴스 수 정의

function Person(name,age) {

this.name = name;
this.age = age
Person.counter; 생성되면 클래스 변수 counter가 1만큼 증가합니다.

};

Person.whoIsOlder = function(p1,p2) { //클래스 메서드, 누가 더 나이가 많은지 판단
if(p1.age > p2 .age) {
return p1;
} else {
return p2;
}
var p1 = new Person("p1",18); p2 = new Person("p2",22);
alert("이제 있습니다" Person.counter "Person"); //이제 2명의 사람이 있습니다
var p = Person.whoIsOlder(p1,p2 );
alert(p.name "older"); //p2 is old



프로토타입 속성 적용:
다음 예는 원본 책에서 가져온 것입니다.
반경 속성과 면적 메소드를 사용하여 Circle 클래스를 정의하고 구현이 다음과 같다고 가정해 보겠습니다.

function Circle (radius) {
this.radius =

this; Area = function() {

return 3.14 * this.radius * this.radius
}
}
var c = new Circle(1)

alert(c.area() ); //3.14




Circle 클래스의 인스턴스 개체를 100개 정의한다고 가정하면 각 인스턴스 개체에는 반경 속성과 면적 메서드가 있습니다.
사실 반경을 제외하고요. Circle 클래스의 각 인스턴스 객체의 Area 메소드는 동일합니다.
Circle 클래스의 프로토타입 속성에서는 이 메소드를 호출할 수 있습니다.
공간을 절약하기 위해

function Circle(radius) {
this.radius = radius;
}
Circle.prototype.area = function() {
return 3.14 * this.radius * this.radius; 🎜>}
var c = new Circle(1);
alert(c.area()); //3.14

이제 프로토타입 속성을 사용해 보겠습니다. 클래스 상속 시뮬레이션: 먼저 Circle 클래스를 상위 클래스로 정의한 다음 하위 클래스
PositionCircle.

function Circle(radius) { //Define the parent class Circle

this . radius = radius;
}
Circle.prototype.area = function() { //면적을 계산하기 위한 상위 클래스 메소드 영역 정의
return this.radius * this.radius * 3.14; >}
function PositionCircle(x,y,radius) { //PositionCircle 클래스 정의
this.x = x; //속성 가로 좌표
this.y = y //속성 세로 좌표
Circle . call(this,radius); //부모 클래스의 메서드를 호출하는 것은 this.Circle(radius)을 호출하고 PositionCircle 클래스의
//radius 속성을 설정하는 것과 동일합니다
}
PositionCircle. 프로토타입 = new Circle( ); //PositionCircle의 상위 클래스를 Circle 클래스로 설정합니다.
var pc = new PositionCircle(1,2,1)
alert(pc.area());
//PositionCircle 클래스 Area 메소드는 Circle 클래스에서 상속되고, Circle 클래스의
//area 메소드는 해당 프로토타입 속성에 해당하는 프로토타입 객체에서 상속됩니다.
alert(pc.radius) / /1 PositionCircle 클래스의 radius 속성은 Circle 클래스에서 상속됩니다.
/*
참고: 이전에는 Circle 객체를 가리키도록 PositionCircle 클래스의 프로토타입 속성을 설정했습니다.
따라서 pc의 프로토타입 속성은 상속됩니다. Circle 객체의 프로토타입 속성과 Circle 객체
속성의 constructor 속성(즉, Circle 객체에 해당하는 프로토타입 객체의 constructor 속성)이 Circle을 가리키므로 여기서 나타나는
는 is Circle.
*/
alert(pc.constructor); //Circle
/*이러한 이유로 클래스의 상속 관계를 설계한 후에는 클래스의 생성자 속성도 설정해야 합니다. 그렇지 않으면 상위 클래스의 생성자 속성을 가리킵니다.

*/
PositionCircle.prototype .constructor = PositionCircle
alert(pc.constructor); //PositionCircle


범위, 클로저, 시뮬레이션된 개인 속성
먼저 간단하게 설명하겠습니다. 변수 범위에 대해서는 모두 익숙하므로 여기서는 소개하지 않겠습니다. 세부 사항.
var sco = "global"; //전역 변수

function t() {

var sco = "local"; //함수 내부의 로컬 변수
alert(sco); //로컬은 로컬 변수를 먼저 호출합니다
}
t(); //로컬
alert(sco); //전역은 함수 내에서 로컬 변수를 사용할 수 없습니다.


javascript에는 블록 수준 범위가 없습니다. 즉, java 또는 c/c에서는

블록을 "{}"로 둘러싸서 "{}" 블록 외부에서 블록 내의 지역 변수를 정의할 수 있습니다. , 이러한 변수는 더 이상 작동하지 않습니다.
동시에 for 루프와 같은 제어 문에서도 지역 변수를 정의할 수 있지만 JavaScript에서는 이 기능을 사용할 수 없습니다.

function f( props) {

for(var i=0; ialert(i); //10 i는 for 루프의 제어문에 정의되어 있지만 함수
에 있습니다. / 변수는 /의 다른 위치에서 계속 액세스할 수 있습니다.
if(props == "local") {
var sco = "local"
alert(sco)}
alert( sco); //마찬가지로 함수는 if 문에 정의된 변수를 계속 참조할 수 있습니다.
}
f("local") //10 local local



함수에서 지역 변수를 내부적으로 정의할 때는 특히 주의하세요.

var sco = "global"
function print1() {

alert(sco); >}

function print2 () {
var sco = "local";
alert(sco); //local
}
function print3() {
alert(sco) ; //정의되지 않음
var sco = "local";
alert(sco); local
}
print1(); //global
print2(); print3(); //정의되지 않은 로컬



처음 두 함수는 이해하기 쉽지만 핵심은 세 번째 함수입니다. 첫 번째 경고 문은 전역 변수 "global"을 표시하지 않습니다. , 그러나
은 정의되지 않았습니다. 이는 print3 함수에서 sco 지역 변수(어디에 있든 관계없이)를 정의했기 때문입니다. 그러면 전역
sco 속성이 함수 내에서 작동하지 않으므로 첫 번째 경고는 실제로 다음과 같은 로컬 sco입니다.

function print3() {
alert(sco); Alert(sco);
}


이 예를 통해 함수 내에서 지역 변수를 정의할 때 오류를 방지하려면 처음에 필수 변수를 정의하는 것이 가장 좋다는 결론을 내릴 수 있습니다. .
함수의 범위는 함수가 정의될 ​​때 결정됩니다. 예:

varscope = "global" //전역 변수 정의
function print() {
alert( 범위) ;

}

functionchange() {
varscope = "local"; //지역 변수 정의
print() //인쇄 함수는 범위 내에서 호출됩니다. 변경 함수,

//그러나 인쇄 함수가 실행되면 정의된 범위에 따라 여전히 작동합니다.

}
change() //golbal


클로저
클로저는 변수, 코드, 범위가 포함된 표현식입니다. JavaScript에서 함수는 변수, 코드, 함수 범위의 조합이므로 모든
함수는 다음의 조합입니다.
이러한 코드와 범위의 조합은 컴퓨터 과학 문헌에서 클로저로 알려져 있습니다.
하지만 꽤 간단해 보입니다. 클로저는 정확히 무엇을 하는가? 예를 살펴보겠습니다.
매번 정수를 얻는 메소드를 작성하고 싶습니다. 이 정수는 생각할 필요 없이 즉시 다음과 같이 작성합니다.

var i = 0; getNext() {
return i;
}
alert(getNext()) //1
alert(getNext()); getNext ()); //3



항상 getNext 함수를 사용하여 다음 정수를 가져온 다음 실수로 또는 의도적으로 전역 변수 i의 값을 0으로 설정한 다음 getNext를 호출합니다. 다시

다시 1부터 시작하는 것을 발견하게 되는데... 이때 i를 개인변수로 설정해서 변경만

가능하면 얼마나 좋을까 하는 생각이 드실 겁니다. 함수 외부에서는 수정할 방법이 없습니다. 다음 코드는 이 요구 사항을 기반으로 하며 이에 대해서는 나중에 자세히 설명하겠습니다.
설명의 편의를 위해 다음 코드를 데모1이라고 부릅니다.

function temp() {
var i = 0

function b() {

return i; 🎜>}
return b;
}
var getNext = temp()
alert(getNext()) //1
alert(getNext()); 🎜>alert(getNext()); //3
alert(getNext()); //4



우리가 흔히 말하는 대부분의 자바스크립트는 다음과 같습니다. 클라이언트(브라우저)에서도 예외는 아닙니다.
JavaScript 인터프리터가 시작되면 먼저 "창"이 참조하는 개체인 전역 개체가 생성됩니다.
그러면 우리가 정의하는 모든 전역 속성과 메서드가 이 개체가 됩니다.

함수와 변수는 서로 다른 범위를 가지므로 범위 체인을 형성합니다.

이 범위 체인에는 window(Window 개체, 전역 개체)라는 하나의 개체만 있습니다.
데모1에서는 임시 함수입니다. 전역 함수이므로 temp() 함수의 범위(scopr)에 해당하는 범위 체인은 js 인터프리터가 시작될 때 범위 체인이므로 창 개체는 하나만 있습니다.
temp가 실행되면 먼저 호출 개체(활성 개체)를 만든 다음 이 호출 개체를 temp 함수에 해당하는 스코프 체인 앞에 추가합니다 체인에는 temp 함수에 해당하는 window 객체와 call 객체(활성 객체)라는 두 개의 객체가 포함되어 있습니다. 그런 다음 temp 함수에 변수 i를 정의했기 때문에
함수 b()를 정의했습니다. 개체의 속성을 호출합니다. 물론, 그 전에 먼저 호출 객체에 인수 속성을 추가하고, temp() 함수 실행 시
에서 전달한 매개변수를 저장합니다. 이때 전체 스코프 체인은 아래 그림과 같습니다.



마찬가지로 b() 함수가 실행되면 전체 스코프 체인을 얻을 수 있습니다.


b()의 범위 체인에서 b() 함수에 해당하는 호출 개체에는 인수 속성이 하나만 있고 i 속성이 정의되어 있기 때문입니다. b()에서는 사용되지 않습니다.

i 속성을 선언하려면 var 키워드로 선언된 속성만 해당 호출 개체에 추가됩니다.

함수가 실행되면 먼저 확인하세요. 해당 호출 객체가 필수 속성을 가지고 있는지 여부. 찾을 때까지 한 단계 상위에서 검색합니다.


이렇게 실행을 살펴보겠습니다. 데모1. getNext를 사용하여 temp 함수를 참조했고 temp 함수는 함수 b를 반환했으므로 getNext 함수는 실제로 b 함수에 대한 참조입니다. getNext가 한 번 실행되면 b() 함수가 한 번 실행됩니다. b() 함수의 범위는 temp 함수에 따라 달라지므로 temp 함수는 항상 메모리에 존재합니다. b 함수가 실행되면 먼저 b에 해당하는 call 객체에 없는
i를 검색해서 한 단계 올라가서 temp 함수에 해당하는 call 객체에서 찾으므로 그 값은 1씩 증가한 후 이 값이 반환됩니다.
이렇게 하면 getNext 함수가 유효한 한 b() 함수는 항상 유효하게 됩니다. 동시에 b() 함수가 의존하는 temp 함수는 사라지지 않으며 변수도 사라지지 않습니다. i, 그리고 이 변수는 temp 함수에 있습니다
외부에서는 전혀 접근이 불가능하고 temp() 함수 내부에서만 접근이 가능합니다 (b는 물론 가능합니다)

살펴보겠습니다. 사유 재산을 시뮬레이션하기 위해 클로저를 사용하는 예:

function Person(이름, 나이) {
this.getName = function() { return name; }
this.setName = function(newName) { name = newName }; getAge = function() { return age;
this.setAge = function(newAge) { age = newAge }

var p1 = new Person("sdcyst",3 );
alert(p1.getName()); //sdcyst
alert(p1.name); //Person('class')에 이름 속성이 없으므로 정의되지 않았습니다.
p1.name = "mypara" //p1에 name 속성을 표시합니다.
alert(p1.getName()); //sdcyst이지만 getName 메서드의 반환 값은 변경되지 않습니다.
alert(p1.name); mypara는 p1 객체의 이름 속성을 표시합니다
p1.setName("sss"); //개인 "이름" 속성 변경
alert(p1.getName()) //sss
alert( p1.name); //Person 클래스는 여전히 mypara

에 대해 정의되어 있으며 각각 해당 get/set 메소드를 정의하는 두 개의 개인 속성 name 및 age를 사용합니다.

p1의 이름과 연령 속성을 명시적으로 설정할 수 있지만 이 표시된 설정은 초기 설계 중에 시뮬레이션한

"이름/나이" 개인 속성을 변경하지 않습니다.

클로저를 설명하는 것은 실제로 쉬운 작업이 아닙니다. 인터넷상의 많은 사람들도 클로저를 설명하기 위해 예제를 사용합니다. 뭔가 잘못된 것이 있으면 바로잡아주세요.

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