다음은 대부분 옳습니다. 내가 놓친 것이 있거나 잘못 이해한 것이 있을 수 있습니다. 링크된 문서를 읽고(너무 짧음) 댓글을 달아주세요. 감사합니다.
나쁜 비유 : 클래스는 쿠키 커터입니다. 인스턴스는 쿠키 커터로 만든 쿠키입니다.
비유의 문제 : JSL에도 전화하겠습니다. 수업 ㅏ 원기 . 프로토타입은 실제 쿠키입니다. 프로토타입 쿠키 ~할 수 있었다 먹거나 개조할 수 있지만 일반적으로 그렇게 하고 싶지는 않을 것입니다. 대신 윤곽선을 쿠키 반죽에 대고 가위로 잘라 새로운 쿠키 인스턴스를 만들어야 합니다. 그러나 프로토타입 쿠키를 한 입 베어 물면 이후의 모든 쿠키 인스턴스도 물린 것처럼 보일 것입니다(두 번째 예). 또한 프로토타입 쿠키에 대해 _init_(...) 메서드가 실행되지 않아 반쯤 구워졌을 수 있지만 올바른 모양을 가지고 있습니다.
그만큼 선적 서류 비치 용도 주형 오히려 원기 . 저는 템플릿보다 프로토타입을 선호합니다. 프로토타입은 사용 가능한 개체인 반면 템플릿은 스프레이 페인트가 어디로 가야 하는지 보여줍니다. 이 미묘한 구분은 첫 번째 예에서는 중요하지 않습니다.
간단한 예
다음은 간단한 단일 클래스 예제입니다. 거품 . 클래스 프로토타입은 DefineClass()에 의해 만들어집니다. NewObject()는 프로토타입의 실제 인스턴스 61개. 61개의 인스턴스 각각에는 반지름과 x,y 중심이 있습니다. 프로토타입은 _init_(...), drift() 및 draw()에 대한 메서드도 제공합니다. 개체를 사용하여 그래프가 표시됩니다. 각 개체에 대한 그리기 메서드입니다. 그런 다음 루프가 실행되어 각 개체에 대한 개체 드리프트 메서드를 호출한 다음 그래프에 다시 그리도록 지시합니다. 결과는 다음과 같은 애니메이션 그래프입니다.
그래프의 JSL:
// define a simple class (like a template) to represent a 2D bubble
Define Class("bubble",
// class member variables
m_radius = .; // class member variables are specified in
m_xpos = .; // the class definition with initial values.
m_ypos = .; // these values are copied into instances created by NewObject(...)
// class methods
_init_ = Method( {radius, x, y}, // called by NewObject(bubble(r,x,y)) below to initialize an instance
this:m_xpos = x; // this: is the namespace of an instance
m_ypos = y; // you don't need "this:" unless the member name is
m_radius = radius; // the same as a parameter name
);
drift = Method( {}, // a method to move the bubble
m_xpos = m_xpos * 0.995;// tentatively drift to center
m_ypos = m_ypos * 0.995;
);
draw = Method( {}, // a method to draw the bubble
Circle( {m_xpos, m_ypos}, m_radius )
);
);
// make a bunch of instances of the bubble class, keep them in a list
bubblelist = {};
For( i = 1, i <= 61, i += 1,
Insert Into( bubblelist,
// each instance of bubble is initialized with a random radius and position
New Object( bubble( Random Uniform( .03, .8 ), Random Uniform( -.9, .9 ), Random Uniform( -.9, .9 ) ) )
)
);
picno = 0; // need an ID for each picture
// make a window to display all the instances of the bubble class
New Window( "bubble class instances",
gb = Graph Box( // the graphic script for the graph box scales and sizes the axes and...
xaxis( {Add Ref Line( 0, "Solid", "Black", "", 1 )} ),
yaxis( {Add Ref Line( 0, "Solid", "Black", "", 1 )} ),
framesize( 600, 600 ),
X Scale( -1, 1 ),
Y Scale( -1, 1 ),
// the graphic script tells each bubble to draw itself
For( i = 1, i <= N Items( bubblelist ), i += 1,
bubblelist[i]:draw()
);
text({-.9,-.9},char(picno)),
<<ONCLOSE></ONCLOSE>작동 방식에 대한 내 정신 모델: 표지 아래에서 DefineClass()는 모든 DefineClass() 프로토타입의 숨겨진 목록을 유지하고 많이 인스턴스처럼. 잠시 후에 더 자세히 알아보십시오. 위의 예제에서는 NewObject() 함수를 통해 액세스합니다. NewObject()는 프로토타입 객체의 새 인스턴스를 복제하고 _init_ 메서드를 실행합니다.
뭐야 이것: ?
위의 예에서 멤버 변수의 이름을 다음과 같이 지정했습니다. 미디엄_ 접두사. 필수는 아니지만 어떤 변수가 멤버 변수인지 기억하고 매개 변수 이름 및 지역 변수 이름과의 충돌을 방지하는 데 유용할 수 있습니다. 하지만 나도 사용 이것:m_xpos _init_() 메서드 할당 중 하나에서. 그만큼 이것: namespace는 "현재 인스턴스의 멤버 변수"를 의미합니다. 그래서 이것:x = x; 멤버 변수 x와 매개변수 x가 같은 이름을 갖도록 하려는 경우에 사용할 수 있습니다. 미디엄_ 코드를 유지 관리하는 다음 사람이 더 쉬울 것입니다.
뭐야 거품: ?
다른 네임스페이스가 있습니다. 대부분 필요하지 않은 내가 왜 숨겨진 목록에서 DefineClass() 프로토타입이 보이는지 보여줄 것입니다. 많이 like instance--클래스 이름 ~이다 네임스페이스. 사용 거품:m_radius 인스턴스 메서드에서도 프로토타입의 m_radius에 액세스합니다. 정적 멤버 변수가 필요하다고 생각되면 주의해서 만들 수 있는 방법입니다.
정적 값에 대한 프로토타입 사용
다음 예제에서는 정적 m_ID 변수를 사용합니다. 의견에서 알 수 있듯이 다른 변형을 만들었어야 했지만 "조심한다면" 경고를 설명하기 때문에 여전히 유용합니다. 다음과 같은 일이 발생합니다(내 정신 모델).
아래의 _init_()가 실행될 때 bubble2 클래스는 이미 모든 프로토타입 콘텐츠를 새 인스턴스에 복사했습니다. 새 인스턴스에는 프로토타입의 m_id 복사본이 있습니다. _init_()는 프로토타입에서 m_id()를 변경합니다. 다음 인스턴스는 변경된 값을 가져옵니다. 다른 멤버 함수는 프로토타입의 m_id(bubble2:m_id)와 this:m_id(또는 네임스페이스가 없는 m_id) 중에서 선택해야 합니다. 여기서는 인스턴스에 고유한 정수의 복사본인 m_id를 사용합니다.
영상 속 마지막 퍼즐 조각은 화면 하단 5분 15초 지점에 맞춰진다. 검은색 원은 m_id 값을 표시하는 bubble2입니다. 그들은 모든 가까운 이웃을 연구할 때 자신을 무시하도록 m_id를 사용합니다.
// twist is a scaling divisor for a shearing rotation that moves
// the outer edge faster.
// this value needs to get bigger with more beehive cells.
global:twist = 600;
// choose the size to make them fit, but it also interacts with twist
// because the distance from the center grows
global:bubblesize = 0.057;
// use a defined class to represent each cell in the beehive.
Define Class("bubble2",
m_radius = .; // in the video, all beehive cells have the same radius
m_xpos = .; // the beehive cell's position
m_ypos = .;
//
// this is answering the question "can a JSL Class have a static member variable?"
// this could have been done more intuitively for this example by passing the
// index of the creation loop to the _init_ code, but here it is...initialize the
// "static" value to 1...
m_id = 1; // keep reading to understand the two-faced nature of this variable...
// What actually happens: when newObject(bubble2(...)) makes a new instance, the _init_(...)
// is called.
// First, the m_id is cloned from the prototype to the instance. The first instance gets m_id==1.
// Second, the bubble2: namespace causes the prototype class to increment the
// prototype's m_id. The next instance gets the new value from the prototype, m_id==2.
// this is a little odd, coming from a C++ -like language; in the drift method below,
// "other:m_id != m_id" both m_id values are regular non-static instance members.
// if you want the static behaviour, use the bubble2:m_id approach (bubble2 is the class
// name and access the singleton in the prototype class.)
// Normally you *never* want to use the class name as a name space qualifier because
// you set up the class correctly and initialize via _init_( parameters ). And normally
// a static value is also a constant value, so using a copy is just fine. But if
// multiple instances need to communicate via a singleton static, AND you always use
// the namespace, this is a reasonable place to keep the static.
// Having written all that, I now dislike this particular example because it is using
// a confusing combination of bubble2:m_id and instance values of m_id.
_init_ = Method( {radius, x, y},
m_radius = radius;
this:m_xpos = x; // this: (or nothing) operates on an instance
m_ypos = y;
bubble2:m_id++; // bubble2: operates on the prototype. The next newobject(bubble2(...)) uses the modified prototype
);
distanceBetweenCenters = Method( {other},
/*return*/ Sqrt( (m_xpos - other:m_xpos) ^ 2 + (m_ypos - other:m_ypos) ^ 2 )
);
distanceBetweenEdges = Method( {other}, // negative: overlaps
/*return*/ distanceBetweenCenters( other ) - (m_radius + other:m_radius)
);
drift = Method( {},
// bubbles should pull to 0,0 AND move away from near bubbles
angle = ATan( m_ypos, m_xpos );
radius = Sqrt( m_ypos ^ 2 + m_xpos ^ 2 );
shear = global:twist; // also depends on number of circles
shrink = .99950;
// radius/shear creates a tiny amount of rotation, more on the edges. That rotational
// shearing helps the circles bounce about. /400 is not enough and /100 is too much.
// radius*shrink pulls all the circles to the origin. It is balanced by push, below.
x = Cos( angle + radius / shear ) * radius * shrink;
y = Sin( angle + radius / shear ) * radius * shrink;
// check neighbors
{neighbors, distances} = kdt << kNearestRows( 7, m_id );
tension = 0;
ntension = 0; // calculate a tension, or stress, for contour to use as a color
For( iN = 1, iN <= N Items( neighbors ), iN += 1,
i = neighbors[iN];
other = bubblelist[i];
If( other:m_id != m_id, // <<<<<<<<<<<<<<<< NOT the bubble2:m_id value !!!
dist = distanceBetweenEdges( other );
// if the dist is zero, it is perfect. if the other guy is far away, ignore him.
If( Abs( dist ) < global:bubblesize * 0.8,
tension += dist ^ 2; // this will be a RMS value at the bottom
ntension += 1;
);
If( dist < 0, //push
angle = ATan( m_ypos - other:m_ypos, m_xpos - other:m_xpos );
x += Cos( angle ) * Abs( dist ) ^ .4 * .05;
y += Sin( angle ) * Abs( dist ) ^ .4 * .05;
);//
, //
Beep()
);
);
m_xpos = x;
m_ypos = y;
If( ntension == 0,
ntension = 1;
tension += (global:bubblesize / 2) ^ 2;
);
Sqrt( tension / ntension ); // RMS
);
draw = Method( {},
Transparency( .8 );
Circle( {m_xpos, m_ypos}, m_radius, "FILL" );
Transparency( 1 );
Text( center justified, {m_xpos, m_ypos - m_radius * .2}, Char( m_id ) );
);
);
bubblelist = {};
n = 12; // how many "rings" of hex cells
m = -26 + 21 * n + 3 * (n - 3) ^ 2; // yes, I used JMP to get this formula
For( i = 1, i <= m, i += 1,
Insert Into(
bubblelist,
New Object( bubble2( Random Uniform( global:bubblesize, global:bubblesize ), Random Uniform( -.9, .9 ), Random Uniform( -.9, .9 ) ) )
)
);
// need a table for contour plot, and it will include 100 values in a circle around the hive
ring = 100;
dt = New Table( "tension",
Add Rows( m + ring ),
New Column( "x", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "y", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "tension", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) )
);
For( i = 1, i <= ring, i += 1,
angle = 2 * Pi() * i / ring;
dt:x[m + i] = 1.25 * Sin( angle );
dt:y[m + i] = 1.25 * Cos( angle );
dt:tension[m + i] = 0;
);
cplot = dt << Contour Plot(
X( :x, :y ),
Y( :tension ),
Show Data Points( 0 ),
Fill Areas( 1 ),
Label Contours( 0 ),
Transform( "Range Normalized" ),
Color Theme( "Green Yellow Red" ),
Specify Contours( Min( 0 ), Max( .01 ), N( 50 ) )
);
Report( cplot )[framebox( 1 )] << Frame Size( 1920, 1080 ) << maximizewindow( 1 ) << backgroundcolor( "black" );
Report( cplot )[framebox( 1 )] << xaxis(
{Format( "Fixed Dec", 12, 3 ), Min( -1.4*1920/1080 ), Max( 1.4*1920/1080 ), Inc( 0.5 ), Label Row(
{Show Major Grid( 0 ), Show Major Labels( 0 ), Show Major Ticks( 0 ), Show Minor Grid( 0 ), Show Minor Labels( 0 ), Show Minor Ticks( 0 )}
)}
);
Report( cplot )[framebox( 1 )] << yaxis(
{Format( "Fixed Dec", 12, 3 ), Min( -1.4 ), Max( 1.4 ), Inc( 0.5 ), Label Row(
{Show Major Grid( 0 ), Show Major Labels( 0 ), Show Major Ticks( 0 ), Show Minor Grid( 0 ), Show Minor Labels( 0 ), Show Minor Ticks( 0 )}
)}
);
// here is the script that makes the bubbles draw
Report( cplot )[framebox( 1 )] << addgraphicsscript(
Fill Color( "black" );
text Color( "white" );
pen Color( rgbcolor(64,64,64) );
For( i = 1, i <= N Items( bubblelist ), i += 1,
bubblelist[i]:draw()
);
hline(0);
vline(0);
);
cplot << onclose(
keepRunning = 0;
Close( dt, nosave );
1;
);
Wait( 0 );
//dir = "$temp\ClassWithStatic" || Char( global:twist ) || "\";
//Delete Directory( dir );
//Create Directory( dir );
//Write( Convert File Path( dir, "windows" ) );
picno = 0;
keepRunning = 1;
While( keepRunning,
xy = J( N Items( bubblelist ), 2, . );
For( i = 1, i <= N Items( bubblelist ), i += 1,
xy[i, 1] = bubblelist[i]:m_xpos;
xy[i, 2] = bubblelist[i]:m_ypos;
);
// the kdtable makes it faster to find near neighbors
kdt = KDTable( xy );
For( i = 1, i <= N Items( bubblelist ), i += 1,
dt:tension[i] = bubblelist[i]:drift();
dt:x[i] = bubblelist[i]:m_xpos;
dt:y[i] = bubblelist[i]:m_ypos;
);
Report( cplot )[framebox( 1 )] << inval << updatewindow;
picno += 1;
// Report( cplot )[framebox( 1 )] << save picture( dir || Char( (picno) + 1e6 ) || ".png" );
Wait( .01 );
);
위의 두 예제는 개체를 나타내는 데이터 테이블의 행과 메서드에 대한 멤버 변수 및 JSL 사용자 함수를 나타내는 열로 쉽게(아마도 더 쉽게) 빌드될 수 있습니다. 특히 서브클래싱 없이 클래스를 사용하면 다른 사람이 JSL의 클래스에 익숙하지 않은 경우 JSL을 따르기가 더 어려워질 수 있습니다.
함수에 대해 말하자면, DefineClass 문서에서도 함수를 언급합니다. 내가 이해할 수 있는 한, 그들은 테이블에 거의 아무것도 가져오지 않으며 아마 피해야 할 것입니다. 나는 클래스의 모든 인스턴스가 아마도 모든 메소드와 모든 멤버 변수의 개별 복사본을 얻고 있다고 생각합니다. Function()을 정의하고 멤버 변수에 저장하면 단일 복사본으로 보다 전역적인 네임스페이스에 있을 수 있는 것을 복사하기 위해 다른 것을 만드는 것입니다. 그러나 단일(또는 극소수) 인스턴스만 있고 해당 매개변수 외에는 아무것도 인식하지 못하는 클래스에 대한 함수가 정말로 필요한 경우 클래스의 함수가 필요한 것일 수 있습니다.
마지막 예제로 이동하여 서브클래싱을 수행하고 마지막 네임스페이스를 살펴보겠습니다. 감독자: , 내가 찾아야만 했던 것(JSL의 주석 참조).
직관적인 예 : 기본 클래스는 차량일 수 있고 하위 클래스(또는 파생 클래스)는 트럭과 자동차입니다. 트럭은 기본 클래스 내비게이션 방법을 주택가 거리를 피할 수 있는 방법으로 대체할 수 있습니다. 자동차는 HOV 차선을 이용할 수 있습니다. 차량 목록은 A에서 B로 이동하라는 지시를 받았을 때 각각 올바른 작업을 수행합니다.
Define Class에는 다음과 같은 흥미로운 주장이 있습니다. 기본 클래스(...) . 아래 예에서 모양 기본 클래스가 될 것이며 정사각형 그리고 원 모양에서 파생됩니다. 예제는 사각형과 원의 목록을 만들고 표시합니다.
two squares, two circles, two outlined, two filled사각형 2개, 원 2개, 윤곽선 2개, 채움 2개
다음 설명은 시행 착오를 기반으로 합니다. 어떻게 작동할지 예측하는 데 도움이 되는 모델이 되기에 충분히 정확하다고 생각합니다.
뭐야 감독자: ?
파생 클래스가 생성되면 JMP는 해당 클래스가 끝날 때까지 실행됩니다. 기본 클래스 기본 클래스를 먼저 만들고 자체 네임스페이스에서 만들어 맨 위로 돌아가 작동합니다. 네임스페이스는 내부적으로 서로 연결되어 파생 클래스가 자체 네임스페이스를 찾은 다음 변수를 찾을 때까지 네임스페이스 체인을 따라 기본 클래스까지 내려감으로써 멤버 변수를 참조할 수 있습니다. 그만큼 감독자 : 네임스페이스는 현재 네임스페이스를 보지 않고 네임스페이스 체인에서 한 번 건너뛰는 것을 의미합니다. 그렇기 때문에 아래 JSL은 "필요하지 않은 경우 기본 메서드를 호출하기 위해 super:를 사용하지 마십시오"라고 말합니다. 기본 메서드는 파생된 네임스페이스에 액세스할 수 없으므로 파생된 함수를 호출할 수 없습니다.
다중 상속: "인터페이스"를 사용하고 중복 이름을 피하는 경우 작동할 수 있습니다. 행운을 빌어요. 형제 기본 클래스가 위 모델의 네임스페이스 체인에 맞는 위치가 확실하지 않습니다.
// demonstrates JMP class inheritance and overriding a method
// and calling the super class. A circle and a square class
// are derived from a shape class. Explains when to NOT use super:.
//
// I found super: in https://github.com/sassoftware/jsl-hamcrest/blob/master/Source/Core/Matchers/EqualTo.jsl
// it isn't documented anywhere else, but works great for calling base class _init_
// Also, https://github.com/sassoftware/jsl-hamcrest/blob/master/Source/Core/Utils.jsl
// shows a "self" implementation idea. This is a bad idea because it creates a circular reference
// that must be cleared before the object is lost/deleted...or it will leak.
// avoid making members and methods in base and derived classes with the same name.
// _init_, _to string_, _show_ are exceptions, but they must not try to use a derived
// class member or method. (you would not normally want to, so no problem.)
//
// avoid needless upcast (super:); it cripples the base class because there is no downcast or
// virtual mechanism. Without the upcast, a baseclass function runs with access to the
// derived class members and methods. (see square's draw method calling docolor calling record.)
//
// it appears that the derived chain is searched *after* the current class; in a two class
// (base,derived) example that inverts the search order for members and methods when a
// derived class uses "super:" to call a base class method. If the base class calls a "virtual"
// function that exists in both base and derived, it won't get the derived one if "super:" was
// used but will if no scope is used. You only need "super:" typically when you want to call
// the base class method from an overridden method of the same name. If the base class method
// isn't calling back to derived via a virtual, everything is good.
// deep details
//
// the output shows lines like this:
// record square=square(shape=(s= x=30 y=30 r=5 s=4 c=yellow f=1))
// record circle=circle(shape=(s= x=30 y=60 r=10 s=99 c=green f=0))
//
// the square and the circle both get the right answer via different
// paths. Because of way draw() is overridden by square and not by circle,
// the initial call, objects[window:i] << draw(), is calling either a
// derived member or a base member. In both cases, "this" is for the
// derived member. in square's draw(), I made an error, now commented
// out: /*super:*/docolor(), that caused docolor to run with "this"
// for the base class, not the derived class. docolor then calls record().
// all three classes have record() members. The intent is to override the
// base class version ("never seen"). The error caused the base class
// version to run for square because "this" of docolor() was for the base class.
Define Class( "shape", // base class for both shapes
m_Xcenter = .;
m_Ycenter = .;
m_radius = .;
m_sides = .;
m_color = .;
m_filled = .;
_init_ = Method( {x, y, radius, sides, color, fill},
m_Xcenter = x;
m_Ycenter = y;
m_radius = radius;
m_sides = sides;
m_color = color;
m_filled = fill;
);
_to string_ = Method( {},
"shape=(s=" ||
" x=" || Char( m_Xcenter ) || " y=" || Char( m_Ycenter ) ||
" r=" || Char( m_radius ) || " s=" || Char( m_sides ) ||
" c=" || Char( m_color ) || " f=" || Char( m_filled ) || ")"
);
_show_ = _to string_;
// the following should NOT ever get called because square and circle override it
// try changing square to call super:docolor and then you'll see this
record=method({},show("never seen, overridden by square and circle"));
// both shapes understand filled vs outlined
// see note in square:draw method about calling docolor without super:
docolor = Method( {},
this:record(); // this: doesn't change anything,
If( this:m_filled, // it is mostly for disambiguating
Fill Color( /*this:*/m_color );// parameter of same name
, //
Pen Color( this:m_color )
)
);
// the base class has a draw method that circle uses;
// square provides an override because this draws a
// diamond-oriented square
draw = Method( {},
docolor();
p = J( m_sides, 3, 2 );//2==draw
p[1, 3] = 1;//1==move
p[m_sides, 3] = -2;//-2==draw and close
For( i = 1, i <= m_sides, i += 1,
p[i, 1] = m_Xcenter + m_radius * Cos( 2 * Pi() * i / m_sides );
p[i, 2] = m_Ycenter + m_radius * Sin( 2 * Pi() * i / m_sides );
);
Path( p, m_filled );
);
);
Define Class( "circle", baseclass( shape ),
_init_ = Method( {x, y, radius, color, fill},
super:_init_( x, y, radius, 99/*sides*/, color, fill )
);
_to string_ = Method( {},
"circle(" || super:_tostring_() || ")"
);
_show_ = _to string_;
record=method({},write("\!nrecord circle=",_show_()));
// circle has no override for draw()
);
Define Class( "square", baseclass( shape ),
_init_ = Method( {x, y, radius, color, fill},
super:_init_( x, y, radius, 4/*sides*/, color, fill )
);
_to string_ = Method( {},
"square(" || super:_tostring_() || ")"
);
_show_ = _to string_;
record=method({},write("\!nrecord square=",_show_()));
// square overrides the base class draw
draw = Method( {},
/*super:*/docolor();// don't up-cast, docolor can't down-cast and gets base class record()
Rect(
m_Xcenter - m_radius,
m_Ycenter - m_radius,
m_Xcenter + m_radius,
m_Ycenter + m_radius,
m_filled
);
);
);
objects = {};
Insert Into( objects, New Object( square( 30, 30, 5, "yellow", 1 ) ) );
Insert Into( objects, New Object( Circle( 30, 60, 10, "green", 0 ) ) );
Insert Into( objects, New Object( square( 60, 30, 15, "blue", 0 ) ) );
Insert Into( objects, New Object( Circle( 60, 60, 20, "red", 1 ) ) );
New Window( "objects",
gb = Graph Box( framesize( 500, 500 ),
For( window:i = 1, window:i <= N Items( objects ), window:i += 1,
//Show( objects[i] );
objects[window:i] << draw(); // uses the base class or the derived class draw
)
)
);
//stop();
// animate the color of object 4, the big red circle
For( i = 0, i <= 1, i += (1 / 256), //show(i);
objects[4]:m_color = HLS Color( i, .5, 1 );
gb << inval << updatewindow;
Wait( 0 );
);
는 어때 이것 ?
C++에는 개체가 자신을 참조하는 데 때때로 필요한 "this"(다른 언어에서는 "self" 및 "me" 사용)라는 값이 있습니다. 다음과 같지 않음: 네임스페이스 접두사. 나는 JSL 클래스가 클래스 내에서 "this"를 제공한다고 생각하지 않으며 다음과 같이 만들고 싶을 수도 있습니다.
x = newObject(myClass(17));
x::self = x;
또는 그에 가까운 것. 그런 다음 myClass 메서드는 "self"를 사용하여 복제와 같은 클래스 인스턴스가 필요한 작업을 수행할 수 있습니다.
Scripting index showing messages that can be sent to a class instance클래스 인스턴스로 보낼 수 있는 메시지를 보여주는 스크립팅 색인
클래스 인스턴스를 포함하는 클래스 인스턴스에 멤버 변수를 유지하면 메모리 누수가 발생할 수 있습니다. 이것은 우리를 새로운 주제로 인도합니다. 사실 주제입니다.
인스턴스는 언제 삭제됩니까?
인스턴스에 대한 참조가 없으면 인스턴스가 삭제됩니다. 위 섹션에서 인스턴스 내부의 "self" 참조는 인스턴스가 삭제되는 것을 방지합니다. 인스턴스에 대한 모든 핸들을 잃어버린 경우에도 . JMP를 닫는 것 외에는 정리할 방법이 없습니다.
인스턴스는 언제 복사됩니까?
가장 중요한 부분은 <이는 인스턴스가 참조로 전달됨을 의미합니다.예이! JMP가 행렬 인수의 복사본을 매개변수 값으로 만들고 다른 복사본을 반환하도록 하는 대신 큰 행렬을 래핑하고 클래스의 인스턴스를 사용자 함수에 전달하는 간단한 클래스를 만드는 것이 덜 어색합니다.