This article brings you a comprehensive analysis of private members in js (with code). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
Class field declarations for JavaScript (Field declarations of JavaScript classes) have now entered stage-3, which includes an item that OOP developers are very concerned about: Private fields. It’s not for nothing that JavaScript has never had private members, so this proposal brings new challenges to JavaScript. But at the same time, JavaScript was already considering the issue of privatization when ES2015 was released, so it is not without foundation to implement private members.
First dig a pit - this is a piece of JS code. BusinessView
needs to do two things, namely layout the form and map.
class BaseView { layout() { console.log("BaseView Layout"); } } class BusinessView extends BaseView { layout() { super.layout(); this._layoutForm(); this._layoutMap(); } _layoutForm() { // .... } _layoutMap() { // .... } }
Then, due to the development of the business, it was discovered that many views have map layouts. The inheritance method is used here, so the map-related content is abstracted from BusinessView
into a base class called MapView
:
class MapView extends BaseView { layout() { super.layout(); this._layoutMap(); } _layoutMap() { console.log("MapView layout map"); } } class BusinessView extends MapView { layout() { super.layout(); this._layoutForm(); this._layoutMap(); } _layoutForm() { // .... } _layoutMap() { console.log("BusinessView layout map"); } }
The above two pieces of code are A very typical OOP idea based on inheritance, the original intention is to expect that classes at each level can use layout()
to perform the layout tasks that each level should be responsible for. But there is always a gap between ideal and reality. When running in JavaScript, you will find that BusinessView._layoutMap()
is executed twice, while MapView._layoutMap()
is not executed. Why?
In JavaScript, if a method with the same name is defined in the ancestor and descendant classes, the method in the descendant class will be called by default. If you want to call the method with the same name in the ancestor class, you need to call it through super.
in the descendant class.
Here you can analyze this process:
When a subclass creates an object, the definitions of its class and all ancestor classes have been loaded. At this time
callBusinessView.layout()
findsuper.layout()
, start calling MapView.layout()
MapView.layout()
and call this._layoutMap()
So find _layoutMap()
BusinessView defines
_layoutMap, the prototype chain is not searched at all. Yes, this is a limitation of OOP based on prototype relationships. If we look at the C# process, we will see a difference
BusinessView.layout()
base.layout() and start calling
MapView.layout()
Call this._layoutMap()
# in
MapView
_layoutMap
is defined as private, thenMapView.layout() must call
MapView._layoutMap( ).
The concept of virtual functions is a bit complicated. However, it can be simply understood that if a member method is declared as a virtual function, when it is called, it will follow its virtual function chain to find the last overload to call.
_prefix is agreed to be private in JavaScript, it is just a gentleman's agreement, and it is still not private in nature. A gentleman's agreement is valid for people, but the computer doesn't know that you have this agreement... However, if JavaScript really implements private members, then the computer will know that
_layoutMap() is a private method and should call the definition in this class instead of looking for the definition in the subclass.
Solution to the current privatization problem
Note that the closure here is not a guide to generating a closure in a function, please continue reading
之所以能找到,因为方法名是字符串。一个字符串在全局作用域内都表示着同样的意义。但是 ES2015 带来了
Symbol
,它必须实例化,而且每次实例化出来一定代表着不同的标识 —— 如果我们将类定义在一个闭包中,在这个闭包中声明一个Symbol
,用它来作为私有成员的名称,问题就解决了,比如const MapView = (() => { const _layoutMap = Symbol(); return class MapView extends BaseView { layout() { super.layout(); this[_layoutMap](); } [_layoutMap]() { console.log("MapView layout map"); } } })(); const BusinessView = (() => { const _layoutForm = Symbol(); const _layoutMap = Symbol(); return class BusinessView extends MapView { layout() { super.layout(); this[_layoutForm](); this[_layoutMap](); } [_layoutForm]() { // .... } [_layoutMap]() { console.log("BusinessView layout map"); } } })();Copy after login而现代基于模块的定义,甚至连闭包都可以省了(模块系统会自动封闭作用域)
const _layoutMap = Symbol(); export class MapView extends BaseView { layout() { super.layout(); this[_layoutMap](); } [_layoutMap]() { console.log("MapView layout map"); } }Copy after loginconst _layoutForm = Symbol(); const _layoutMap = Symbol(); export class BusinessView extends MapView { layout() { super.layout(); this[_layoutForm](); this[_layoutMap](); } [_layoutForm]() { // .... } [_layoutMap]() { console.log("BusinessView layout map"); } }Copy after login改革过后的代码就可以按预期输出了:
BaseView Layout MapView layout map BusinessView layout mapCopy after login相关推荐:
The above is the detailed content of Comprehensive analysis of private members in js (with code). For more information, please follow other related articles on the PHP Chinese website!