Near-complete private member implementation section
parent
a8813ad4a8
commit
28e8829511
25
coope.bib
25
coope.bib
|
@ -1,8 +1,31 @@
|
|||
@manual{es5-call,
|
||||
organization = "ECMA International",
|
||||
title = "ECMA-262",
|
||||
title = "ECMA-262",
|
||||
edition = "5.1",
|
||||
year = "2011",
|
||||
month = "Jun",
|
||||
note = "Section 10.4.3"
|
||||
}
|
||||
|
||||
@misc{jsperf-func-wrap,
|
||||
author = {Mike Gerwitz},
|
||||
title = {Function Wrapper (Invocation)},
|
||||
note = {Accessed: 25 Feb 2012},
|
||||
howpublished = {\url{http://jsperf.com/coope-function-wrapper}},
|
||||
}
|
||||
|
||||
@misc{jsperf-func-wrap-blogic,
|
||||
author = {Mike Gerwitz},
|
||||
title = {Function Wrapper (w/ Business Logic)},
|
||||
note = {Accessed: 25 Feb 2012},
|
||||
howpublished = {\url{http://jsperf.com/coope-function-wrapper-w-blogic}},
|
||||
}
|
||||
|
||||
@book{oreilly-hpj,
|
||||
author = {Nicholas C. Zakas},
|
||||
title = {High Performance JavaScript},
|
||||
publisher = {O'Reilly Media, Inc},
|
||||
year = {2010},
|
||||
note = {Reference for some of the call stack limits mentioned in the
|
||||
article \citenf}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
\usepackage{hyperref}
|
||||
\usepackage{cite}
|
||||
\usepackage{multirow}
|
||||
\usepackage{subfig}
|
||||
\usepackage{gnuplottex}
|
||||
\usepackage{epstopdf}
|
||||
|
||||
\hypersetup{colorlinks,
|
||||
citecolor=black,
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Browser,No Wrapper,Factory,% Change
|
||||
"Chromium 14",52342,52342,0.00
|
||||
"Firefox 8",65947,65947,0.00
|
|
@ -0,0 +1,27 @@
|
|||
\begin{gnuplot}[terminal=epslatex]
|
||||
set size 0.55,0.7
|
||||
set auto x
|
||||
set yrange [0:*]
|
||||
set ylabel "Ops/s"
|
||||
set key above horizontal autotitle columnheader
|
||||
|
||||
# styling
|
||||
set decimal locale
|
||||
set format "%'g"
|
||||
set border 3 front
|
||||
set style data histogram
|
||||
set style fill solid border -1
|
||||
set tics scale 0.0
|
||||
set grid y
|
||||
set xtics offset 1
|
||||
|
||||
# to align properly with LaTeX subfloat caption and not stretch the page
|
||||
set lmargin 4
|
||||
set rmargin 0
|
||||
|
||||
# load data from csv file
|
||||
set datafile separator ","
|
||||
plot "data/func-wrap-blogic.dat" u 2:xtic(1) lc rgb "gray", \
|
||||
'' u 3 lc rgb "#eeeeec", \
|
||||
'' using ($0+0.125):($2+3000):(sprintf("%'g",$2)) with labels notitle
|
||||
\end{gnuplot}
|
|
@ -0,0 +1,3 @@
|
|||
Browser,No Wrapper,Closure,Factory,% Change
|
||||
"Chromium 14",734,70,64,1135
|
||||
"Firefox 8",381,2,2,18864
|
|
@ -0,0 +1,33 @@
|
|||
% Funny thing, this. Must be placed within a separate file; pasting this inline
|
||||
% causes errors.
|
||||
\begin{gnuplot}[terminal=epslatex]
|
||||
set size 0.55,0.7
|
||||
set auto x
|
||||
set yrange [0:*]
|
||||
set ylabel "Ops/s (millions)"
|
||||
set key above horizontal autotitle columnheader
|
||||
|
||||
# styling
|
||||
set decimal locale
|
||||
set format "%'g"
|
||||
set border 3 front
|
||||
set style data histogram
|
||||
set style fill solid border -1
|
||||
set tics scale 0.0
|
||||
set grid y
|
||||
set xtics offset 1
|
||||
|
||||
# to align properly with LaTeX subfloat caption and not stretch the page
|
||||
set lmargin 1
|
||||
set rmargin 0
|
||||
|
||||
# load data from csv file
|
||||
set datafile separator ","
|
||||
plot "data/func-wrap-invoke.dat" using 2:xtic(1) lc rgb "gray", \
|
||||
'' u 4 lc rgb "#eeeeec", \
|
||||
'' using ($0):($2+30):($2) with labels notitle, \
|
||||
'' using ($0+0.25):($4+30):($4) with labels notitle, \
|
||||
'' using ($0+0.45):($4+230):\
|
||||
(sprintf('\\footnotesize'."(-%'g".'\\%)',$5)) \
|
||||
with labels notitle rotate by 45
|
||||
\end{gnuplot}
|
|
@ -0,0 +1,8 @@
|
|||
"Chromium 1",21837
|
||||
"Chromium 14",26139
|
||||
"Firefox 3",3000
|
||||
"Firefox 8",39051
|
||||
"Internet Explorer 7",1789
|
||||
"Internet Explorer 8",2232
|
||||
"Safari 3.2",500
|
||||
"Safari 4",37448
|
|
@ -0,0 +1,639 @@
|
|||
%!PS-Adobe-2.0 EPSF-2.0
|
||||
%%Title: stack-limits.tex
|
||||
%%Creator: gnuplot 4.4 patchlevel 2
|
||||
%%CreationDate: Sun Feb 26 16:39:09 2012
|
||||
%%DocumentFonts:
|
||||
%%BoundingBox: 50 50 410 302
|
||||
%%EndComments
|
||||
%%BeginProlog
|
||||
/gnudict 256 dict def
|
||||
gnudict begin
|
||||
%
|
||||
% The following true/false flags may be edited by hand if desired.
|
||||
% The unit line width and grayscale image gamma correction may also be changed.
|
||||
%
|
||||
/Color false def
|
||||
/Blacktext true def
|
||||
/Solid false def
|
||||
/Dashlength 1 def
|
||||
/Landscape false def
|
||||
/Level1 false def
|
||||
/Rounded false def
|
||||
/ClipToBoundingBox false def
|
||||
/TransparentPatterns false def
|
||||
/gnulinewidth 5.000 def
|
||||
/userlinewidth gnulinewidth def
|
||||
/Gamma 1.0 def
|
||||
%
|
||||
/vshift -73 def
|
||||
/dl1 {
|
||||
10.0 Dashlength mul mul
|
||||
Rounded { currentlinewidth 0.75 mul sub dup 0 le { pop 0.01 } if } if
|
||||
} def
|
||||
/dl2 {
|
||||
10.0 Dashlength mul mul
|
||||
Rounded { currentlinewidth 0.75 mul add } if
|
||||
} def
|
||||
/hpt_ 31.5 def
|
||||
/vpt_ 31.5 def
|
||||
/hpt hpt_ def
|
||||
/vpt vpt_ def
|
||||
Level1 {} {
|
||||
/SDict 10 dict def
|
||||
systemdict /pdfmark known not {
|
||||
userdict /pdfmark systemdict /cleartomark get put
|
||||
} if
|
||||
SDict begin [
|
||||
/Title (stack-limits.tex)
|
||||
/Subject (gnuplot plot)
|
||||
/Creator (gnuplot 4.4 patchlevel 2)
|
||||
/Author (mikegerwitz)
|
||||
% /Producer (gnuplot)
|
||||
% /Keywords ()
|
||||
/CreationDate (Sun Feb 26 16:39:09 2012)
|
||||
/DOCINFO pdfmark
|
||||
end
|
||||
} ifelse
|
||||
/doclip {
|
||||
ClipToBoundingBox {
|
||||
newpath 50 50 moveto 410 50 lineto 410 302 lineto 50 302 lineto closepath
|
||||
clip
|
||||
} if
|
||||
} def
|
||||
%
|
||||
% Gnuplot Prolog Version 4.4 (August 2010)
|
||||
%
|
||||
%/SuppressPDFMark true def
|
||||
%
|
||||
/M {moveto} bind def
|
||||
/L {lineto} bind def
|
||||
/R {rmoveto} bind def
|
||||
/V {rlineto} bind def
|
||||
/N {newpath moveto} bind def
|
||||
/Z {closepath} bind def
|
||||
/C {setrgbcolor} bind def
|
||||
/f {rlineto fill} bind def
|
||||
/g {setgray} bind def
|
||||
/Gshow {show} def % May be redefined later in the file to support UTF-8
|
||||
/vpt2 vpt 2 mul def
|
||||
/hpt2 hpt 2 mul def
|
||||
/Lshow {currentpoint stroke M 0 vshift R
|
||||
Blacktext {gsave 0 setgray show grestore} {show} ifelse} def
|
||||
/Rshow {currentpoint stroke M dup stringwidth pop neg vshift R
|
||||
Blacktext {gsave 0 setgray show grestore} {show} ifelse} def
|
||||
/Cshow {currentpoint stroke M dup stringwidth pop -2 div vshift R
|
||||
Blacktext {gsave 0 setgray show grestore} {show} ifelse} def
|
||||
/UP {dup vpt_ mul /vpt exch def hpt_ mul /hpt exch def
|
||||
/hpt2 hpt 2 mul def /vpt2 vpt 2 mul def} def
|
||||
/DL {Color {setrgbcolor Solid {pop []} if 0 setdash}
|
||||
{pop pop pop 0 setgray Solid {pop []} if 0 setdash} ifelse} def
|
||||
/BL {stroke userlinewidth 2 mul setlinewidth
|
||||
Rounded {1 setlinejoin 1 setlinecap} if} def
|
||||
/AL {stroke userlinewidth 2 div setlinewidth
|
||||
Rounded {1 setlinejoin 1 setlinecap} if} def
|
||||
/UL {dup gnulinewidth mul /userlinewidth exch def
|
||||
dup 1 lt {pop 1} if 10 mul /udl exch def} def
|
||||
/PL {stroke userlinewidth setlinewidth
|
||||
Rounded {1 setlinejoin 1 setlinecap} if} def
|
||||
3.8 setmiterlimit
|
||||
% Default Line colors
|
||||
/LCw {1 1 1} def
|
||||
/LCb {0 0 0} def
|
||||
/LCa {0 0 0} def
|
||||
/LC0 {1 0 0} def
|
||||
/LC1 {0 1 0} def
|
||||
/LC2 {0 0 1} def
|
||||
/LC3 {1 0 1} def
|
||||
/LC4 {0 1 1} def
|
||||
/LC5 {1 1 0} def
|
||||
/LC6 {0 0 0} def
|
||||
/LC7 {1 0.3 0} def
|
||||
/LC8 {0.5 0.5 0.5} def
|
||||
% Default Line Types
|
||||
/LTw {PL [] 1 setgray} def
|
||||
/LTb {BL [] LCb DL} def
|
||||
/LTa {AL [1 udl mul 2 udl mul] 0 setdash LCa setrgbcolor} def
|
||||
/LT0 {PL [] LC0 DL} def
|
||||
/LT1 {PL [4 dl1 2 dl2] LC1 DL} def
|
||||
/LT2 {PL [2 dl1 3 dl2] LC2 DL} def
|
||||
/LT3 {PL [1 dl1 1.5 dl2] LC3 DL} def
|
||||
/LT4 {PL [6 dl1 2 dl2 1 dl1 2 dl2] LC4 DL} def
|
||||
/LT5 {PL [3 dl1 3 dl2 1 dl1 3 dl2] LC5 DL} def
|
||||
/LT6 {PL [2 dl1 2 dl2 2 dl1 6 dl2] LC6 DL} def
|
||||
/LT7 {PL [1 dl1 2 dl2 6 dl1 2 dl2 1 dl1 2 dl2] LC7 DL} def
|
||||
/LT8 {PL [2 dl1 2 dl2 2 dl1 2 dl2 2 dl1 2 dl2 2 dl1 4 dl2] LC8 DL} def
|
||||
/Pnt {stroke [] 0 setdash gsave 1 setlinecap M 0 0 V stroke grestore} def
|
||||
/Dia {stroke [] 0 setdash 2 copy vpt add M
|
||||
hpt neg vpt neg V hpt vpt neg V
|
||||
hpt vpt V hpt neg vpt V closepath stroke
|
||||
Pnt} def
|
||||
/Pls {stroke [] 0 setdash vpt sub M 0 vpt2 V
|
||||
currentpoint stroke M
|
||||
hpt neg vpt neg R hpt2 0 V stroke
|
||||
} def
|
||||
/Box {stroke [] 0 setdash 2 copy exch hpt sub exch vpt add M
|
||||
0 vpt2 neg V hpt2 0 V 0 vpt2 V
|
||||
hpt2 neg 0 V closepath stroke
|
||||
Pnt} def
|
||||
/Crs {stroke [] 0 setdash exch hpt sub exch vpt add M
|
||||
hpt2 vpt2 neg V currentpoint stroke M
|
||||
hpt2 neg 0 R hpt2 vpt2 V stroke} def
|
||||
/TriU {stroke [] 0 setdash 2 copy vpt 1.12 mul add M
|
||||
hpt neg vpt -1.62 mul V
|
||||
hpt 2 mul 0 V
|
||||
hpt neg vpt 1.62 mul V closepath stroke
|
||||
Pnt} def
|
||||
/Star {2 copy Pls Crs} def
|
||||
/BoxF {stroke [] 0 setdash exch hpt sub exch vpt add M
|
||||
0 vpt2 neg V hpt2 0 V 0 vpt2 V
|
||||
hpt2 neg 0 V closepath fill} def
|
||||
/TriUF {stroke [] 0 setdash vpt 1.12 mul add M
|
||||
hpt neg vpt -1.62 mul V
|
||||
hpt 2 mul 0 V
|
||||
hpt neg vpt 1.62 mul V closepath fill} def
|
||||
/TriD {stroke [] 0 setdash 2 copy vpt 1.12 mul sub M
|
||||
hpt neg vpt 1.62 mul V
|
||||
hpt 2 mul 0 V
|
||||
hpt neg vpt -1.62 mul V closepath stroke
|
||||
Pnt} def
|
||||
/TriDF {stroke [] 0 setdash vpt 1.12 mul sub M
|
||||
hpt neg vpt 1.62 mul V
|
||||
hpt 2 mul 0 V
|
||||
hpt neg vpt -1.62 mul V closepath fill} def
|
||||
/DiaF {stroke [] 0 setdash vpt add M
|
||||
hpt neg vpt neg V hpt vpt neg V
|
||||
hpt vpt V hpt neg vpt V closepath fill} def
|
||||
/Pent {stroke [] 0 setdash 2 copy gsave
|
||||
translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
|
||||
closepath stroke grestore Pnt} def
|
||||
/PentF {stroke [] 0 setdash gsave
|
||||
translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
|
||||
closepath fill grestore} def
|
||||
/Circle {stroke [] 0 setdash 2 copy
|
||||
hpt 0 360 arc stroke Pnt} def
|
||||
/CircleF {stroke [] 0 setdash hpt 0 360 arc fill} def
|
||||
/C0 {BL [] 0 setdash 2 copy moveto vpt 90 450 arc} bind def
|
||||
/C1 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 0 90 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C2 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 90 180 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C3 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 0 180 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C4 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 180 270 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C5 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 0 90 arc
|
||||
2 copy moveto
|
||||
2 copy vpt 180 270 arc closepath fill
|
||||
vpt 0 360 arc} bind def
|
||||
/C6 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 90 270 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C7 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 0 270 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C8 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 270 360 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C9 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 270 450 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C10 {BL [] 0 setdash 2 copy 2 copy moveto vpt 270 360 arc closepath fill
|
||||
2 copy moveto
|
||||
2 copy vpt 90 180 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C11 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 0 180 arc closepath fill
|
||||
2 copy moveto
|
||||
2 copy vpt 270 360 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C12 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 180 360 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C13 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 0 90 arc closepath fill
|
||||
2 copy moveto
|
||||
2 copy vpt 180 360 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/C14 {BL [] 0 setdash 2 copy moveto
|
||||
2 copy vpt 90 360 arc closepath fill
|
||||
vpt 0 360 arc} bind def
|
||||
/C15 {BL [] 0 setdash 2 copy vpt 0 360 arc closepath fill
|
||||
vpt 0 360 arc closepath} bind def
|
||||
/Rec {newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto
|
||||
neg 0 rlineto closepath} bind def
|
||||
/Square {dup Rec} bind def
|
||||
/Bsquare {vpt sub exch vpt sub exch vpt2 Square} bind def
|
||||
/S0 {BL [] 0 setdash 2 copy moveto 0 vpt rlineto BL Bsquare} bind def
|
||||
/S1 {BL [] 0 setdash 2 copy vpt Square fill Bsquare} bind def
|
||||
/S2 {BL [] 0 setdash 2 copy exch vpt sub exch vpt Square fill Bsquare} bind def
|
||||
/S3 {BL [] 0 setdash 2 copy exch vpt sub exch vpt2 vpt Rec fill Bsquare} bind def
|
||||
/S4 {BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt Square fill Bsquare} bind def
|
||||
/S5 {BL [] 0 setdash 2 copy 2 copy vpt Square fill
|
||||
exch vpt sub exch vpt sub vpt Square fill Bsquare} bind def
|
||||
/S6 {BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt vpt2 Rec fill Bsquare} bind def
|
||||
/S7 {BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt vpt2 Rec fill
|
||||
2 copy vpt Square fill Bsquare} bind def
|
||||
/S8 {BL [] 0 setdash 2 copy vpt sub vpt Square fill Bsquare} bind def
|
||||
/S9 {BL [] 0 setdash 2 copy vpt sub vpt vpt2 Rec fill Bsquare} bind def
|
||||
/S10 {BL [] 0 setdash 2 copy vpt sub vpt Square fill 2 copy exch vpt sub exch vpt Square fill
|
||||
Bsquare} bind def
|
||||
/S11 {BL [] 0 setdash 2 copy vpt sub vpt Square fill 2 copy exch vpt sub exch vpt2 vpt Rec fill
|
||||
Bsquare} bind def
|
||||
/S12 {BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill Bsquare} bind def
|
||||
/S13 {BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill
|
||||
2 copy vpt Square fill Bsquare} bind def
|
||||
/S14 {BL [] 0 setdash 2 copy exch vpt sub exch vpt sub vpt2 vpt Rec fill
|
||||
2 copy exch vpt sub exch vpt Square fill Bsquare} bind def
|
||||
/S15 {BL [] 0 setdash 2 copy Bsquare fill Bsquare} bind def
|
||||
/D0 {gsave translate 45 rotate 0 0 S0 stroke grestore} bind def
|
||||
/D1 {gsave translate 45 rotate 0 0 S1 stroke grestore} bind def
|
||||
/D2 {gsave translate 45 rotate 0 0 S2 stroke grestore} bind def
|
||||
/D3 {gsave translate 45 rotate 0 0 S3 stroke grestore} bind def
|
||||
/D4 {gsave translate 45 rotate 0 0 S4 stroke grestore} bind def
|
||||
/D5 {gsave translate 45 rotate 0 0 S5 stroke grestore} bind def
|
||||
/D6 {gsave translate 45 rotate 0 0 S6 stroke grestore} bind def
|
||||
/D7 {gsave translate 45 rotate 0 0 S7 stroke grestore} bind def
|
||||
/D8 {gsave translate 45 rotate 0 0 S8 stroke grestore} bind def
|
||||
/D9 {gsave translate 45 rotate 0 0 S9 stroke grestore} bind def
|
||||
/D10 {gsave translate 45 rotate 0 0 S10 stroke grestore} bind def
|
||||
/D11 {gsave translate 45 rotate 0 0 S11 stroke grestore} bind def
|
||||
/D12 {gsave translate 45 rotate 0 0 S12 stroke grestore} bind def
|
||||
/D13 {gsave translate 45 rotate 0 0 S13 stroke grestore} bind def
|
||||
/D14 {gsave translate 45 rotate 0 0 S14 stroke grestore} bind def
|
||||
/D15 {gsave translate 45 rotate 0 0 S15 stroke grestore} bind def
|
||||
/DiaE {stroke [] 0 setdash vpt add M
|
||||
hpt neg vpt neg V hpt vpt neg V
|
||||
hpt vpt V hpt neg vpt V closepath stroke} def
|
||||
/BoxE {stroke [] 0 setdash exch hpt sub exch vpt add M
|
||||
0 vpt2 neg V hpt2 0 V 0 vpt2 V
|
||||
hpt2 neg 0 V closepath stroke} def
|
||||
/TriUE {stroke [] 0 setdash vpt 1.12 mul add M
|
||||
hpt neg vpt -1.62 mul V
|
||||
hpt 2 mul 0 V
|
||||
hpt neg vpt 1.62 mul V closepath stroke} def
|
||||
/TriDE {stroke [] 0 setdash vpt 1.12 mul sub M
|
||||
hpt neg vpt 1.62 mul V
|
||||
hpt 2 mul 0 V
|
||||
hpt neg vpt -1.62 mul V closepath stroke} def
|
||||
/PentE {stroke [] 0 setdash gsave
|
||||
translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
|
||||
closepath stroke grestore} def
|
||||
/CircE {stroke [] 0 setdash
|
||||
hpt 0 360 arc stroke} def
|
||||
/Opaque {gsave closepath 1 setgray fill grestore 0 setgray closepath} def
|
||||
/DiaW {stroke [] 0 setdash vpt add M
|
||||
hpt neg vpt neg V hpt vpt neg V
|
||||
hpt vpt V hpt neg vpt V Opaque stroke} def
|
||||
/BoxW {stroke [] 0 setdash exch hpt sub exch vpt add M
|
||||
0 vpt2 neg V hpt2 0 V 0 vpt2 V
|
||||
hpt2 neg 0 V Opaque stroke} def
|
||||
/TriUW {stroke [] 0 setdash vpt 1.12 mul add M
|
||||
hpt neg vpt -1.62 mul V
|
||||
hpt 2 mul 0 V
|
||||
hpt neg vpt 1.62 mul V Opaque stroke} def
|
||||
/TriDW {stroke [] 0 setdash vpt 1.12 mul sub M
|
||||
hpt neg vpt 1.62 mul V
|
||||
hpt 2 mul 0 V
|
||||
hpt neg vpt -1.62 mul V Opaque stroke} def
|
||||
/PentW {stroke [] 0 setdash gsave
|
||||
translate 0 hpt M 4 {72 rotate 0 hpt L} repeat
|
||||
Opaque stroke grestore} def
|
||||
/CircW {stroke [] 0 setdash
|
||||
hpt 0 360 arc Opaque stroke} def
|
||||
/BoxFill {gsave Rec 1 setgray fill grestore} def
|
||||
/Density {
|
||||
/Fillden exch def
|
||||
currentrgbcolor
|
||||
/ColB exch def /ColG exch def /ColR exch def
|
||||
/ColR ColR Fillden mul Fillden sub 1 add def
|
||||
/ColG ColG Fillden mul Fillden sub 1 add def
|
||||
/ColB ColB Fillden mul Fillden sub 1 add def
|
||||
ColR ColG ColB setrgbcolor} def
|
||||
/BoxColFill {gsave Rec PolyFill} def
|
||||
/PolyFill {gsave Density fill grestore grestore} def
|
||||
/h {rlineto rlineto rlineto gsave closepath fill grestore} bind def
|
||||
%
|
||||
% PostScript Level 1 Pattern Fill routine for rectangles
|
||||
% Usage: x y w h s a XX PatternFill
|
||||
% x,y = lower left corner of box to be filled
|
||||
% w,h = width and height of box
|
||||
% a = angle in degrees between lines and x-axis
|
||||
% XX = 0/1 for no/yes cross-hatch
|
||||
%
|
||||
/PatternFill {gsave /PFa [ 9 2 roll ] def
|
||||
PFa 0 get PFa 2 get 2 div add PFa 1 get PFa 3 get 2 div add translate
|
||||
PFa 2 get -2 div PFa 3 get -2 div PFa 2 get PFa 3 get Rec
|
||||
gsave 1 setgray fill grestore clip
|
||||
currentlinewidth 0.5 mul setlinewidth
|
||||
/PFs PFa 2 get dup mul PFa 3 get dup mul add sqrt def
|
||||
0 0 M PFa 5 get rotate PFs -2 div dup translate
|
||||
0 1 PFs PFa 4 get div 1 add floor cvi
|
||||
{PFa 4 get mul 0 M 0 PFs V} for
|
||||
0 PFa 6 get ne {
|
||||
0 1 PFs PFa 4 get div 1 add floor cvi
|
||||
{PFa 4 get mul 0 2 1 roll M PFs 0 V} for
|
||||
} if
|
||||
stroke grestore} def
|
||||
%
|
||||
/languagelevel where
|
||||
{pop languagelevel} {1} ifelse
|
||||
2 lt
|
||||
{/InterpretLevel1 true def}
|
||||
{/InterpretLevel1 Level1 def}
|
||||
ifelse
|
||||
%
|
||||
% PostScript level 2 pattern fill definitions
|
||||
%
|
||||
/Level2PatternFill {
|
||||
/Tile8x8 {/PaintType 2 /PatternType 1 /TilingType 1 /BBox [0 0 8 8] /XStep 8 /YStep 8}
|
||||
bind def
|
||||
/KeepColor {currentrgbcolor [/Pattern /DeviceRGB] setcolorspace} bind def
|
||||
<< Tile8x8
|
||||
/PaintProc {0.5 setlinewidth pop 0 0 M 8 8 L 0 8 M 8 0 L stroke}
|
||||
>> matrix makepattern
|
||||
/Pat1 exch def
|
||||
<< Tile8x8
|
||||
/PaintProc {0.5 setlinewidth pop 0 0 M 8 8 L 0 8 M 8 0 L stroke
|
||||
0 4 M 4 8 L 8 4 L 4 0 L 0 4 L stroke}
|
||||
>> matrix makepattern
|
||||
/Pat2 exch def
|
||||
<< Tile8x8
|
||||
/PaintProc {0.5 setlinewidth pop 0 0 M 0 8 L
|
||||
8 8 L 8 0 L 0 0 L fill}
|
||||
>> matrix makepattern
|
||||
/Pat3 exch def
|
||||
<< Tile8x8
|
||||
/PaintProc {0.5 setlinewidth pop -4 8 M 8 -4 L
|
||||
0 12 M 12 0 L stroke}
|
||||
>> matrix makepattern
|
||||
/Pat4 exch def
|
||||
<< Tile8x8
|
||||
/PaintProc {0.5 setlinewidth pop -4 0 M 8 12 L
|
||||
0 -4 M 12 8 L stroke}
|
||||
>> matrix makepattern
|
||||
/Pat5 exch def
|
||||
<< Tile8x8
|
||||
/PaintProc {0.5 setlinewidth pop -2 8 M 4 -4 L
|
||||
0 12 M 8 -4 L 4 12 M 10 0 L stroke}
|
||||
>> matrix makepattern
|
||||
/Pat6 exch def
|
||||
<< Tile8x8
|
||||
/PaintProc {0.5 setlinewidth pop -2 0 M 4 12 L
|
||||
0 -4 M 8 12 L 4 -4 M 10 8 L stroke}
|
||||
>> matrix makepattern
|
||||
/Pat7 exch def
|
||||
<< Tile8x8
|
||||
/PaintProc {0.5 setlinewidth pop 8 -2 M -4 4 L
|
||||
12 0 M -4 8 L 12 4 M 0 10 L stroke}
|
||||
>> matrix makepattern
|
||||
/Pat8 exch def
|
||||
<< Tile8x8
|
||||
/PaintProc {0.5 setlinewidth pop 0 -2 M 12 4 L
|
||||
-4 0 M 12 8 L -4 4 M 8 10 L stroke}
|
||||
>> matrix makepattern
|
||||
/Pat9 exch def
|
||||
/Pattern1 {PatternBgnd KeepColor Pat1 setpattern} bind def
|
||||
/Pattern2 {PatternBgnd KeepColor Pat2 setpattern} bind def
|
||||
/Pattern3 {PatternBgnd KeepColor Pat3 setpattern} bind def
|
||||
/Pattern4 {PatternBgnd KeepColor Landscape {Pat5} {Pat4} ifelse setpattern} bind def
|
||||
/Pattern5 {PatternBgnd KeepColor Landscape {Pat4} {Pat5} ifelse setpattern} bind def
|
||||
/Pattern6 {PatternBgnd KeepColor Landscape {Pat9} {Pat6} ifelse setpattern} bind def
|
||||
/Pattern7 {PatternBgnd KeepColor Landscape {Pat8} {Pat7} ifelse setpattern} bind def
|
||||
} def
|
||||
%
|
||||
%
|
||||
%End of PostScript Level 2 code
|
||||
%
|
||||
/PatternBgnd {
|
||||
TransparentPatterns {} {gsave 1 setgray fill grestore} ifelse
|
||||
} def
|
||||
%
|
||||
% Substitute for Level 2 pattern fill codes with
|
||||
% grayscale if Level 2 support is not selected.
|
||||
%
|
||||
/Level1PatternFill {
|
||||
/Pattern1 {0.250 Density} bind def
|
||||
/Pattern2 {0.500 Density} bind def
|
||||
/Pattern3 {0.750 Density} bind def
|
||||
/Pattern4 {0.125 Density} bind def
|
||||
/Pattern5 {0.375 Density} bind def
|
||||
/Pattern6 {0.625 Density} bind def
|
||||
/Pattern7 {0.875 Density} bind def
|
||||
} def
|
||||
%
|
||||
% Now test for support of Level 2 code
|
||||
%
|
||||
Level1 {Level1PatternFill} {Level2PatternFill} ifelse
|
||||
%
|
||||
/Symbol-Oblique /Symbol findfont [1 0 .167 1 0 0] makefont
|
||||
dup length dict begin {1 index /FID eq {pop pop} {def} ifelse} forall
|
||||
currentdict end definefont pop
|
||||
end
|
||||
%%EndProlog
|
||||
gnudict begin
|
||||
gsave
|
||||
doclip
|
||||
50 50 translate
|
||||
0.050 0.050 scale
|
||||
0 setgray
|
||||
newpath
|
||||
1.000 UL
|
||||
LTb
|
||||
1.000 UL
|
||||
LTa
|
||||
1342 1993 M
|
||||
5461 0 V
|
||||
stroke
|
||||
LTb
|
||||
1342 1993 M
|
||||
5461 0 R
|
||||
stroke
|
||||
LTa
|
||||
1342 2258 M
|
||||
5461 0 V
|
||||
stroke
|
||||
LTb
|
||||
1342 2258 M
|
||||
5461 0 R
|
||||
stroke
|
||||
LTa
|
||||
1342 2523 M
|
||||
5461 0 V
|
||||
stroke
|
||||
LTb
|
||||
1342 2523 M
|
||||
5461 0 R
|
||||
stroke
|
||||
LTa
|
||||
1342 2788 M
|
||||
5461 0 V
|
||||
stroke
|
||||
LTb
|
||||
1342 2788 M
|
||||
5461 0 R
|
||||
stroke
|
||||
LTa
|
||||
1342 3053 M
|
||||
5461 0 V
|
||||
stroke
|
||||
LTb
|
||||
1342 3053 M
|
||||
5461 0 R
|
||||
stroke
|
||||
LTa
|
||||
1342 3319 M
|
||||
5461 0 V
|
||||
stroke
|
||||
LTb
|
||||
1342 3319 M
|
||||
5461 0 R
|
||||
stroke
|
||||
LTa
|
||||
1342 3584 M
|
||||
5461 0 V
|
||||
stroke
|
||||
LTb
|
||||
1342 3584 M
|
||||
5461 0 R
|
||||
stroke
|
||||
LTa
|
||||
1342 3849 M
|
||||
5461 0 V
|
||||
stroke
|
||||
LTb
|
||||
1342 3849 M
|
||||
5461 0 R
|
||||
stroke
|
||||
LTa
|
||||
1342 4114 M
|
||||
5461 0 V
|
||||
stroke
|
||||
LTb
|
||||
1342 4114 M
|
||||
5461 0 R
|
||||
stroke
|
||||
LTa
|
||||
1342 4379 M
|
||||
5461 0 V
|
||||
stroke
|
||||
LTb
|
||||
1342 4379 M
|
||||
5461 0 R
|
||||
1949 1993 M
|
||||
0 2386 R
|
||||
2556 1993 M
|
||||
0 2386 R
|
||||
3162 1993 M
|
||||
0 2386 R
|
||||
3769 1993 M
|
||||
0 2386 R
|
||||
4376 1993 M
|
||||
0 2386 R
|
||||
4983 1993 M
|
||||
0 2386 R
|
||||
5589 1993 M
|
||||
0 2386 R
|
||||
6196 1993 M
|
||||
0 2386 R
|
||||
-4854 0 R
|
||||
0 -2386 V
|
||||
5461 0 V
|
||||
0 2386 R
|
||||
-5461 0 R
|
||||
1.000 UP
|
||||
stroke
|
||||
LT0
|
||||
0.75 0.75 0.75 C 1.000 1949 1993 203 1159 BoxColFill
|
||||
LTb
|
||||
1949 1993 N
|
||||
0 1158 V
|
||||
202 0 V
|
||||
0 -1158 V
|
||||
-202 0 V
|
||||
Z stroke
|
||||
LT0
|
||||
0.75 0.75 0.75 C 1.000 2556 1993 203 1387 BoxColFill
|
||||
LTb
|
||||
2556 1993 N
|
||||
0 1386 V
|
||||
202 0 V
|
||||
0 -1386 V
|
||||
-202 0 V
|
||||
Z stroke
|
||||
LT0
|
||||
0.75 0.75 0.75 C 1.000 3162 1993 204 160 BoxColFill
|
||||
LTb
|
||||
3162 1993 N
|
||||
0 159 V
|
||||
203 0 V
|
||||
0 -159 V
|
||||
-203 0 V
|
||||
Z stroke
|
||||
LT0
|
||||
0.75 0.75 0.75 C 1.000 3769 1993 203 2072 BoxColFill
|
||||
LTb
|
||||
3769 1993 N
|
||||
0 2071 V
|
||||
202 0 V
|
||||
0 -2071 V
|
||||
-202 0 V
|
||||
Z stroke
|
||||
LT0
|
||||
0.75 0.75 0.75 C 1.000 4376 1993 203 96 BoxColFill
|
||||
LTb
|
||||
4376 1993 N
|
||||
0 95 V
|
||||
202 0 V
|
||||
0 -95 V
|
||||
-202 0 V
|
||||
Z stroke
|
||||
LT0
|
||||
0.75 0.75 0.75 C 1.000 4983 1993 203 119 BoxColFill
|
||||
LTb
|
||||
4983 1993 N
|
||||
0 118 V
|
||||
202 0 V
|
||||
0 -118 V
|
||||
-202 0 V
|
||||
Z stroke
|
||||
LT0
|
||||
0.75 0.75 0.75 C 1.000 5589 1993 204 28 BoxColFill
|
||||
LTb
|
||||
5589 1993 N
|
||||
0 27 V
|
||||
203 0 V
|
||||
0 -27 V
|
||||
-203 0 V
|
||||
Z stroke
|
||||
LT0
|
||||
0.75 0.75 0.75 C 1.000 6196 1993 203 1987 BoxColFill
|
||||
LTb
|
||||
6196 1993 N
|
||||
0 1986 V
|
||||
202 0 V
|
||||
0 -1986 V
|
||||
-202 0 V
|
||||
Z stroke
|
||||
LT0
|
||||
0.75 0.75 0.75 C 1.000 UL
|
||||
LT1
|
||||
1.000 UP
|
||||
LTb
|
||||
1.000 UL
|
||||
LTb
|
||||
1342 4379 M
|
||||
0 -2386 V
|
||||
5461 0 V
|
||||
0 2386 R
|
||||
-5461 0 R
|
||||
1.000 UP
|
||||
stroke
|
||||
grestore
|
||||
end
|
||||
showpage
|
||||
%%Trailer
|
|
@ -0,0 +1,24 @@
|
|||
\begin{gnuplot}[terminal=epslatex,scale=0.8]
|
||||
set size 0.9,1
|
||||
set auto x
|
||||
set yrange [0:*]
|
||||
set ylabel "Call stack size"
|
||||
set key off
|
||||
|
||||
# styling
|
||||
set decimal locale
|
||||
set format "%'g"
|
||||
set border 3 front
|
||||
set style data histogram
|
||||
set style fill solid border -1
|
||||
set tics scale 0.0
|
||||
set xtics rotate by -45 offset 0.3
|
||||
set grid y
|
||||
|
||||
set bmargin 5
|
||||
|
||||
# load data from csv file
|
||||
set datafile separator ","
|
||||
plot "data/stack-limits.dat" using 2:xtic(1) lc rgb "gray", \
|
||||
'' using ($0+0.15):($2+2000):(sprintf("%'g",$2)) with labels
|
||||
\end{gnuplot}
|
|
@ -0,0 +1,123 @@
|
|||
var Class = ( function( extending )
|
||||
{
|
||||
// implementation left to reader
|
||||
var _privname = getRandomName();
|
||||
|
||||
var C = function( dfn )
|
||||
{
|
||||
// extend from an empty base
|
||||
return C.extend( null, dfn );
|
||||
};
|
||||
|
||||
C.extend = function( base, dfn )
|
||||
{
|
||||
base = base || function() {};
|
||||
|
||||
// prevent ctor invocation
|
||||
extending = true;
|
||||
|
||||
var ctor = function()
|
||||
{
|
||||
// do nothing if extending
|
||||
if ( extending )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// call "actual" constructor
|
||||
this.__construct &&
|
||||
this.__construct.apply(
|
||||
this, arguments
|
||||
);
|
||||
};
|
||||
|
||||
// public prototype
|
||||
ctor.prototype = new base();
|
||||
ctor.prototype.constructor = ctor;
|
||||
|
||||
// private prototype (read-only,
|
||||
// non-configurable, non-enumerable)
|
||||
Object.defineProperty(
|
||||
ctor, _privname, { value: {} }
|
||||
);
|
||||
|
||||
copyTo(
|
||||
ctor.prototype,
|
||||
ctor[ _privname ],
|
||||
dfn
|
||||
);
|
||||
|
||||
// done extending; clear flag to
|
||||
// ensure ctor can be invoked
|
||||
extending = false;
|
||||
|
||||
return ctor;
|
||||
};
|
||||
|
||||
function copyTo( pub, priv, members )
|
||||
{
|
||||
var hasOwn = Object.prototype
|
||||
.hasOwnProperty;
|
||||
|
||||
for ( var member in members )
|
||||
{
|
||||
if ( !hasOwn.call( members, member ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// if prefixed with an underscore,
|
||||
// assign to private "prototype"
|
||||
var dest = ( member[ 0 ] === '_' )
|
||||
? priv : pub;
|
||||
|
||||
dest[ member ] = wrap(
|
||||
members[ member ]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function wrap( method )
|
||||
{
|
||||
return function()
|
||||
{
|
||||
this.__priv =
|
||||
this.constructor[ _privname ];
|
||||
|
||||
var retval = method.apply(
|
||||
this, arguments
|
||||
);
|
||||
|
||||
this.__priv = undefined;
|
||||
return retval;
|
||||
};
|
||||
}
|
||||
|
||||
return C;
|
||||
} )( false );
|
||||
|
||||
|
||||
// dummy implementation
|
||||
function getRandomName()
|
||||
{
|
||||
return '__privobj';
|
||||
}
|
||||
|
||||
|
||||
var Foo = Class(
|
||||
{
|
||||
getValue: function()
|
||||
{
|
||||
return this.__priv._getPrivValue();
|
||||
},
|
||||
|
||||
_getPrivValue: function()
|
||||
{
|
||||
return 'private';
|
||||
}
|
||||
} );
|
||||
|
||||
var inst = new Foo();
|
||||
inst.getValue(); // "private"
|
||||
inst._getPrivValue; // undefined
|
||||
inst.__priv; // undefined
|
|
@ -54,7 +54,7 @@ var Class = ( function( extending )
|
|||
|
||||
dest[ member ] = members[ member ];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return C;
|
||||
} )( false );
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
function wrap( func )
|
||||
{
|
||||
return function()
|
||||
{
|
||||
return 'one ' +
|
||||
func.apply( this, arguments ) +
|
||||
' three';
|
||||
};
|
||||
}
|
||||
|
||||
function str( value )
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
wrap( str )( 'two' ); // "one two three"
|
||||
|
||||
|
||||
// demonstrating wrappers with prototypes
|
||||
function Foo( value )
|
||||
{
|
||||
this._value = value;
|
||||
};
|
||||
|
||||
Foo.prototype = {
|
||||
bar: wrap( function()
|
||||
{
|
||||
return this._value;
|
||||
} )
|
||||
};
|
||||
|
||||
var inst = new Foo( '2' );
|
||||
inst.bar(); // "one 2 three"
|
|
@ -1,5 +1,5 @@
|
|||
\section{Encapsulating the Hacks}
|
||||
\label{sec:encap}
|
||||
\label{sec:encap-hacks}
|
||||
Imagine jumping into a project in order to make a simple modification and then
|
||||
seeing the code in \jsref{lst:prot-share}. This is a far cry from the simple
|
||||
protected member declarations in traditional classical object-oriented
|
||||
|
@ -182,7 +182,7 @@ of that base constructor.
|
|||
\subsubsection{Factory Conveniences}
|
||||
Although our constructor factory described in section~\ref{sec:ctor-factory} is
|
||||
thus far very simple, one should take the time to realize what a powerful
|
||||
abstraction has been created; it allows us to inject our own code in any part of
|
||||
abstraction has been created: it allows us to inject our own code in any part of
|
||||
the constructor creation process, giving us full control over our class-like
|
||||
objects. Indeed, this abstraction will be used as a strong foundation going
|
||||
forward throughout all of section~\ref{sec:encap}. In the meantime, we can take
|
||||
|
@ -242,7 +242,7 @@ require the use of the keyword, as has been demonstrated throughout this article
|
|||
with the various \var{Error} types. Secondly, the omission of the keyword would
|
||||
allow us to jump immediately into calling a method on an object without dealing
|
||||
with awkward precedence rules: \code{Foo( "Name" ).getName()} vs. \code{( new
|
||||
Foo( "Name" ) ).getName()}. However, those reasons exit more to offer syntactic
|
||||
Foo( "Name" ) ).getName()}. However, those reasons exist more to offer syntactic
|
||||
sugar; they do little to persuade those who do want or not mind the
|
||||
\operator{new} operator.
|
||||
|
||||
|
@ -287,9 +287,197 @@ instance of itself through a recursive call.
|
|||
|
||||
Alternatively, the reader may decide to throw an error instead of automatically
|
||||
returning a new instance. This would require the use of the \operator{new}
|
||||
operator, while still ensuring the global scope will not be polluted with
|
||||
unnecessary values. If the constructor is in strict mode, then the error would
|
||||
help to point out bugs in the code. However, for the reason that the keyword is
|
||||
optional for many core ECMAScript constructors, the author recommends the
|
||||
implementation in \jsref{lst:new-global-fix}.
|
||||
operator for instantiation, while still ensuring that the global scope will not
|
||||
be polluted with unnecessary values. If the constructor is in strict mode, then
|
||||
the pollution of the global scope would not be an issue and the error would
|
||||
instead help to point out inconsistencies in the code. However, for the reason
|
||||
that the keyword is optional for many core ECMAScript constructors, the author
|
||||
recommends the implementation in \jsref{lst:new-global-fix}.
|
||||
|
||||
\subsection{Private Member Encapsulation}
|
||||
Section~\ref{sec:encap} discussed the encapsulation of private member data
|
||||
by means of private property and method objects, avoiding the performance impact
|
||||
of privileged members (see section~\ref{sec:privileged}). In order to avoid
|
||||
memory leaks, the private data was stored on the instance itself rather than a
|
||||
truly encapsulated object. The amount of code required for this implementation
|
||||
is relatively small, but it is still repeated unnecessarily between all
|
||||
constructors.
|
||||
|
||||
The private member implementation had two distinct pieces --- private
|
||||
properties, as demonstrated in \jsref{lst:encap-inst}, and private methods, as
|
||||
demonstrated in \jsref{lst:method-priv}. This distinction is important, as
|
||||
private methods should not be redefined for each new instance (see
|
||||
\fref{fig:proto-priv-cmp}). Properties, however, \emph{must} have their values
|
||||
copied for each new instance to prevent references from being shared between
|
||||
multiple instances (see \jsref{lst:proto-reuse}; this is not an issue for
|
||||
scalars). For the time being, we will focus on the method implementation and
|
||||
leave the manual declaration of private properties to the \func{\_\_construct()}
|
||||
method.
|
||||
|
||||
The listings in section~\ref{sec:encap} were derived from a simple concept ---
|
||||
the private member objects were within the scope of the prototype members.
|
||||
However, if we are encapsulating this hack within our constructor factory, then
|
||||
the members (the definition object) would be declared \emph{outside} the scope
|
||||
of any private member objects that are hidden within our factory. To expose the
|
||||
private ``prototype'' object, we could accept a function instead of a definition
|
||||
object, which would expose a reference to the object (\jsref{lst:prot-func}).
|
||||
However, this would be very unnatural and unintuitive. To keep our ``class''
|
||||
declarations simple, another method is needed.
|
||||
|
||||
Consider the private member concept in a classical sense --- the data should be
|
||||
available only to the methods of the class, but should not be accessible outside
|
||||
of them. That is, given any class \code{C} with private property \code{C.\_priv}
|
||||
and public method \code{C.getPrivValue()}, and an instance \code{i} of class
|
||||
\code{C}, \code{i.\_priv} should not be defined unless within the context of
|
||||
\code{i.getPrivValue()}. Consider then the only means of exposing that data to
|
||||
the members of the prototype in ECMAScript without use of closures: through the
|
||||
instance itself (\keyword{this}). This naturally derives an implementation that
|
||||
had not been previously considered due to the impracticality of its use without
|
||||
an automated factory --- exposing private members before a method invocation and
|
||||
revoking them after the method has returned.
|
||||
|
||||
To accomplish this, the factory must be able to intelligently determine when a
|
||||
method is being invoked. This leads us into a somewhat sensitive topic ---
|
||||
function wrapping. In order to perform additional logic on invocation of a
|
||||
particular method, it must be wrapped within another function. This
|
||||
\dfn{wrapper} would expose the private data on \keyword{this}, invoke the
|
||||
original function associated with the method call, remove the reference and then
|
||||
return whatever value was returned by the original function. This creates the
|
||||
illusion of invoking the method directly.\footnote{This is the same concept used
|
||||
to emulate \code{Function.bind()} in pre-ECMAScript 5 environments. This concept
|
||||
can also be easily extended to create \dfn{partially applied functions}.}
|
||||
|
||||
\lstinputlisting[%
|
||||
label=lst:func-wrap,
|
||||
caption=Wrapping a function by returning a \emph{new} function which calls the
|
||||
original,
|
||||
lastline=16
|
||||
]{lst/func-wrap.js}
|
||||
|
||||
\jsref{lst:func-wrap} demonstrates the basic concept of a function wrapper.
|
||||
\func{wrap()} accepts a single argument, \var{func}, and returns a new anonymous
|
||||
function which invokes \var{func}, returning its value with a prefix and suffix.
|
||||
Note how all arguments are forwarded to \var{func}, allowing us to invoke our
|
||||
wrapped function as if it were the original. Also note the context in which
|
||||
\var{func} is being called (the first argument of \func{apply()}). By binding
|
||||
\keyword{this} of \var{func} to \keyword{this} of our wrapper, we are
|
||||
effectively forwarding it. This detail is especially important if we are using
|
||||
a wrapper within a prototype, as we \emph{must} bind \keyword{this} to the
|
||||
instance that the method is being invoked upon. Use of \func{wrap()} with a
|
||||
prototype is demonstrated in \jsref{lst:func-wrap-ex} below.
|
||||
|
||||
\lstinputlisting[%
|
||||
label=lst:func-wrap-ex,
|
||||
caption=Using \func{wrap()} from \jsref{lst:func-wrap} with prototypes,
|
||||
firstnumber=last,
|
||||
firstline=20
|
||||
]{lst/func-wrap.js}
|
||||
|
||||
It is this concept that will be used to implement method wrapping in our
|
||||
constructor factory. For each function $f$ of definition object $D$, $f'$ will
|
||||
be created using a method similar to \jsref{lst:func-wrap-ex}. $f'$ will invoke
|
||||
$f$ after setting the private member object on \keyword{this}, then reset it
|
||||
after $f$ returns. Finally, the return value of $f$ will be returned by $f'$. It
|
||||
should be noted that $f'$ must exist even if $f$ is public, since public methods
|
||||
may still need access to private members.\footnote{As we will see in the
|
||||
examination of \fref{fig:func-wrap-perf}, the performance impact of this
|
||||
decision is minimal.}
|
||||
|
||||
\begin{figure*}[t]
|
||||
\center
|
||||
\subfloat[%
|
||||
Wrapper performance \emph{(invocation only)}. Operations per second rounded to
|
||||
millions.\cite{jsperf-func-wrap} Numbers in parenthesis indicate percent
|
||||
change between the two values, indicating a significant performance loss.
|
||||
]{
|
||||
\input{data/func-wrap-invoke.tex}
|
||||
\label{fig:func-wrap-perf-invoke}
|
||||
}
|
||||
\quad
|
||||
\subfloat[%
|
||||
Wrapper performance \emph{with business logic}
|
||||
(\code{(new Array(100)).join(',|').split('|')}); performance
|
||||
impact is negligible. Operations per second.\cite{jsperf-func-wrap-blogic}
|
||||
]{
|
||||
\input{data/func-wrap-blogic.tex}
|
||||
\label{fig:func-wrap-perf-blogic}
|
||||
}
|
||||
\caption{Function wrapping performance considerations. When measuring invocation
|
||||
performance, the wrapper appears to be a terrible solution to any problem.
|
||||
However, when considering the business logic the remainder of the software is
|
||||
likely to contain, the effects of the wrapper are negligible. As such, worrying
|
||||
about the wrapper is likely to be a micro-optimization, unless dealing with
|
||||
call stack limitations. The wrapper in these tests simply invokes the wrapped
|
||||
method with \code{Function.apply()}, forwarding all arguments.}
|
||||
\label{fig:func-wrap-perf}
|
||||
\end{figure*}
|
||||
|
||||
Many readers are likely to be concerned about a decision that wraps every
|
||||
function of our definition object, as this will require two function calls each
|
||||
time a method is invoked. \fref{fig:func-wrap-perf-invoke} shows why this detail
|
||||
is likely to be a concern --- invoking our wrapped function is so slow in
|
||||
comparison to invoking the original function directly that the solution seems
|
||||
prohibitive. However, one must consider how functions are \emph{actually} used
|
||||
--- to perform some sort of business logic. It is rare that we would invoke
|
||||
bodiless functions continuously in a loop. Rather, we should take into
|
||||
consideration the \emph{percent change between function invocations that contain
|
||||
some sort of business logic}. This is precisely what
|
||||
\frefpg{fig:func-wrap-perf-blogic} takes into consideration, showing that our
|
||||
invocation worry is would actually be a micro-optimization. For example, in
|
||||
software that performs DOM manipulation, the performance impact of
|
||||
wrapper invocation is likely to be negligible due to repaints being highly
|
||||
intensive operations.
|
||||
|
||||
One legitimate concern of our wrapper implementation, however, is limited
|
||||
call stack space. The wrapper will effectively cut the remaining stack space in
|
||||
half if dealing with recursive operations on itself, which may be a problem
|
||||
for environments that do not support tail call optimizations, or for algorithms
|
||||
that are not written in such a way that tail call optimizations can be
|
||||
performed.\footnote{Another concern is that the engine may not be able to
|
||||
perform tail call optimization because the function may recurse on the wrapper
|
||||
instead of itself.} In such a situation, we can avoid the problem entirely by
|
||||
recommending that heavy recursive algorithms do not invoke wrapped methods;
|
||||
instead, the recursive operation can be performed using ``normal'' (unwrapped)
|
||||
functions and its result returned by a wrapped method call.
|
||||
|
||||
\begin{figure}[t]
|
||||
\center
|
||||
\input{data/stack-limits.tex}
|
||||
\caption{Call stack limits of various common browsers. \cite{oreilly-hpj}
|
||||
Determining the call stack limit for your own environment is as simple as
|
||||
incrementing a counter for each recursive call until an error is thrown.}
|
||||
\label{fig:stack-limits}
|
||||
\end{figure}
|
||||
|
||||
That said, call stack sizes for ECMAScript environments are growing increasingly
|
||||
larger. Call stack limits for common browsers (including historical versions for
|
||||
comparison) are listed in \frefpg{fig:stack-limits}. Should this limit be
|
||||
reached, another alternative is to use \func{setTimeout()} to reset the stack
|
||||
and continue the recursive operation. This can also have the benefit of making
|
||||
the operation asynchronous.
|
||||
|
||||
Factoring this logic into the constructor factory is further complicated by our
|
||||
inability to distinguish between members intended to be public and those
|
||||
intended to be private. In section~\ref{sec:encap}, this issue was not a concern
|
||||
because the members could be explicitly specified separately per implementation.
|
||||
With the factory, we are provided only a single definition object; asking for
|
||||
multiple would be confusing, messy and unnatural to those coming from other
|
||||
classical object-oriented languages. Therefore, our second task shall be to
|
||||
augment \func{copyTo()} in \jsref{lst:ctor-factory} to distinguish between
|
||||
public and private members.
|
||||
|
||||
Section~\ref{sec:privileged} mentioned the convention of using a single
|
||||
underscore as a prefix for member names to denote a private member (e.g.
|
||||
\code{this.\_foo}). We will adopt this convention for our definition object, as
|
||||
it is both simple and performant (only a single-character check). Combining this
|
||||
concept with the wrapper implementation, we arrive at
|
||||
\jsref{lst:ctor-factory-priv}.
|
||||
|
||||
\lstinputlisting[%
|
||||
label=lst:ctor-factory-priv,
|
||||
caption=Altering the constructor factory in \jsref{lst:ctor-factory} to
|
||||
support private methods in a manner similar to \jsref{lst:method-priv},
|
||||
lastline=97
|
||||
]{lst/ctor-factory-priv.js}
|
||||
|
||||
(INCOMPLETE.)
|
||||
|
|
|
@ -46,3 +46,14 @@ The following listings are provided under alternative licenses.
|
|||
\small
|
||||
\item[\jsref{lst:defprop-check}] GNU LGPL (taken from ease.js)
|
||||
\end{description}
|
||||
|
||||
\subsection{Reference Licenses}
|
||||
The reader should be warned that certain references mentioned within this
|
||||
article are non-free (that is, their licenses do not permit redistribution,
|
||||
modification, or derivative works). These references are denoted with
|
||||
``\citenf''. While these resources are not the official documentation for free
|
||||
software (and consequently do not pose a direct threat to the users of free
|
||||
software), be aware that they do prohibit you from helping your friends and
|
||||
neighbors by giving them a copy.
|
||||
|
||||
This article itself holds no such restrictions.
|
||||
|
|
Loading…
Reference in New Issue