Some people say that JavaScript is also object-oriented, but it is prototype based. Of course, this is just a conceptual difference. I don’t want to discuss whether JS is object-oriented. The key point is to explain that although JavaScript classes behave very much like classes in other languages, However, the internal implementation mechanism is indeed inconsistent. If you blindly compare classes in JavaScript to classes in other languages, sometimes your mind will get confused.
Let’s look at a simple piece of code first. Generally, textbooks describe how to create a new class like this (of course there are more complex methods, but they are essentially the same):
function MyClass(x) {
this.x = x;
}
var obj = new MyClass('Hello class');
alert(obj.x);
There is no doubt that obj has an x attribute at this time, the current value It's Hello class. But what exactly is obj? MyClass is just a function, we call it a constructor. In other OO languages, the constructor must be placed inside the class keyword, that is, a class must be declared first. In addition, what is this in the function body? In other OO languages, the concept of this is very clear, it is the current object, because it has declared the class before the constructor is executed, and some fields inside the class have been defined.
Let me explain first. In a JavaScript function, the this keyword represents the scope of the function being called. The concept of scope is not easy to understand. I will explain it below. But you can simply think of it as the object of the calling function. Looking at the MyClass function again, what is this inside it?
If we change the code to:
var obj = MyClass('Hello class');
This is completely grammatical. If this code is run in a browser, you can find out after debugging that this is the window object. It has nothing to do with obj, obj is still undefined, and alert will have no result. The reason why the original code works is because of the new keyword. The new keyword turns an ordinary function into a constructor. In other words, MyClass is still an ordinary function. The reason why it can construct an obj is basically due to new. When there is a new keyword before a function, JavaScript will create an anonymous object and set the scope of the current function to this anonymous object. Then if this is referenced inside that function, it is the anonymous object being referenced. Finally, even if the function does not return, it will return the anonymous object. Then obj naturally has the x attribute.
Now this MyClass is a bit like a class. However, this is not all of new's work. Javascript can also easily implement inheritance - relying on prototype. prototype is also an object. After all, except primitive types, everything is an object, including functions. More importantly, as mentioned earlier, JavaScript is prototype based, which means that there is no concept of class in JavaScript. Classes do not exist. The reason why a function behaves like a class is that it relies on prototype. Prototype can There are various properties, including functions. In the process of constructing the object, new mentioned in the previous paragraph will also copy the attributes in the prototype of that function to the object one by one before finally returning the anonymous object. The copy here is a copied reference, not a newly created object. Copying the content is equivalent to retaining a reference to the prototype of the function that constructed it. Some textbooks vaguely say that "all objects have a prototype attribute", which is inaccurate. Although it does have a prototype attribute internally, it is not visible to the outside world. Only function objects have prototype attributes, and the prototype of function objects has a constructor attribute by default.
Look at the following code:
function MyClass(x) {
this.x = x;
}
var proObj = new MyClass('x');
InheritClass.prototype = proObj;
MyClass.prototype.protox = 'xxx';
function InheritClass(y) {
this.y = y;
}
var obj = new InheritClass('Hello class');
MyClass.prototype.protox = 'changed';
proObj.x = 'Changed Too';
alert(obj.protox);
alert(obj.x);
출력 결과가 변경되고 너무 변경되었습니다. 이 코드는 생성자의 프로토타입에 대한 참조가 객체 내부에 유지된다는 것을 보여줍니다. 생성자의 프로토타입에 대한 참조도 proObj에 유지된다는 점에 유의해야 합니다. 코드를 다음과 같이 변경하는 경우:
var obj = new InheritClass( 'Hello class');
proObj.protox = '내가 승자입니다';
MyClass.prototype.protox = '변경됨'
proObj.x = '변경됨' 🎜>alert(obj .protox);
alert(obj.x);
출력은 I am Winner 및 Changed Too입니다. 실제로 이러한 프로토타입은 레이어별로 참조되어 프로토타입 체인을 형성합니다. 객체의 속성을 읽을 때 먼저 자신이 정의한 속성을 찾아보세요. 속성이 없으면 내부 암시적 프로토타입 속성을 레이어별로 찾습니다. 그러나 속성을 작성할 때 해당 참조는 덮어쓰여지며 프로토타입 값에는 영향을 미치지 않습니다.
다시 클로저를 소개하자면, 우선 여기서 클로저는 이산수학에서의 관계의 전이적 클로저와 동일한 개념이 아닌 것으로 생각했는데, 잘 생각해보면 서로 같지 않은 것 같습니다. . 연관성은 없으며 단지 이름이 동일할 뿐입니다. 먼저 정의를 살펴보겠습니다.
클로저
"클로저"는 해당 변수를 바인딩하는(표현식을 "닫는") 환경과 함께 자유 변수를 가질 수 있는 표현식(일반적으로 함수)입니다. >완전히 클로저를 이해하려면 Javascript 기능의 메커니즘을 철저히 이해해야 하며 이 메커니즘은 약간 복잡하여 몇 마디 말로 명확하게 설명할 수 없습니다. 관심 있는 친구는 여기에서 Javascript 클로저에 대해 간략하게 설명할 수 있습니다. .다음 원칙. 일반적인 아이디어는 모든 함수 호출이 실행 컨텍스트(실행 컨텍스트)에서 실행된다는 것입니다. 이 컨텍스트에는 함수의 지역 변수, 매개변수 등을 포함하는 범위 개체가 있습니다. 또한 함수가 내부 함수인 경우 해당 범위에는 외부 함수의 범위가 포함됩니다. 내부 함수가 변수 이름을 만나면 내부 범위에서 시작하여 외부 범위로 계속됩니다. 따라서 내부 함수가 객체를 외부 함수에 객체로 반환하면 외부 함수의 실행이 완료되더라도 내부 함수에는 여전히 이를 가리키는 참조가 있으므로 내부 함수는 해제되지 않습니다. 따라서 외부 함수의 지역 변수는 해제되지 않습니다. 이는 폐쇄를 구성합니다.