Near-complete private member implementation section

master
Mike Gerwitz 2012-03-05 23:20:29 -05:00
parent a8813ad4a8
commit 28e8829511
14 changed files with 1128 additions and 10 deletions

View File

@ -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}
}

View File

@ -8,6 +8,9 @@
\usepackage{hyperref}
\usepackage{cite}
\usepackage{multirow}
\usepackage{subfig}
\usepackage{gnuplottex}
\usepackage{epstopdf}
\hypersetup{colorlinks,
citecolor=black,

View File

@ -0,0 +1,3 @@
Browser,No Wrapper,Factory,% Change
"Chromium 14",52342,52342,0.00
"Firefox 8",65947,65947,0.00

View File

@ -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}

View File

@ -0,0 +1,3 @@
Browser,No Wrapper,Closure,Factory,% Change
"Chromium 14",734,70,64,1135
"Firefox 8",381,2,2,18864

View File

@ -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}

View File

@ -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

View File

@ -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

View File

@ -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}

View File

@ -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

View File

@ -54,7 +54,7 @@ var Class = ( function( extending )
dest[ member ] = members[ member ];
}
};
}
return C;
} )( false );

33
lst/func-wrap.js 100644
View File

@ -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"

View File

@ -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.)

View File

@ -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.