GhaSShee


Javascript 1


Reference * Javascript 6th Edition (O'Reilly)
# Introduction ## e.g. Draw circles ~~~js const CHANNELS_PER_PIXEL = 4; //rgba function drawCircle (x0, y0, radius, canvas) { var x = radius; var y = 0; var decisionOver2 = 1 - x; // Decision criterion divided by 2 evaluated at x=r, y=0 var imageWidth = canvas.width; var imageHeight = canvas.height; var context = canvas.getContext('2d'); var imageData = context.getImageData(0, 0, imageWidth, imageHeight); var pixelData = imageData.data; var makePixelIndexer = function (width) { return function (i, j) { var index = CHANNELS_PER_PIXEL * (j * width + i); //index points to the Red channel of pixel //at column i and row j calculated from top left return index; }; }; var pixelIndexer = makePixelIndexer(imageWidth); var drawPixel = function (x, y) { var idx = pixelIndexer(x,y); pixelData[idx] = 255; //red pixelData[idx + 1] = 0; //green pixelData[idx + 2] = 255;//blue pixelData[idx + 3] = 255;//alpha }; while (x >= y) { drawPixel(x + x0, y + y0); drawPixel(y + x0, x + y0); drawPixel(-x + x0, y + y0); drawPixel(-y + x0, x + y0); drawPixel(-x + x0, -y + y0); drawPixel(-y + x0, -x + y0); drawPixel(x + x0, -y + y0); drawPixel(y + x0, -x + y0); y++; if (decisionOver2 <= 0) { decisionOver2 += 2 * y + 1; // Change in decision criterion for y -> y+1 } else { x--; decisionOver2 += 2 * (y - x) + 1; // Change for y -> y+1, x -> x-1 } } context.putImageData(imageData, 0, 0); } ~~~ syntax : - statement : 状態の変化を記述する - expression : 数値演算のような何か - control structure : statement * e.g. for statement , if statement , while statement ## Core Javascript ~~~js x = null; // Null is a special value, meaning "no value". 
x = undefined; // Undefined is like null. ~~~ object : a collection of name/value pairs, or a string to value map ~~~js “two” = “three” ~~~ `prototype` をかませると、 instance method でなく class method を定義する ~~~js Point.prototype.r = function() { return Math.sqrt( this.x * this.x + this.y * this.y ); }; ~~~ ### JS in html ~~~ ~~~ ~~~js function debug(msg) { var log = document.getElementById("debuglog"); if (!log) { log = document.createElement("div"); log.id = "debuglog"; log.innerHTML = "

Debug Log

" document.body.appendChild(log); } var pre = document.createElement("pre"); var text = document.createTextNode(msg); pre.appendChild(text); log.appendChild(pre); // pre.innerHTML = msg; とほぼ同じ } function hide(e, reflow) { if (reflow) { e.style.display = "none" } else { e.style.visibilty = "hidden" ; } } function highlight(e) { if (!e.className) e.className = "hilite"; else e.className += "hilite"; } ~~~ ~~~ ~~~ Capturing : Root Object(HTMLだとDocumentオブジェクト)から イベントが発生したオブジェクトに向かって子孫要素をたどり、 順にイベントハンドラに対し処理をディスパッチしていく。http://javascript.info/tutorial/bubbling-and-capturing ~~~ if(image.addEventListener) // addEventListenerというメソッドが存在すれば ~~~ ~~~ function debug2(msg) { var log = $("#debuglog"); if (log.length == 0 ) { log = $("

Debug Log

"); log.appendTo(document.body); } log.append($("
").text(msg));
}
~~~


~~~

~~~


html5 の新しい要素
:   flash を丸々実装したようなもの

    - video
    - audio
    - canvas


## Javascript Loan Calculator

* window.localStorage
* xml
  * ajax を使うとページの一部分だけを書き換える

unicodes

* ecma 3 : Unicode 2.1-
* ecma 5 : Unicode 3-


case-sensitive : distinct `small leter` and `CAPITAL LETTER`

* JavaScript : case-sensitive
* HTML  : not case-sensitive





# Lexical Structure Whitespace, Line Breaks, and Format Control Characters : ~~~ '\u0009' // tab '\u0020' // white space '\uFEFF' // asark '\u000A' // Line Finisher '\n' '\u000D' // carriage return '\u2028' // line separator '\u2029' // paragraph separartor ~~~ ~~~ \r\n // CR LF ~~~ category $ Cf $ : control the visual presentation of text - RIGHT-TO-LEFT MARK `\u200F` - LEFT-TO-RIGHT MARK `\u200E` - ZERO WIDTH JOINER `\u200D` : アラビア語の制御 - ZERO WIDTH NON JOINER `\u200C` : アラビア語の制御 ; 先頭には用いられない BOM : deginate {big endian , little endian} in 16bit Encoding - BOM is just '0xFEFF' - if (BOM = '0xFFFE') it is wrong. Ligature : string -> logo http://blog.antenna.co.jp/PDFTool/archives/2006/01/23/ unicode escape sequence : `\uA0E9` comment : `//` においては unicode は escape されない ~~~ Unicode Standization —----normalize----—> Javascript ~~~ ## literal literal : a data value that appears directly in a program ~~~ 12

 "hello world" 
'Hi' 
true 
/javascript/g // RegExp i
 null // Absence of an object ~~~ ## identifier ~~~ var $name = 'aaa' var _name = 'aaa' var na$me = 'aaa' _ name 
v13 
$str var π = 3.14; var sí = true; ~~~ ## Reserved words Reserved words ~~~ 

break case catch continue debugger default delete function do if else in 
false instanceof finally new for null return typeof switch var this void throw while true with try ~~~ ES5 reserved words

 ~~~ class const enum export extends import super ~~~ 
@strict reserved words

 ~~~ implements let private public yield interface package protected static arguments eval ~~~ Java reserved words
 : ES3 reserves all of this ~~~ abstract boolean byte char class const double enum export extends final float goto native implements package import private int protected interface public long short static super synchronized throws transient volatile ~~~ predefined global variables : you should not use ~~~ arguments Array Boolean Date decodeURI decodeURIComponent encodeURI encodeURIComponent Error eval EvalError Function Infinity isFinite isNaN JSON Math NaN Number Object parseFloat parseInt RangeError ReferenceError RegExp String SyntaxError TypeError undefined URIError ~~~ ## semicolon ~~~ statement; statement; statement // you can omit ; if statements are in different lines statement ... statemnent // you can omit ; the end of line ~~~ ~~~ var a 
a
=
3 
console.log(a) // JavaScript interprets as // var a; a = 3; console.log(a); ~~~ ~~~ var y = x + f 
(a+b).toString() // Javascript interprets as // var y = x + f(a+b).toString(); ~~~ semicolon
に関する例外
 : `break` , `return` , `continue` ~~~ return 
true; // Javascript interprets the code like return; true; ~~~ ~~~ var x = 0 ;[x,x+1,x+2].forEach(function(y){console.log(y)}) // Defensive ; keeps this statement separate ~~~
# Types, Values, and Variables ~~~ variable -> value lval = rval ~~~ ### types
 primitive type
 - numbers - strings - booleans - null , undefined object - unordered collection - type any value can be the sole member of its own special type special objects - array : ordered collectino - function - constructor - class : subtype of constructor class - Array class

 - Date class - RegExp class - Error class javascript has gabage collection (GC) ~~~ type +--primitive +--object type +--with method type : all but below +--without method type : null, undefined type +-- mutable : objects, array +-- immutable : numbers, booleans, string, null, undefined ~~~ ### variables 
variables : $ untyped $ - variable is declared by “var” keyword . - Javascript uses “lexical scoping” - lexical scoping : variable defined outside of function is global - lex : 字句 ## Numbers - no distinction between `Integer` and `Float` - the 64-bit floating-point format defined by the IEEE 754 standard - covering $ \quad \pm 1.7976931348623157 \times 10^{308} $ - integers are exact only in `−9007199254740992` ( $ −2^{53} $ ) and `9007199254740992` ( $ 2^{53} $ ) - $ 2^53 $ 以上のInteger においては厳密さに欠ける e.g. ~~~ - 23; ~~~ - `23` : numeric literal - `-` : unary negative operator e.g. ~~~ 0xff 255 0xCAFE911 212855057 6.023e23 : モル数 Math.pow(2,53) // => 9007199254740992: 2 to the power 53 
Math.ceil(.6) // => 1.0: round to the nearest integer 
Math.floor(.6)
// => 0.0: round down to an integer Math.round(.6) // => 1.0: round up to an integer 
Math.abs(-5) // 5 
Math.max(x,y,z) 
Math.min(x,y,z) 
Math.random() 
Math.PI Math.E // e: The base of natural logarithm 
Math.sqrt(3) 
Math.pow(3, 1/3) 
Math.sin(0) 
Math.log(10) 
Math.log(100) Math.LN10 // log_10 
Math.log(512) Math.LN2 // log_2 
Math.exp(3)
 ~~~ ~~~ Math.E cubed Math.ceil(Math.random()*100) Math.log(100)/Math.LN10 // 2 Math.log(100)/Math.log(10) // 2 Math.LN10==Math.log(10) // true ~~~ 
operators with non-numeric operands that cannot be converted to numbers ~~~ NaN === NaN // false NaN == NaN // false Infinity === Infinity // true var x = NaN // undefined x != x // true isNaN(NaN) // true isFinite(Number.MAX_VALUE) // true isFinite("hello") // false isFinite(1/0) // false ~~~ ~~~ -0 === 0 // true var zero = 0; var negz = -0 zero == negz // true 1/zero === 1/negz // false ~~~ IEEE-754 floating-point representation ~~~ var x = .3 - .2 var y = .2 - .1; x == y // false x == .1 // false y == .1 // true ~~~ 浮動小数点で等しいかどうか比べる時には本当に注意が必要 ### ES6 You can see Number Object details with typing; ~~~ Number.prototype ~~~ ~~~ Number.isSafeInteger(n) { return (typeof n === 'number' && Math.round(n) === n && Number.MIN_SAFE_INTEGER <= n && n <= Number.MAX_SAFE_INTEGER); } Number.isSafeInteger(99999999999999999999) // false Number.isSafeInteger(9999999999999) // true ~~~ ~~~ Math.floor(-3.1) // -4 Math.ceil(-3.1) // -3 Math.trunc(-3.1) // return near 0 => -3 Math.round(-3.1) // -3 ~~~ ~~~ 1.000000234 = 1.000000234(mantissa) × 100. ~~~ ~~~ log1p(x) := ln(x+1) ~~~ ~~~ Math.clz32(x) // Counts the leading zero bits in the 32 bit integer x. Math.clz32(0b01000000000000000000000000000000) // 1 Math.clz32(0b00100000000000000000000000000000) // 2 Math.clz32(2) // 30 Math.clz32(1) // 31 ~~~ ~~~ Math.sinh(x) Math.cosh(x) Math.tanh(x) Math.asinh(x) // Computes the inverse hyperbolic sine of x. Math.acosh(x) Math.atanh(x) Math.hypot(...values) // Computes the square root of the sum of the squares of its arguments. ~~~ ### Date Object ~~~ var then = new Date(2010, 0, 1);
 var now = new Date();
 var elapsed = now - then; later.getFullYear() 
later.getMonth() 
later.getDate() 
later.getDay() 
later.getHours() 
later.getUTCHours() later.toString() 
later.toUTCString() 
later.toLocaleDateString() 
later.toLocaleTimeString() 
later.toISOString() ~~~ ~~~ new Date().toLocaleTimeString(); "23:48:36" console.log(date.toLocaleDateString('ar-EG')); // → "٢٠/١٢/٢٠١٢" ~~~ API : application programming interface
 ### Reference JS funstion locale関連 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString locale := (Language, Region) - プログラミングでは言語と場所を組み合わせたものをlocaleと呼ぶ - en-US : Engilish + United States - en-GB : English + Great Britain ## Text - string : immutable ordered sequence of charcters (u16-bit vals) - the length of a string : the number of characters (u16-bit vals) - javacript は char 型を持たない - Javascript uses UTF-16 ### string Literals code map : `codepoint` $ \mapsto $ `character` surrogate pair : Unicode characters whose codepoints do not fit in 16 bits ~~~ > var p = '\u03c0' // undefined > p // π > p.length // 1 > var e = '\ud835\udc52'// undefined > e // 𝑒 ~~~ 上に挙げたように、二つの codepoint が一つの文字を表す場合もある Javascript では charcter を単位とみなすのではなく、
だ #### quotations ~~~ > 'name="myform"' // ' ' の中に、" " は入る > "Wouldn't you prefer O'Reilly's book?"
 // " " の中に、' ' は入る > 'O\'Reilly\'s' "O'Reilly's" // ' ' の中に、\' \' は入る ~~~ ~~~   // conventions // - html : " " を使う // - javascript : ' ' を使う ~~~ #### line break ~~~ > "This string\nhas two lines" This string has two lines > "\u03c0 is the ration of a circle's cicumferece to its diameter" π is the ration of a circle's cicumferece to its diameter ~~~ - ecma3 : string code must be in 1 line - ecma5 : string code can be in multiple lines by \ - ecma6 : で増えたのは テンプレートリテラル : ``で囲ったもの - \ はstring literal に含まれまない。 - つまり \ はプリコンパイラあるいはマクロのようなものとして、文字列をつなげる変換がなされている、と考えられる。 ### Working with Strings - https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleDateString - https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/replace ### Excape Sequences ~~~ \0 : NUL (\u0000) \b : Backspace (\u0008) \t : Horizontal tab (\u0009) \n : Newline (\u000A) \v : Vertical tab (\u000B) \f : Form feed (\u000C) \r : Carriage return (\u000D) \" : " \' : ' \\ \xXX : Latin-1 (2-hex) \uXXXX : Unicode (4-hex) ~~~ ### RegExp : Regular Expression ~~~ > RegExp(); /(:?)/ ~~~ ~~~ var re = /(\w+)\s(\w+)/; // RegExp /\w/ : word character var str = "John Smith"; // RegExp /\s/ : space var newstr = str.replace(re, "$2, $1"); console.log(newstr); // Smith, John ~~~ ~~~ /^HTML/ // /^HTML/ /[1-9][0-9]*/ // /[1-9][0-9]*/ /\bjavascript\b/i // /\bjavascript\b/i var text = "testing: 1, 2, 3"; var pattern = /\d+/g // \d : digit number pattern.test(text) // true text.search(pattern) // 9 text.match(pattern) // 1,2,3 text.replace(pattern, "#"); // testing: #, #, # text.split(/\D+/); // \D : Non-digit number ,1,2,3 text.split(/\d+/); testing: ,, ,, , ~~~ ## Boolean Values any javascript value can be converted to a boolean value falsy values : converted into false ~~~ undefined null 0 -0 NaN "" ~~~ truthy values ~~~ otherwise ~~~ you can write ~~~ if (o !== null) ... if (o) // less strict : o is not false / falsy value ~~~ Boolean values have only useful method `toString()` ## null / undefined ### `null` ~~~ typeof(null) "object" ~~~ ### `undefined` : - the value of variables that have not been initialized - the value you get when you query the value of an object property or array element that does not exist. - the value returned by function which does not have return value. - the value of function parameters for which no argument is supplied. ~~~ > function a(aa, bb){ console.log("aa is : " + aa); } undefined > a(); undefined undefined ~~~ `undefined` : a predefined global variable. - ES3 : undefined is a read/write variable - ES5 : undefined is read-only ~~~ > typeof(undefined) "undefined" ~~~ ### `null` and `undefined` ~~~ undefined==null // true undefined===null // false ~~~ ## The Global Object The Global Object : unique in a system the properties of Global Object : globally defined symbols when JS interpreter starts , it creates a new Global Obect; global properties : `undefined` , `Infinity` , `NaN` * global functions : `isNaN()` , `parseInt()` , `eval()` * global constructor : `Date()` , `RegExp()` , String() , `Object()`, `Array()` * global objects : Math , JSON global objects $ \in $ the Global Object this book has core reference section !!! @clientSide ~~~ > var global = this; undefined > global Window { external: Object, chrome: Object, document: document, GoogleAnalyticsObject: "ga", alreadyProcessedMarkdeep: true… } ~~~ ## Wrapper Objects ~~~ > var s = "test"; undefined > s.len = 4 // creates `new String(s)` and discard it 4 var t = s.len ; // creates another `new String(s)` but `s.len` is not defined yet undefined t undefined ~~~ that `new String(s)` is called "Wrapper Object" ~~~ > var s = "test"; n = 1, b = true ; > var S = new String(s); > var N = new Number(n); > var B = new Boolean(b); > S == s && B == b && N == n true ~~~ ## Immutable Primitive Values & Mutable Object References Primitives are immutable : ~~~ > var s = "hello"; undefined > s.toUpperCase(); "HELLO" > s "hello" ~~~ Objects are mutable : ~~~ > var o = {x: 1}; undefined > o.x = 2; 2 > o.y = 3; 3 > o Object {x: 2, y: 3} ~~~ ~~~ > var o = {x: 1} > var p = {x: 1} > o == p false ~~~ ### compare Arrays ~~~ > var a = ['a', 'b', 'c'] > var b = []; > for (var i = 0; i< a.length; i++) { b[i] = a[i]; } > a == b false ~~~ ~~~ function equalArrays(a,b){ if (a.length != b.length) return false; for (var i=0; i equalArrays(a,b); true ~~~ #### bug ~~~ var b = {"0":1, "1":2, "2":3 , length: 3} undefined ~~~ #### bugFix ~~~ > function equalArrays(a, b) { if (JSON.stringify(a) != JSON.stringify(b)) return false ; return true; } undefined > equalArrays(a,b); false ~~~ ## Type conversions ~~~ > 10 + " Objects" // "10 Objects" > "7" * "4" // 28 > var n = 1 - "x" > n + " object"; // "NaN object" ~~~ ... see P46 (Table 3-2 @ 3.8 Type Conversion ) ### conversion with `==` #### true ~~~ null == undefined // true false == 0 // true ~~~ #### false ~~~ // if converts null/undefined to false if (null) // but `==` not null == false // false undefined == 0 // false ~~~ ### explicit conversions ~~~ Number("3") // 3 String(false) // "false" Boolean([]) // true Object(3) // new Number(3) ~~~ except `null`/`undefined` has `toString()` ~~~ false.toSring() // "false" ~~~ ~~~ x = "hello" x + "" // same as String(x) +x // same as Number(x) !!x // same as Boolean(x) ~~~ ~~~ (200).toString(2); // "11001000" (200).toString(8); // "310" (200).toString(16); // "c8" ~~~ ~~~ var n = 123456.789 n.toFixed(0) // "123457" n.toFixed(1) // "123456.8" n.toFixed(2) // "123456.79" n.toFixed(3) // "123456.789" n.toFixed(4) // "123456.7890" n.toExponential(1) // "1.2e+5" n.toExponential(2) // "1.23e+5" n.toExponential(3) // "1.235e+5" n.toExponential(10) // "1.2345678900e+5" n.toPrecision(10) // "123456.7890" n.toPrecision(20) // "123456.78900000000431" n.toPrecision(3) // "1.23e+5" ~~~ ~~~ parseInt("3 cats and 2 dogs") // 3 parseInt("32 cats and 2 dogs") // 32 parseInt("32.1 cats and 2 dogs")// 32 parseInt("32 cats and 2 dogs") // 32 parseFloat("it is 3.14 meters long.") // NaN parseFloat("3.14 meters long.") // 3.14 parseFloat(" 3.14 meters long.") // 3.14 parseInt("0xFF") // 255 parseInt("-0xff") // -255 parseInt(".1") // NaN parseFloat(".1") // 0.1 parseFloat("0.1") // 0.1 parseInt("0.1") // 0 parseFloat("$86.09") // NaN ~~~ ### Object to Primitive Conversions #### Object to Boolean even `new Boolean(false)` is true ~~~ > if (new Boolean(false)) console.log("hello"); hello ~~~ #### Object to String #### Object to Number #### `toString()` ~~~ {x:1, y:2}).toString() // "[object Object]" ({x:1}).toString() // "[object Object]" [1,2,3].toString() // "1,2,3" (function(x) { f(x); }).toString() // "function (x) { f(x); }" /\d+/g.toString() // "/\d+/g" (new Date()).toString() // "Wed Jul 13 2016 23:18:48 GMT+0900 (JST)" ~~~ #### `valueOf()` ~~~ ({x:1 , y:2}).valueOf(); // Object {x: 1, y: 2} ~~~ ~~~ Object.valueOf() // Object ~~~ Wrapper class defines `valueOf()` method ### type conversion (object -> primitive ) step obj ==> string : 1. toString() 2. valueOf() 3. TypeError obj ==> number : 1. valueOf() 2. toString() 3. TypeError - Array Object では valueOf() をそのまま使っても使い物にならない ~~~ 1*[1,2,3] // NaN 1*[1] // 1 1 * parseInt("1,2,3") // 1 1 * parseInt([1,2,3]) // 1 ~~~ The Date Class : the only predefined with object-string /number conversion - Date Object 以外 : valueOf first - Date Object : toString first ~~~ var now = new Date(); // undefined typeof(now) // "object" typeof(now + 1) // "string" typeof(now - 1) // "number" now == now.toString() // true now > ( now -1 ) // true ~~~ ## variable declaration ~~~ var hoge = 1; //equals to var hoge; // undefined hoge = 1; // "" ~~~ javascript variable can be int and the next string legally . ~~~ ~~~ ## Variable Scope * var でない定義は global 変数 // not strict mode ### Function Scope and Hoisting block scope `{}` : javascript にはない - block scope のある言語では、変数宣言はより小さいスコープでなされる方が良い ~~~ var scope = "glocal" ; function f(){ console.log(scope); // this is hoisting var scope = "local"; console.log(scope); } > f(); undefined local ~~~ ~~~ var scope = "global" ; function f(){ console.log(scope); } ~~~ ~~~ var hoge = 1; // hoge : (Global Object).hoge // hoge : nonconfugurable foo = 1; // foo : configurable ~~~ - deleteできる方がよくない? javascript : normal mode - 何もなしかつ変数がまだ定義されていない : global object かつ configurable - mandated : placed under the rule of another coutry global object : global variable $ \leftrightarrow $ call object : local variable - lexically scoped language: the scope of a variable can be thought of as the set of source code lines for which the variable is defined. - lex : 字句 - search(x) : variable resolution ### SCOPE CHAIN ~~~ * object * object * x ... * object ~~~ - not x in any Object in SCOPE CHAIN -> Reference Error - ES3 : call object - ES5 : declarative environment record - ES6 : receiver # expression ~~~ expression ::= constant value | variable name | expression.identifier / expression[expression] (property access expression) | {x:value,...} / [v1,v2,...] (object / array Initializer expression) | function invocation | operator combination | object creation expression `new Object` / `new Point(1,2)` ~~~ ## Primary Expressions ### reserved words ~~~ true // constant false // constant null // constant this // not constant ~~~ ### special global variable `undefined` ## Objects and Array Initializer not primary expression ? object/array initializer の式は毎回更新される Also, the property names in object literals may be strings rather than identifiers ~~~ p = {x: 1, y: 2} side = 500 var square = { "uleft" : {x : p.x, y : p.y}, 'lright' : {x: p.x + side, y : p.y + side} }; ~~~ ### function invocation ~~~ var square = function(x) { return x * x; } ~~~ の右辺がfunction literal 1. function is evaluated 2. arguments are evaluated to make a list of arguments 3. arguments are assigned 4. function body executed - javascript の配列はいろんな要素を詰め込むことができる - c だと、一つの型に絞られる - array[中身] : 中身はまずstring にconvert される ~~~ var hoge = { "he is Tom" : 1}; // undefined hoge."he is Tom"; // sytax error hoge["he is Tom"] // 1 ~~~ ## Object Creation Expression ~~~ new Object() // () can be omitted ~~~ evaluation of `new Object` : 1. create empty object `{}` // オブジェクトのための領域が確保される 2. special function をinvoke し、`new Object` を `this` の値として、special function に渡す 3. special function (constructor) はそれを初期化する 4. 2-cases - (case a) : constructor は戻り値を持たず、この `new Object` が expression の値となる // static Object - (case b) : constructor が戻り値を持つ場合、それがexpression の値となり `new Object` は捨てられる。 // instance Object ## Operator operator : 演算子には、右結合と左結合があります ~~~ 9 - 3 operand operator operand 9 - 3 - 5 をどう解釈するか 左結合  ((9 - 3) - 5 ) = 1 右結合  ( 9 - (3 - 5)) = 11 --> bad x = 3 operand operator operand x = y = 5 は右結合か左結合か? (x = y ) = 5 // left --> bad x = (y = 5 ) // right ~~~ ### Number of Operands - unary operator : 単項演算子 - binary operator : 二項演算子 - ternary operator : 三項演算子 // ? : ~~~ expr ::= ... expr * expr expr | * / \ expr expr | | * * / \ / \ e e e e ... ~~~ ~~~ compiler ( address , value ) ( left , right ) ( lval , rval ) javascript lval = rval ~~~ ### operator side effect 演算子の副作用 - assinment ( increment , decrement) - delete - (function () { Foo();// if Foo has side effect } ## precedence - function invocation > operator ## associativity ~~~ q = (a?b:(c?d:(e?f:g))); expr = expr + expr x = (1*2) + (3 *4) ~~~ quotient : 商 ~~~ 9 % 6 // 3 -9 % 6 // -3 -9 % 7 // -2 9 % 7 // 2 -9 % 7 // -2 9 % 7 // 2 6.5 % (1/3) // 0.16666666666666702 6.5 % (1/3) // = 6.5 - 6.333333333 = 0.16666666666666702 ~~~ - If either of its operand values is an object,it converts it to a primitive using the $ object-to-primitive $ algorithm described in §3.8.3: Date objects are converted by their `toString()` method, and all other objects are converted via `valueOf()`, if that method returns a primitive value. Most objects do not have a useful `valueOf()` method, however, so they are converted via `toString()` as well. - After $ object-to-primitive $ conversion,if either operand is a string, the other is converted to a string and concatenation is performed. - Otherwise, both operands are converted to numbers (or to `NaN`) and addition is performed. because + : left associativity ~~~ 1 + 2 + " blind mice"; // => "3 blind mice" 1 + (2 + " blind mice"); // => "12 blind mice" ~~~ incr / decrement ++lval / --lval - post-increment - pre-increment ~~~ x = "hello" // hello ++x; // NaN ~~~ but ~~~ x = "hello" // hello x = x + 1; // hello1 ~~~ ## bitwise operator bitwise operator expect `unsined int 32bit` ### `&` AND 小数点以下は切り捨て ~~~ (-1)&(1.1) // 1 (-1)&(1.7) // 1 ~~~ ### `^` XOR ~~~ ^ : XOR operator 排他的論理和 1 ^ 1 -> 0 0 ^ 0 -> 0 0 ^ 1 -> 1 1 ^ 0 -> 1 ~~~ ### `~` NOT ~~~ ~ : NOT operator ~~~ ### `<<` `>>` `>>>` SHIFT ~~~ << : 0 fill >> : depending on the most left bit : 符号を格納 >>> : 0 fill ~~~ ## Relational Expressions ### `==` `===` ~~~ == : check two "values" are the same ( equality ) === : check two operands are "identical" ( strict equality ) != !== ~~~ ~~~ null === null undefined === undefined true === true false === false number === number // except NaN string === string // if they contain the same 16bit values and locate in the same position object === object // if the same instance ~~~ ~~~ v1:T == v2:T // if v1 === v2 null == undefined 1 == "1" 1 == true 0 == false Object == string // if toString(Object) === string Object == number // if valueOf(Object) === number ~~~ ### Comparison Operators ~~~ "11" < "3" // true ( string ) "11" < 3 // false ( numeric ) "one" < 3 // false ( numeric ) NaN < 3 ~~~ String.localeCompare() ### `in` operator ~~~ var point = {x:1, y:2}; "x" in point; // true "z" in point; // false "toString" in point; // true var data = [7,8,9] "0" in data // true 1 in data // true 2 in data // true 7 in data // false ~~~ ### `instanceof` operator " prototype chain " : described in 6.2.2 ~~~ o instanceof f // refers `f.prototype` and look for o's "prototype chain" ~~~ ~~~ var d = new Date(); d instanceof Date; // true d instanceof Object; // true d instanceof Number; // false var a = [1,2,3]; a instanceof Array; // true a instanceof Object; // true a instanceof RegExp; // false ~~~ ### `&&` `||` `!` ### `=` : assignment ~~~ (a = b) == 0 // possible ~~~ ~~~ a op= b // a = a op b ~~~ ## `eval` Expressions ~~~ eval("3+2") 5 ~~~ `eval()` is adopted the environment where it is called ~~~ var y = 1; eval("y = 2;"); // 2 y; // 2 ~~~ ~~~ var x = 1; var a = eval("(function f() {return x+1;})()"); a // 2 ~~~ ~~~ var geval = eval; var x = "global", y = "global"; function f() { var x = "local"; eval("x += 'changed';"); return x; } function g() { var y = "local"; geval("y += 'changed';"); return y; } console.log(f(),x); console.log(g(),y); ~~~ ~~~ var x = "global" function f(){ var x = "local"; var leval = eval; var nestedreturn = (function g(){ var x = "nested"; leval("x += 'changed';"); return x; })(); return [x,nestedreturn]; } consolo.log(f(),x); ~~~ - IE では、globaleval() の代わりに execScript() がある ### `eval` in strict mode "use strict" では eval は 新しいローカル環境を構築して、跡を残さない。 ~~~ "use strict" var x = 1; eval("var x = 2;"); console.log(x) // 1 ~~~ ## Miscellaneous Operators ### `? :` ### `typeof` ~~~ typeof "globalchanged" // "string" typeof undefined // "undefined" typeof null // "object" typeof true // "boolean" typeof NaN // "number" ~~~ compare two object - instanceof - class attribute : 6.8.2 - constructor property : 6.8.1 / 9.2.2 #### function and callable object -> see Callable Objects section ### `delete` operator ~~~ delete lval ~~~ ~~~ var o = { x: 1, y: 2}; delete o.x; "x" in o // false var a = [1,2,3]; delete a[2]; a.length // 2 ~~~ ~~~ var x ; delete x ; // false function foo(){}; delete foo; // false ~~~ var o = {x:1, y:2}; delete o.x; typeof o.x; delete o.x; delete o; delete 1; this.x = 1; delete x; ### `void` ### `,` : comma operator ~~~ for(var i=0,j=10; i < j; i++,j--) console.log(i+j); ~~~ # Statements - expr : evaluated to value - stmt : executed to make something happen statement - expression statement : assignment / func invocation - decleration statement : declare value / define function javascript programs : sequence of statements these are statements - conditionals : `if` `switch` - loops : `while` , `for` - Jumps : `break`, `return` , `throw` ## expression statement stmt ::= expr with side effects ~~~ greeting = "hello" + name; counter++; delete o.x; alert(greeting); window.close(); window.open(); // Math.cos(x); // not stmt cx = Math.cos(x); ~~~ ## compound statement / empty statement `{}` : statement block : combine multiple stmt into single compound stmt ~~~ { x = Math.PI; cx = Math.cos(x); console.log("cos(π) = " + cx); } ~~~ stmt block has no scope !! e.g. sytax `while` ~~~ stmt ::= while cond stmt ~~~ here, the inner stmt has no scope the while has scope . empty stmt ~~~ ; ~~~ e.g. ~~~ for(i=0; i < a.length; a[i++]=0) ; ~~~ explicit ~~~ for( i = 0; i < a.length ; a[i++]=0) /* empty */ ; ~~~ ## Declaration Statements ~~~ stmt ::= var-stmt function-stmt ~~~ ### `var` stmt ~~~ var name_1 [ = value_1] [ ,..., name_n [= value_n]] ~~~ ~~~ var i; var j = 0; var p,q; var greeting = "hello" + name; var x = 1, y = Math.cos(2), r, theta; var x = 2, y = x*x; var x = 2, f = function(x){return x*x}, y = f(x); ~~~ ### `function` stmt ~~~ function name([arg [,arg [..., arg]]]){ stmts } ~~~ ## Conditionals ### `if` ~~~ stmt ::= if (expr) stmt if (expr) stmt else stmt ~~~ ### `switch` ~~~ stmt ::= switch(expr) { stmts } ~~~ e.g. ~~~ switch(n){ case 1: // some stmt break; case 2; // some stmt break; default; // some stmt break; } ~~~ ~~~ function convert(x) { switch(typeof x) { case 'number': return x.toString(16); case 'string': return '"' + x + '"'; default: return String(x); } } ~~~ ## Loops - `while` - `do/while` - `for` - `for/in` ### `while` #### syntax ~~~ while (expr) stmt ~~~ ### `do/while` #### syntax ~~~ do stmt while (expr) ~~~ ~~~ function printArray(a) { var len = a.length, i = 0; if (len == 0) console.log("Empty Array"); else do console.log(a[i]); while (++i < len); } ~~~ ### `for` syntax ~~~ for (init; test ; incr) stmt ~~~ equiv ~~~ init; while(test) { stmt incr; } ~~~ e.g. object in a list ~~~ function tail(o){ for (; o.next; o=o.next) ; return o; } ~~~ ### `for/in` syntax ~~~ for (variable in object) stmt ~~~ assign o's index into a ~~~ var o = {x:1, y:2, z:3} var a = [], i = 0; for(a[i++] in o) ; ~~~ ~~~ for (i in a) console.log(i); 0 1 2 ~~~ - all properties and methods are enumerable / except `toString()` method - if loop body defines new object then the object won't be enumerated. #### enumeration order follow the order in which they are defined Enumeration order depends implementaion if - enum properties - has int array index - used `delete` - used `Object.defineProperty()` (section 6.7) ## Jumps - `break` - `continue` - `throw` with `try/catch/finally` stmt - `return` ### `break` syntax ~~~ break; ~~~ ~~~ labelname: stmt ... break labelname; ~~~ ### `continue` syntax ~~~ continue; ~~~ ~~~ continue labelname; ~~~ continue in loop - while : jump to expr - do / while : jump to expr - for : jump to incr; - for / in : jump to next var ~~~ for (i=0; i < data.length; i++){ if (!data[i]) continue; total += data[i]; } ~~~ ### `return` ~~~ return expr; ~~~ ### throw ~~~ throw expr; ~~~ ### `try/catch/finally` ~~~ try{ // you can throw err ; // anywhere in try clause } catch (e) { } finally { } ~~~ funny try/finally clause ~~~ for (init; test; incr) stmt // equals init; while(test) try stmt finally incr ~~~ ## Miscellaneous Statements ### `with` syntax ~~~ with (object) stmt ~~~ ~~~ documnet.forms[0].name.value = ""; documnet.forms[0].address.value = ""; documnet.forms[0].email.value = ""; ~~~ equals ~~~ with(document.forms[0]){ name.value = ""; address.value = ""; email.value = ""; } ~~~ another way ~~~ var f = domuments.forms[0]; f.name.value = ""; f. ... f. ... ~~~ #### note ~~~ with(o) x = 1; ~~~ - if `o` has `x` -> `o.x = 1` - else -> `x = 1` `with` do not create new object !! ### `debugger` put `debugger` where you want debug ~~~ function f(o) { if (o === undefined) debegger; // ... } ~~~ Firefox has Firebug ### `use strict ` `use strict` is a $ directive $ , not $ stmt $ - provides `strict code` #### diff between $ directive $ and $ statement $ $ directive $ : an expression statement - consists of a special string literal - ecma5 see an expression statement as having some side effect. - Future version : use `use` keyword without quotations `"use script"` : only put in - start of a script - start of a function body but in function ~~~ function() { stmt // regular stmt : no side effect "use strict" stmt // has side effect } ~~~ this is possible the code passed to `eval()` is strict - if called from strict code - if the code includes "use strict" #### strict mode strict code is executed in $ strict mode $ $ strict mode $ - `with` stmt is not allowed - variables must be declared (RefError is thrown) - no-method function invoked has `this` value of `undefined` ~~~ var hasStrictMode = (function() {"use strict"; return this===undefined}()); // true ~~~ - `call()` , `apply()` invocating function has `this` value of the first argument - assignments to non-writable properties and throw a `TypeError` - creating new property on non-extensible object throw a `TypeError` - code passed to `eval()` is also strict - cannot define lvals as caller's scope - it creates new scope and discard at `eval()` returns - the `arguments` object in a function holds a static copy. - if the `delete` operator is followed by an unqualified indentifier, it throws `SyntaxError`. - delete nonconfigurable property throw `TypeError` - `SyntaxError` if object define two property by the same name. - `SyntaxError` if function declaration have 2 parameters with the same name. - octal integer literals starting with `0` not allowed - `eval` and `arguments` are treated as keyword - the ability to examine the call stack is restricted - `arguments.caller` / `arguments.callee` throw a `TypeError` in strict mode function - strict mode functions have `caller` / `arguments` throwing `TypeError`. ## Summary | statement | Syntax | Porpose | | :--- | :--- | :--- | | break | `break [label]` | | | case | `case expr: ` | Label a stmt within `switch` | | continue | `continue [label];` | | | debugger | `debugger;` | | | default | `default:` | Label a stmt within `switch` | | do/while | `do stmt while (expr);` | | | empty | `;` | | | for | `for(init; test; incr) stmt` | | | for/in | `for (var in obj) stmt` | | | function | `function name([param[, ...]]){ body }` | | | if/else | `if (expr) stmt1 [else stmt2]` | | | label | `label: stmt` | | | return | `return [expr];` | | | switch | `switch (expr) {stmt}` | Multiway branch to `case`/`default` | | throw | `throw expr` | | | try | `try {stmt} [catch {handler stmt}] [finally [cleanup stmt]]` | Handle exceptions | | use strict| `"use strict"` | | | var | `var name [ = expr ] [, ...]; ` | | | while | `while (expr) stmt` | | | with | `with (obj) {stmt}` | | # Objects object : an un-ordered collection of properties objects map strings into values ~~~ object = { str1 : value1, str2 : value2, str3 : value3, ... } ~~~ prototype : the super object property attribute : - `writable` attribute : whether the value can be set - `enumerable` attribite : whether it can be called by `for/in loop iterations` - `confiurable` attribute : whether it can be deleted, and whether its attributes can be changed object attributes : - prototype : reference to another object - class : a string storing object type - extensible : whether new properties can be added 3 object types : - a native object : - originally defined in ECMA - `Array` , `function` , `Date` , `RegExp` - a host object : - defined by the host environments - HTMLElements objects - a user-defined object : 2 property types : - an own property : defined in this - an inherited property : defined in prototype ## Creating Object | object creation | prototype | | :---: | :---: | | object literal | `Object.prototype` | | `new Constructor()` | `Constructor.prototype` | | `Object.create(proto)` | `proto` | Object.prototype : do not have prototype prototype chain : (継承?)の鎖 ### Object Literals just write $ object literal $ - property name : `identifier` or `string literal` - property value : expr (any) - reserved words can be used without quoting (ES5) - ".." : trailing comma ; > ES3 ==> ignored (IE error) ### `new` ~~~ var o = new Object() var a = new Array() var d = new Date(); var r = new RegExp(); ~~~ ### `Object.create()` ~~~ Object.create(prototype[, ..]) ~~~ ~~~ var o1 = Object.create({x:1, y:2}) var o2 = Object.create(null) // no inheritance ; even toString not inherited var o3 = Object.create(Object.prototype) // o3 is like {} ~~~ ~~~ function inherit(p) { if (p == null) throw TypeError(); if (Object.create) return Object.create(p); var t = typeof p; if (t !== "object" && t !== "function") throw TypeError(); function f() {}; f.prototype = p; return new f(); } ~~~ // this cannot handle null prototype // no 2nd arguments ~~~ var o = {x : "don't change this value"}; using_library_function(inherit(o)) ~~~ ## Query / Set Properties ### query ~~~ var title = book["main title"] // get the "main title" property of the book ~~~ ~~~ o["for"] // if you access to reserved word propertyName ~~~ [expr*] where - expr* : evaluated to or converted to a string #### Objects As Associative Arrays these are the same ~~~ object.property object["property"] // associative array ~~~ e.g. ~~~ var addr = ""; for (i=0; i < 4; i++) { addr += customer["address" + i ] } ~~~ ~~~ function addstock(portfolio, stockname, shares) { portfolio[stockname] = shares; } ~~~ ~~~ function getvalue(portfolio) { val total = 0.0; for (stock in portfolio) { var shares = portfolio[stock]; var price = getquote(stock); // a function which look up share price total += shares * price; } return total; } ~~~ ### set #### Inheritance ~~~ var o = {} o.x = 1; var p = inherit(o); p.y = 2; var q = inherit(p); q.z = 3; var s = q.toString(); q.x + q.y ~~~ ~~~ Object {z: 3} z: 3 __proto__: Object y: 2 __proto__: Object x: 1 __proto__: Object __defineGetter__: function __defineGetter__() __defineSetter__: function __defineSetter__() __lookupGetter__: function __lookupGetter__() __lookupSetter__: function __lookupSetter__() constructor: function Object() hasOwnProperty: function hasOwnProperty() isPrototypeOf: function isPrototypeOf() propertyIsEnumerable: function propertyIsEnumerable() toLocaleString: function toLocaleString() toString: function toString() valueOf: function valueOf() get __proto__: function __proto__() set __proto__: function __proto__() ~~~ #### override ~~~ var unitcircle = {r:1}; var c = inherit(unitcircle); c.x = 1; c.y = 1; c.r = 2; // override unitcircle.r; ~~~ if `r` is an accessor property with a setter , setter method is called ==> see Getters / Setters section #### Property Access Errors ~~~ var o = {}; o.x // undefined o.y.a // TypeError Exception : undefined dont have property ~~~ let's avoid Exception with ; ~~~ if (o) if (o.y) v = o.y.a ~~~ or ~~~ var v = o && o.y && o.y.a ~~~ because ~~~ true && 123 // 123 true && "hey" // "hey" true && {s:1} // Object {s:1} ~~~ - `Object.prototype` is unchanged ~~~ Object.prototype = 0; // unchanged (fails) ~~~ property assignments fails - read-only property - except `defineProperty()` method configuring read-only property - inherited read-only property - not own property : not extensible property ## `delete` Properties delete property ~~~ delete o.p; delete o["p"]; ~~~ delete inherited property ==> delete @ prototype object e.g. - true ~~~ o = {x:1}; delete o.x; delete o.x; // do Nothing delete o.toString; // do Nothing delete 1; // Nonsense ~~~ - false ~~~ delete Object.prototype; // (non-configurable property) var x = 1; delete this.x; // cannot delete this property function f() {}; delete this.f; ~~~ ### configurable global property ~~~ this.x = 1; delete x; // true //@strict mode delete x; // SyntaxError delete this.x; // true ~~~ ## test Properties check with ### `in` operator ~~~ var o = {x:1} "x" in o ; // true "y" in o ; // false "toString" in o; // true ~~~ ### `hasOwnProperty()` method of an object - return `false` of inherited property ~~~ var o = { x: 1} o.hasOwnProperty("x"); o.hasOwnProperty("y"); o.hasOwnProperty("toString"); // false ~~~ ### `propertyIsEnumerable()` ~~~ var o = inherit({y:2}); o.x = 1; o.propertyIsEnumerable("x"); // true o.propertyIsEnumerable("y"); // false: inherited object ~~~ ### `in` alternatives ~~~ var o = {x:1}; o.x !== undefined; // true o.y !== undefined; // false o.toString !== undefined // true ~~~ note! ~~~ var o = {x:undefined } o.x !== undefined; // false ~~~ ## Enumerating Properties ~~~ var o = {x:1, y:2, z:3}; for (p in o) console.log(p); // prints: x y z ~~~ "toString" is not printed basically because it it not enumerate ### explicitly guard ~~~ for (p in o) { if (!o.hasOwnProperty(p)) continue; // skip inherited properties console.log(p); } ~~~ ### skipping methods ~~~ for (p in o) { if (typeof o[p] === "function") continue; // skip methods console.log(p); } ~~~ ### `merge()` ~~~ function merge(o,p) { for (prop in p) { if (o.hasOwnProperty[prop]) continue; o[prop] = p[prop]; } return o; } ~~~ ### `restrict()` ~~~ /* remove properties from o which p does not have */ function restrict(o,p) { for (prop in o) { if (!(prop in p)) delete o[prop]; } return o; } ~~~ ### `subtract()` ~~~ function subtract(o,p) { for (prop in o) { if (prop in p) delete o[prop]; } return o; } ~~~ ### `union()` ~~~ // if o & p has the same name property , o preceeds. function union(o,p) {return extebd(extend({},o),p)}; ~~~ ### `keys()` ~~~ /* * return an array that holds the name list of enumerable own properties */ function keys(o) { if (typeof o !== "object") throw TypeError(); var result = []; for (var prop in o) { if (o.hasOwnProperty(prop)) result.push(prop); } return result } ~~~ or use - `Object.keys()` : list of all own enumerable properties - `Object.getOwnPropertyNames()` : list of all own properties ## Getters / Setters property : - data property : simple value - accessor property : defined by `setter/getter` ### syntax ~~~ var o = { data_prop: value, get access_prop(){}, set access_prop(value){} }; ~~~ ### e.g. ~~~ var p = { x: 1.0, y: 1.0, // r is read & writable get r() { return Math.sqrt(this.x*this.x + this.y*this.y)}, set r(newvalue) { var oldvalue = Math.sqrt(this.x*this.x + this.y*this.y); var ratio = newvalue/oldvalue; this.x *= ratio; this.y *= ratio; }, // theta is read-only get theta() {return Math.atan2(this.y, this.x);} } ~~~ ### e.g. `random` ~~~ var random = { get octet() {return Math.floor(Math.random()*256);}, get uint16() {return Math.floor(Math.random()*65536);}, get int16() {return Math.floor(Math.random()*65536)-32768;} } ~~~ ## Property Attributes - ES3 : all properties are writable - ES5 : has API : property descriptor - enumerable property - configurable property - query : `Object.getOwnPropertyDescriptor(obj,prop)` - set : `Object.defineProperty(obj,prop, propDesc)` 4 attributes of data property : `propertyDescriptor`'s property - `value` - `writable` - `enumerable` - `configurable` 4 attributes of accessor property : - `get` - `set` - `enumerable` - `configurable` ### query property descriptor object : ~~~ > Object.getOwnPropertyDescriptor({x:1},"x" ) Object { value: 1, writable: true, enumerable: true, configurable: true } ~~~ ~~~ > Object.getOwnPropertyDescriptor(this, "Window") Object { value: function Window() writable: true, enumerable: false, configurable: true } ~~~ ~~~ > Object.getOwnPropertyDescriptor(random,"octet"); Object { set: undefined, enumerable: true, configurable: true } // undefined in inherited property Object.getOwnPropertyDescriptor({},toString); undefined ~~~ #### query the attributes of inherited properties `Object.getPrototypeOf()` : ~~~ Object.getOwnPropertyDescriptor(Object.getPrototypeOf({}),"toString") Object { writable: true, enumerable: false, configurable: true } ~~~ ### set `Object.defineProperty(obj,prop,propDesc)` : ~~~ var o = {}; Object.defineProperty(o, "x", { value: 1, writable: true, enumerable: false, configurable: true } ) > Object.keys(o) [] // "x" is not enumerable Object.defineProperty(o, "x", {writable: false}); o.x = 2; // fails silently Object.defineProperty(o, "x", {value: 3}); o.x // 3 Object.defineProperty(o, "x", {get: function() {return 0;}}) o.x // 0 ~~~ `Object.defineProperties(obj,{prop1: dscrptr1 [,...]})` : ~~~ var p = Object.defineProperties({}, { x: {value:1, writable: true, enumerable: true, configurable: true}, y: {value:2, writable: true, enumerable: true, configurable: true}, r: { get: function() {return Math.sqrt(this.x*this.x + this.y * this.y)}, enumerable: true, configurable: true } }); ~~~ `Object.create(obj, {prop1: dscr1 [,...] })` : ~~~ Object.create({}, { o: {value: 0, writable: false}, x: {value: 1, writable: true}, y: {value: 1, writable: true}, r: {get: function(){return Math.sqrt(this.x*this.x + this.y * this.y)} } }) ~~~ if these attempts failed , then throw `TypeError` - `nonwritable && configurable` ==> can change value - `nonconfigurable` ==> can change `writable` to `nonwritable` rule of throwing `TypeError` - an `object` is not `extensible` ==> you cannot add new property - a `property` is not `configurable` ==> cannot change `configurable` and `enumerable` - an `accessor property` is not `configurable` ==> cannot change `getter/setter` and cannot change it to data property - a `data property` is not `configurable` ==> cannot change it to an `accessor property` - a `data property` is not `configurable` ==> cannot change `nonwritable` to `writable` - a `data property` is not `configurable` and not `writable` ==> cannot change its `value` #### e.g. `extend()` ~~~ Object.defineProperty(Object.prototype, "extend", { writable: true, configurable: true, enumerable: false, value: function(o) { var names = Object.getOwnPropertyNames(o); for (var i=0; i < names.length; i++) { if (names[i] in this) continue; var desc = Object.getOwnPropertyDescriptor(o,names[i]); Object.defineProperty(this, names[i], desc); } } }); ~~~ ### Legacy API for Getters and Setters before ES5 there are - `__lookupGetter__()` - `__lookupSetter__()` - `__defineGetter__()` - `__defineSetter__()` ## Object Attributes object has 3 attributes - prototype - extensible - class ### The `prototype` attribute `Object.getPrototypeOf()` : get that ~~~ var p = {x:1}; var o = Object.create(p); p.isProtitypeOf(o) Object.prototype.isPrototypeOf(o) ~~~ every object has __proto__ and it is the prototype object ~~~ obj.__proto__ // prototype object of obj ~~~ e.g. ~~~ Object.create(({}).__proto__); // create {}'s brother object ~~~ ### The `class` Attribute class attribute : a string that provides information about the type of the object. like; `[object class]` : `toString()` method returns the class ~~~ > this.toString(); "[object Window]" ~~~ ~~~ function classof(o) { if (o === null) return "Null"; if (o === undefined) return "Undefined"; return Object.prototype.toString.call(o).slice(8,-1); } ~~~ ~~~ classof(null) // "Null" classof(1) // "Number" classof("") // "String" classof(false) // "Boolean" classof({}) // "Object" classof([]) // "Array" classof(/./) // "RegExp" classof(new Date()) // "Date" classof(window) // "Window" function f() {}; classof(new f()) // "Object" ~~~ ### The `extensible` Attributes `Object.preventExtensions(obj)` : - prevent Extensions - `Object.isExtensible(obj)` `Object.seal(obj)` : - prevent Extensions - make no-configurrable - There is no way to unseal - `Object.isSealed()` `Object.freeze()` : - prevent Extensions - make no-configurrable - make all of its own data read-only - `Object.isFrozen()` ~~~ var o = Object.seal(Object.create(Object.freeze({x:1}),{y: {value:2, writable: true}})) ~~~ ## Serializing Objects ~~~ o = {x:1, y: {z:[false,null,""]}} s = JSON.stringify(o); p = JSON.parse(s); ~~~ `JSON.stringify(obj)` : - serialize - object ==> string `JSON.parse(str)` : - restore - string ==> object can be serialized - objects - arrays - strings - finite numbers - `true` / `false` - `null` serialized to `null` - `NaN` - `Infunity` / `-Infinity` Date objects ==> ISO-formatted date - `(new Date()).toJSON()` - cannot be restored - `JSON.parse((new Date().toJSON()))` ==> SyntaxError cannot be serialized - Date object - Function - RegExp - Error objects - `undefined` ## Object Methods Object Methos : methods defined on `Object.prototype` ### `toString()` ~~~ > var s = {x:1}.toString() > s [object Object] ~~~ Object class do nothing toString() method is active on; e.g.; - Array - Date - Function ### `toLocaleString()` purpose : return a localized string representation - default: do nothing - `Date` / `Number` classes are defined ### `toJSON()` `Object.prototype` does not actually define a `toJSON()` method, if `toJSON()` method is defined, `JSON.stringify()` method returns the `toJSON` method. e.g. ~~~ var o = {x:1} JSON.stringify(o) // "{"x":1}" o.toJSON = function (){ return "hello"}; JSON.stringify(o) // ""hello"" ~~~ ### `valueOf()` like `toString` but not string case e.g. ~~~ (new Date()).valuOf() // 1474540023924 ~~~

# Arrays Array : - an ordered collection of values - each value is called $ element $ - each element has $ index $ : numeric position - 32-bit index ( $ 0 $ ~ $ 4294967294 $ ( $ 2^{32} - 2 $ ) ) - dynamic (needless to declare the size) - `length` property - sparse array is possible sparse array ~~~ x = []; x[1] = 1; x[100] = 100; x.length // 101 ~~~ - specialized form of class `Object` - inherit from `Array.prototype` ## Creating Arrays - array literal : `a = []` - array constructor : `new Array()` ~~~ var empty = []; var primes = [2,3,5,7,11]; var misc = [ 1.1, true, "a"] // various type possible var base = 100 var table = [base, base+1, base+2, base+3]; var count = [1,,,,,6] // [1, undefined × 4, 6] var a = new Array(10) // [undefined × 10] var b = new Array(5,4,3,2,1, "testing") // [5, 4, 3, 2, 1, "testing, testing"] ~~~ ## Reading and Writing Array Elements javascript interprets : - numeric index ==> string index - $ \quad $ `1` $ \quad \quad \mapsto \quad \quad $ `"1"` Array is Object so !? ~~~ hogehoge = []; // [] hogehoge["hoge"] = "fuga" // "hoge" is not index but property hogehoge.length // so the length is 0 ~~~ Array | Object ------|--------- index | property index is the range of "0" ~ " $ 2 ^ {32} $ " Oh my god ! there is no python syntax !! ~~~ a = []; a[-1] = -1; a.length; // 0 ~~~ ## Sparce Array ~~~ var a1 = [,,,] var a2 = new Array(3) 0 in a1 0 in a2 ~~~ ES5 ==> true / false ES6 ==> false / false ? ## Array Length dangerous array length it's writable !!! ~~~ var a = [1,2,3,4,5] a.length = 3; // a is now [1,2,3] a.length = 0; // delete all ==> a is [] a.length = 5; // no longer there exists elements ~~~ so ~~~ a = [1,2,3]; Object.defineProperty(a, "length", {writable: false}); a.length = 0; // a is [1,2,3] ~~~ ## Adding and Deleting Array Elements just assign ~~~ a = []; a[0] = "zero" a[1] = "one" ~~~ ### `push()` ~~~ a = []; a.push("zero"); // 1 a.push("one","two"); // 3 a; // ["zero", "one", "two"] ~~~ ### `pop()` ~~~ a.pop() // "two" ~~~ ### `shift()` ~~~ a; // ["zero", "one"] a.shift() // "zero" a; // ["one"] ~~~ ### `unshift()` ~~~ a.unshift("zero"); // 2 a; // ["zero", "one"] ~~~ ### `splice()` ~~~ a // ["zero", "one", "two", "three", "four"] a.splice(2,3); // ["two", "three", "four"] a // ["zero", "one"] ~~~ ### `slice()` ~~~ var a = [1,2,3,4,5] a.slice(3,4) // [4] a.slice(2) // [3,4,5] a.slice(-3, -1) // [3,4] ~~~ ## Iterating Arrays `Object.keys(obj)` : return array of object's property name list ~~~ var keys = Object.keys(o) ~~~ `keys[]` / `values[]` ~~~ var keys = Object.keys(o); var values = [] for (var i = 0; i < keys.length; i++) { var key = keys[i]; values[i] = o[key] } ~~~ ~~~ for (var i = 0, len = keys.length; i < len ; i++) ~~~ ~~~ if (!a[i]) continue; // exclude null / undefined if (a[i]===undefined) continue; // exclude undefined if (!(i in a)) continue; // this do not exclude undefined ?? ES6 ?? if (!a.hasOwnProperty(i)) continue; // skip inherited properties if (String(Math.floor(Math.abs(Number(i)))) !== i) continue; // skip if not non-negative integer ~~~ - | lval | rval ------|------|------ Object| key | value Array | num | value ~~~ var data = [1,2,3,4,5]; var sumOfSquares = 0; data.forEach(function(x) { sumOfSquares += x*x; }) sumOfSquares 55 ~~~ ## Multidimensional Arrays Create a multidimensional array ~~~ var table = new Array(10); for (var i = 0; i < table.length; i++) { table[i] = new Array(10); } // Initialize for (var row = 0; row < table.length; row++) { for (var col = 0; col < table[row].length; col++){ table[row][col] = row * col } } // Use the multidimensional array var product = table[5][7] // 35 ~~~ ## Array Methods if you want to see all methods ~~~ > Object.create(Object.getPrototypeOf(new Array)) Array {} __proto__: Array[0] concat: concat() constructor: Array() copyWithin: copyWithin() entries: entries() every: every() fill: fill() filter: filter() find: find() findIndex: findIndex() forEach: forEach() includes: includes() indexOf: indexOf() join: join() keys: keys() lastIndexOf: lastIndexOf() length: 0 map: map() pop: pop() push: push() reduce: reduce() reduceRight: reduceRight() reverse: reverse() shift: shift() slice: slice() some: some() sort: sort() splice: splice() toLocaleString: toLocaleString() toString: toString() unshift: unshift() Symbol(Symbol.iterator): values() Symbol(Symbol.unscopables): Object __proto__: Object ~~~ ### `join()` ~~~ var a = [1,2,3] a.join // "1,2,3" a.join("") // "123" a.join(" ") // "1 2 3" var b = new Array(10); b.join("-") // "----------" 9 hyphens ~~~ ### `reverse()` ### `sort()` ~~~ var a = [33,4,111,2222,55555] a.sort() // Alphabetical order a.sort(function(a,b){return a-b}) ~~~ ~~~ var a = [33,4,111,2222,55555] a.sort() // Alphabetical order a.sort(function(a,b){ if (a == 2222 || b == 2222) return 1; return -1 }) [2222, 111, 33, 4, 55555] ~~~ ~~~ var items = [ { name: 'Edward', value: 21 }, { name: 'Sharpe', value: 37 }, { name: 'And', value: 45 }, { name: 'The', value: -12 }, { name: 'Magnetic' }, { name: 'Zeros', value: 37 } ]; // sort by value items.sort(function (a, b) { if (a.value > b.value) { return 1; } if (a.value < b.value) { return -1; } // a must be equal to b return 0; }); // sort by name items.sort(function(a, b) { var nameA = a.name.toUpperCase(); // ignore upper and lowercase var nameB = b.name.toUpperCase(); // ignore upper and lowercase if (nameA < nameB) { return -1; } if (nameA > nameB) { return 1; } // names must be equal return 0; }); ~~~ ### `concat()` ~~~ var a = [1,2,3]; a.concat(4,5); // [1, 2, 3, 4, 5] a.concat([4,5]) // [1, 2, 3, 4, 5] a.concat([4,5],[6,7]) // [1, 2, 3, 4, 5, 6, 7] a.concat(4,[5,[6,7]]) // [1, 2, 3, 4, 5, [6, 7]] ~~~ ### `toString()` / `toLocalString()` ## ES5 array method ### `forEach()` ### `map()` ### `filter()` ### `every()` / `some()` this is $ \forall $ / $ \exists $ ~~~ [1,2,3].every(function(x){return x < 10;}) // true [1,2,3].every(function(x){return x%2 === 0})// false [1,2,3].some(function(x){return x < 10;}) // true [1,2,3].some(function(x){return x%2 === 0})// true ~~~ ### `reduce()` / `reduceRight()` these are `foldl` and `foldr` ~~~ var a = [1,2,3,4,5] var sum = a.reduce(function(x,y){return x+y}); ~~~ e.g. see 6.2 (`union`) ~~~ var objects = [{x:1}, {y:2}, {z:3}]; var merged = objects.reduce(union); ~~~ ### `indexOf()` / `lastIndexOf()` ~~~ a = [0,1,2,3,2,1,0] a.indexOf(2); // 2 a.lastIndexOf(2); // 4 a.indexOf(4); // -1 (means false) ~~~ ## Array Type ES5 ~~~ Array.isArray([]) // true Array.isArray({}) // false ~~~ no good e.g. ~~~ [] instanceof Array // not better for Array ~~~ In ES3; ~~~ var isArray = Function.isArray || function(o) { return typeof o === "object" && Object.prototype.toString.call(o) === "[object Array]" } ~~~ ## Array-Like Objects Diffs from Object - auto-updating length property - Setting length to a smaller value truncates the array. - inherit methods from Array.prototype - has a class attrubute of "Array" ~~~ a = [1,2,3] JSON.stringify(a); "[1,2,3]" a = {} JSON.stringify(a); "{}" ~~~ make array-like object ~~~ var a = {}; for (var i = 0; i < 10; i++){ a[i] = i*i; } a.length = i; ~~~ ~~~ Array.prototype.join.call(a,"+"); // "0+1+4+9+16+25+36+49+64+81" Array.prototype.slice.call(a, 0) // [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] Array.prototype.map.call(a, function(x) { return Math.sqrt(x); }) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] ~~~ ## Strings As Arrays ### `str.charAt(n)` equals `str[n]` ~~~ var s = "test"; s.charAt(0); // "t" s[1] // "e" ~~~ ### filtering string ~~~ s = "Javascript"; Array.prototype.join.call(s, " ") ~~~ ~~~ Array.prototype.filter.call(s, function(x){ return x.match(/[^aeiou]/); }).join("") ~~~


# function - method : if a function is the property of an object - constructor : a special method - invocation context : `this` value : the object through which a function is called - closure : closed in scopes ## Defining Functions - function definition expression - `var f = function(){}` - `var f = function g() {}` - function declaration statement - `function f (){}` - hoisted the top of the scope : enables function call before declaration - not true statement : - allowed only in top-level statement - not allowed in `loops` / `try/catch` / `with stmt` e.g. ~~~ function printprops(o) { for (var p in o) console.log(p + ": " + o[p] + "\n"); } // return undefined var f = function fact(x) { if (x <= 1) return 1; else return x * fact(x-1); }; // function name is useful for recursion function hypotenuse(a,b) { function square(x) {return x*x;} return Math.sqrt(square(a) + square(b)); } // nested ~~~ ## Invoking Functions 4 ways of invoking function - as function - as method - as constructor - indirectly (`call()` / `apply()`) - jQuery's `$()` is function name ### Function invocation function invocation context ( not method ) - not strict mode : `global object` - strict mode : `undefined` ~~~ // are you in strict mode ? var strict = (function() {return !this;}()) ; ~~~ ### Method Invocation ~~~ o["m"]() // where m is function f().m() // apply m() to the return value of f() ~~~ Method Chaining ~~~ // Find all headers, map to their ids, convert to an array and sort them $(":header").map(function() { return this.id }).get().sort(); // another example shape.setX(100).setY(100).setSize(50).setOUtline("red").setFill("blue").draw() ~~~ don't confuse - method chaining - constructor chaining `this` : keyword , not variable - cannot assign a value to it ### Constructor Invocation ~~~ var o = new Object(); var o = new Object; ~~~ ### Indirect Invocation both methods allow you to explicitly specify the `this` value for the invocation, you can invoke any function as a method of any method with - `call()` - `apply()` see 8.7.3 ## Function Arguments and Parameters - no check # of args ### Optional Parameters invoked with less args ~~~ function getPropertyNames(o, /* optional */ a) { if (a===undefined) a = []; for (var prop in o) a.push(prop); return a; } var a = getPropertyNames(o); getPropertyNames(p,a) ~~~ ~~~ a = a || []; // if (a===undefined) a = []; ~~~ ### Variable-Lenth Argument Lists : `The Arguments Object` The Arguments Object : array-like object ~~~ function f() { for (var i = 0; i< arguments.length;i++) console.log(arguments[i]); } ~~~ ~~~ > f(1,"hello",3,2); 1 hello 3 ~~~ ~~~ function max() { var max = Number.NEGATIVE_INFINITY; for (var i = 0; i < arguments.length; i++) if (arguments[i] > max) max = arguments[i]; return max; } ~~~ ~~~ > max(1,2,5,4,3) 5 ~~~ 3 names of function whose arguments length can change - variadic functions - variable arity functions - varargs functions ~~~ function f(x) { console.log(x); arguments[0] = null; console.log(x); } ~~~ ~~~ > f(9); 9 null undefined // return value ~~~ #### `callee` / `caller` properties @ no Strict mode - `arguments.callee()` : the function - `argumetns.caller()` : the caller function ~~~ var factorial = function(x) { if (x <= 1) return 1; return x * arguments.callee(x-1) } ~~~ ### Using Object Properties As Arguments a function with many arguments ~~~ function arraycopy(from, from_start, to, to_start, length){ // body } ~~~ wrap it with one arg ~~~ function easycopy(args){ arraycopy( args.from, args.from_start, args.to, args.to_start, args.length) } ~~~ then use it ~~~ > var a = [1,2,3,4], b = []; > easycopy({from: a, to: b , length 4}); ~~~ ### Argument Types this section is ridiculous. no need to read. ## Function As Values ~~~ > var o = {f: function(x){return x*x}, x: 3} > o.f(o.x); // 9 ~~~ ~~~ > var a = [function(x) {return x+x*x}, 20]; > a[0](a[1]); // 420 ~~~ ~~~ var operators = { add: function(x,y) {return x+y}, sub: function(x,y) {return x-y}, mul: function(x,y) {return x*y}, div: function(x,y) {return x/y}, pow: Math.pow } function operate2(op, operand1, operand2){ if (typeof operators[op] === "function"){ return operators[op](operand1, operand2); } else throw "unknown err"; } ~~~ ~~~ var j = operate2("add", 2, 3); // 5 ~~~ ### function property ~~~ f.counter = 0; function f() { console.log("this function is called " + ++f.counter + " times."); } ~~~ ~~~ function factorial(n) { if (isFinite(n) && n > 0 && n==Math.round(n)){ if (!(n in factorial)) factorial[n] = n * factorial(n-1); return factorial[n] } else return NaN; } factorial[1] = 1; // initialization ~~~ ## Function As Namespaces it is sometimes useful to define a function simply to act as a temporary namespace in which you can define variables without polluting global variables ~~~ function mymodule() { // Module code goes here. // Any variables used by the module are local to this function } mymodule(); (function(){ // module code goes here })(); ~~~ e.g. ~~~ var extend = (function(){ for (var p in {toString:null}) { return function extend(o) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var prop in source) o[prop] = source[prop]; } return o; }; } return function patched_extend(o) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var prop in source) o[prop] = source[prop]; for (var j=0; j < protoprops.length; j++) { prop = protoprops[j]; if (source.hasOwnProperty(prop)) o[prop] = source[prop]; } } return o }; var protoprops = ["toString","valueOf", "constructor", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "toLocaleString"]; }) o = {x:1} // Object {x: 1} p = extend()(o,{y:2,z:3}); // Object {x: 1, y: 2, z: 3} ~~~ ## Closures Javascript uses lexical scope Lexical Scope : - the variable scope that is in effect when they are defined - not variable scope that is in effect when they are invoked ~~~ var scope = "global variable"; function checkscope() { var scope = "local scope"; function f(){ return scope; } return f(); } checkscope(); // "local scope" ~~~ ~~~ var scope = "global scope"; function checkscope() { var scope = "local scope"; function f() { return scope;} return f; } checkscope()(); // what happens ? ~~~ The nested function `f()` was defined under a scope chain in which the variable scope was bound to the value "local scope". so, `checkscope()()` returns `"local scope"` this is the surprising and powerful nature of closures: they capture the local variable bindings of the outer function within which the are defined.
~~~ var uniqueInteger = (function() { var counter = 0; return function() {return counter++;}; })(); uniqueInteger(); // 0 uniqueInteger(); // 1 uniqueInteger(); // 2 ~~~ Once the outer anonymous function returns, no other code can see the counter variable. the inner function has exclusive access to it .
~~~ function counter() { var n = 0; return { count: function() { return n++; }, reset: function() { n = 0; } }; } c = counter(); d = counter(); c.count() // 0 c.count() // 1 d.count() // 0 d.count() // 1 c.reset() // undefined c.count() // 0 d.count() // 2 ~~~
property getter / setter ~~~ function counter(n) { return { get count() { return n++; }, // property getter method set count(m) { // property setter method if (m >= n) n = m; else throw Error("count can only be set to a larger value") } } } a = counter(1000); // Object {} a.count // 1000 a.count // 1001 a.count // 1002 a.count = 2000; // 2000 a.count // 2000 a.count = 2000; // Error: count can only be set to a larger value(…) ~~~
e.g. make Private property ~~~ function addPrivateProperty(o, name, predicate){ var value; o[ "get" + name ] = function(){ return value; }; o[ "set" + name ] = function(v){ if (predicate && !predicate(v)) throw Error("set" + name + ": invalid value " + v); else value = v; }; } var o = {}; addPrivateProperty(o,"Name",function(x){ return typeof x == "string"; }); o.setName("Frank"); o.getName(); // "Frank" ~~~
~~~ function constfunc(v) { return function(){return v;};} c = constfunc("c"); c() // "c" c() // "c" var funcs = []; for (var i = 0; i < 10; i++) funcs[i] = constfunc(i); funcs[1]() // 1 funcs[2]() // 2 ~~~
~~~ function constfuncs() { var funcs = []; for (var i = 0; i < 10; i++) funcs[i] = function(){ return i;}; return funcs ; } var funcs = constfuncs(); funcs[5]() // what does this return ? ~~~ Answer = 10 . because; ~~~ ... funcs[4]; // function() {return i;} funcs[5]; // function() {return i;} funcs[6]; // function() {return i;} ... ~~~ and `i` refers now `10`. #### this in closure later will see ; ~~~ var self = this, boundArgs = arguments; ~~~ e.g. ~~~ if (!Function.prototype.bind) { Function.prototype.bind = function(o /*, args */) { var self = this, boundArgs = arguments; var args = [], i; for(i = 1; i < boundArgs.length; i++) args.push(boundArgs[i]); for(i = 0; i < arguments.length; i++) args.push(arguments[i]); return self.apply(o, args); }; }; } ~~~ ## Function Properties, Methods, and Constructor ### The length Property ~~~ function (){ arguments.length // the # of args arguments.callee.length // the # of args that the function expects } ~~~ 3.g. ~~~ function check(args) { var actual = args.length; var expected = args.callee.length; if (actual !== expected) throw Error("Expected " + expected + "args; got " + actual); } function f(x,y,z) { check(arguments); return x + y + z; } ~~~ ### The prototype Property $ \forall $ function has prototype ### `call()` / `apply()` `f.apply(o,args)` ~~~ f.call(o) // invoke f() as a method of o f.apply(o) // invoke f() as a method of o ~~~ behaves like; ~~~ o.m = f; o.m(); delete o.m; ~~~ `apply` can take `array[]` as arguments ~~~ o = {} f.call(o, 1,2,3) f.apply(o,[1,2,3]) // takes array ~~~ ~~~ array = [12,23,3,4,5] Math.max(array); // Error Math.max.apply(Math, array); // 23 ~~~ e.g. overwrite method as verbose one ~~~ function trace(o,m) { var original = o[m]; o[m] = function() { console.log(new Date(), "Entering:", m); var result = original.apply(this, arguments); console.log(new Date(), "Exiting:", m); return result; }; } > trace(Math,"max"); // undefined > Math.max(1,2,3); Wed Nov 23 2016 20:56:47 GMT+0900 (JST) "Entering:" "max" Wed Nov 23 2016 20:56:47 GMT+0900 (JST) "Entering:" "max" Wed Nov 23 2016 20:56:47 GMT+0900 (JST) "Exiting:" "max" Wed Nov 23 2016 20:56:47 GMT+0900 (JST) "Exiting:" "max" ~~~ ### `bind()` 1. bind a function to an object 2. execute function 3. delete it ~~~ function f(y) { return this.x + y} var o = {x:10} var g = f.bind(o); g(2); // 3 ~~~ #### e.g. curry - like function ~~~ var sum = function(x,y) {return x+y} var succ = sum.bind(null, 1); ~~~ ~~~ function f(y,z) { return this.x + y + z } var g = f.bind({x:1},2); g(3) ~~~ #### ES3 add `Function.prototype.bind` ~~~ if (!Function.prototype.bind) { Function.prototype.bind = function (o /*,args */) { var self = this, boundArgs = arguments; return function() { var args = [], i; for(i = 1; i < boundArgs.length; i++) args.push(boundArgs[i]); for(i = 0; i < boundArgs.length; i++) args.push(arguments[i]); return self.apply(o, args); }; }; } ~~~ ### `toString()` built-in typically returns "[native code]" ### Constructor ~~~ var f = new Function("x", "y", "return x*y"); ~~~ - `Function()` constructor allows Javascript functions to be dynamically created and compiled at runtime - `Function()` constructor parses the function body and creates a new function object each time it is called. - so do not use in loops - `Function()` do not create "lexical-scope" functions ### Callable Objects - all functions are callable Object. - all callable Objects are not funcions. e.g. - `Window.alert()` - `getElementById()` - `RegExp Objects` - typeof is sometimes bad for RegExp so, define ~~~ function isFunction(x) { return Object.prototype.toString.call(x) === "[object Function]"; } ~~~ ## Functional Programming ### `[].map()` / `[].reduce()` ~~~ var sum = function(x,y) {return x+y}; var square = function(x) {return x*x}; var data = [1,1,3,5,5,6,7,7]; var mean = data.reduce(sum)/data.length; var deviations = data.map(function(x){return x-mean;}); var stddev = Math.sqrt(deviations.map(square).reduce(sum)/(data.length-1)); ~~~ #### ES3 `map()` / `reduce()` ~~~ var map = Array.prototype.map ? function(a,f) {return a.map(f);} : function(a,f) { var results = []; for (var i = 0, len = a.length; i < len; i++){ if (i in a) results[i] = f.call(null,a[i],i,) } } ~~~ ~~~ var reduce = Array.prototype.reduce ? function(a,f,initial) { if (arguments.length > 2) return a.reduce(f,initial); else return a.reduce(f) } : function(a,f,initial){ var i = 0, len = a.length, accumulator; if (arguments.length > 2) accumulator =initial; else { if (len == 0) throw TypeError(); while (i < len) { if (i in a) { accumulator = a[i++]; break; } else i++; } if (i == len) throw TypeError(); } while(i < len) { if (i in a) accumulator = f.call(undefined, accumulator, a[i],i,a); i++; } return accumulator; } ~~~ ### Higher-Order Functions #### `not(f)` ~~~ function not(f) { return function() { var result = f.apply(this, arguments); return !result; } } ~~~ ~~~ var even = function(x) { return x%2 == 0; }; not(even)(22); // false ~~~ #### function `every()` ~~~ function every(f) { return reduce(function(x,y){return f(x) && y}) }; var odd = not(even); [1,3,5].every(odd); // true ~~~ #### `mapper` ~~~ function mapper(f) { return function(a) { return a.map(f);}; } mapper(Math.sin)([1,2,3]); [0.8414709848078965, 0.9092974268256817, ~~~ #### composition ~~~ function compose(f,g){ return function() { return f.call(this,g.apply(this,arguments)); } } compose(square,sum)(2,3); ~~~ ### Partial Application of Function ~~~ function array(a,n) { return Array.prototype.slice.call(a,n || o); } function partialLeft(f){ var args = arguments; return function() { var a = array(args,1); a = a.concat(array(arguments)); return f.apply(this, a); }; } function partialRight(f){ var args = arguments; return function() { var a = array(arguments); a = a.concat(array(args,1)); return f.apply(this,a); }; } function partial(f) { var args = arguments; return function() { var a = array(args,1); var i=0,j=0; for (;i < a.length; i++) if (a[i] === undefined) a[i] = arguments[j++]; a = a.concat(array(arguments,j)); return f.apply(this, a); }; } ~~~ ~~~ function f(x,y,z){return x*y-z;} partialRight(f,2)(3,4); // 3*4-2 = 10 partialLeft(f,2)(3,4); // 2*3-4 = 2 partial(f,undefined,2)(3,4); // 3*2-4 = 2 ~~~ ### Memorization ~~~ function memorize(f) { var cache = (); return function() { var key = arguments.length + Array.prototype.join.call(argumnentes,","); if (key in cache) return cache[key]; else return cache[key] = f.apply(this, arguments) } } ~~~ e.g. ~~~ var gcdmemo = memorize(gcd); gcdmemo(85,187); ~~~ # Classes and Modules javascript class - dynamically extendable (sec. 9.4) - duck typing (9.5) ## Classes and Prototypes class : a set of objects that inherits properties from the same prototype `o1 = inherit(p)` : this function defines a class that is ~~~ o1 = inherit(p) o2 = inherit(p) o3 = inherit(p) ... ~~~ ~~~ class p = {o1, o2, o3, ...} ~~~ range.js ~~~ function range(from, to){ var r = inherit(range.methods); r.from =from; r.to = to; return r; } range.methods = { includes: function(x) {return this.from <= x && x <= this.to; }, foreach: function(f) { for(var x = Math.ceil(this.from); x<= this.to; x++) f(x); }, toString: function(){ return "(" + this.from + "..." + this.to + ")"; } } ~~~ e.g. ~~~ var r = range(5,9); r.includes(6); // true r.foreach(x => console.log(x)); // 5 6 7 8 9 r.foreach((x => console.log(Math.sin(x)))); -0.9589242746631385 -0.27941549819892586 0.6569865987187891 0.9893582466233818 0.4121184852417566 ~~~ ## Classes and Constructors range2.js ~~~ function Range(from, to) { this.from = from; this.to = to; } Range.prototype = { includes: function(x) {return this.from <= x && x <= this.to; }, foreach: function(f) { for (var x = Math.ceil(this.from); x<= this.to; x++) f(x); }, toString: function() {return "(" + this.from + "..." + this.to + ")";} } ~~~ e.g. ~~~ var r = new Range(1,3); r.includes(2); r.foreach((x => console.log(x))); // 1 2 3 ~~~ change Object definition via `__proto__` ~~~ r.__proto__.foo = "Foo!"; var r' = new Range(5,10); // now, Range.prototype has the property "foo" r'.foo // "Foo!" ~~~ ### Constructors and Class Identity ~~~ r instanceof Range; // true ~~~ ### The constructor Property #### function object a function is an object with constructor ~~~ var F = function(){}; // a function object var p = F.prototype; // the prototype of F var c = p.constructor; // p's constructor c === F // true ~~~ ## Java-Style Classes in Javascript Java Class - Instance fileds - Instance methods - Class fields - Class methods Javascript Class - Constructor Object : properties written in constructor are fields of the object - Prototype Object : the properties of this object are inherited to instance - Instance Object : with properties defined on the particular instance 3 steps to define Class 1. write a constructor ( define instance fields ) 2. write a prototype ( define instance methods ) 3. define class properties on the Constructor itself `extend()` ( see Function As Namespaces section ) ~~~ function defineClass(constructor, methods , statics){ if (methods) extend(constructor.prototype, methods); if (statics) extend(constructor, statics); return constructor; } ~~~ e.g. ~~~ var SimpleRange = defineClass( function(f,t) {this.f = f; this.t = t;}, { includes: function(x) {return this.f <=x && x<= this.t;}, toString: function() {return this.f + "..." + this.t;} }, { upto: function(t) { return new SimpleRange(o,t);} } ) ~~~ ### class `Complex()` ~~~ function Complex(real, imaginary) { if (isNaN(real) || isNaN(imaginary)) throw TypeError(); this.r = real; this.i = imaginary; }; // addition Complex.prototype.add = function(that) { return new Complex(this.r + that.r, this.i + that.i); }; // multiply Complex.prototype.mul = function(that) { return new Complex(this.r*that.r - this.i*that.i , this.r*that.i + that.r*this.i) }; // magnitude Complex.prototype.map = function() { return Math.sqrt(this.r*this.r + this.i*this.i); }; // negative Complex.prototype.neg = function() { return new Complex(-this.r, -this.i)} // dual Complex.prototype.dual = function() { return new Complex(this.r, -this.i)} // euqality Complex.prototype.equals = function(that) { return that != null && that.constructor === Complex && this.r === that.r && this.i === that.i; }; Complex.prototype.ZERO = new Complex(0,0); Complex.ONE = new Complex(1,0); Complex.I = new Complex(0,1); Complex.prototype.toString = function() { return "{" + this.r + "," + this.i + "}"; }; Complex.parse = function(s) { try { var m = Complex._format.exec(s); return new Complex(parseFloat(m[1]), parseFloat(m[2])); } catch (x) { throw new TypeError("Can't parse '" + s + "' as a complex number."); } }; Complex._format = /^\{([^,]+),([^}]+)\}$/; ~~~ ~~~ > C = Complex; > (new C(1,0)).add(new C(2,3)) // Complex {r: 3, i: 3} > (new C(1,0)).mul(new C(2,3)) // Complex {r: 2, i: 3} > (new C(1,Math.PI)).mul(new C(2,3)) Complex {r: -7.424777960769379, i: 9.283185307179586} ~~~ Java : - instace field - instance methods are used as if they are local value Javascript : only local fields can get return value ~~~ Complex.prototype.toString = function() { with(this) { return "{" + r + "," + i + "}"; } }; ~~~ Java : - final keyword : cannot change constant Javascript: - (9.6.6 / 9.8.2) ## Augmenting Classes Classes are dynamical : we can add methods to `String`, `Number`, ... Return the complex conjugate ~~~ Complex.prototype.conj = function() { return new Complex(this.r -this.i); }; ~~~ It is possible to add methods to `Object.prototype`, making them available on all objects. ~~~ String.prototype.trim = String.prototype.trim || function() { if (!this) return this; return this.replace(/^\s+|\s+$/g, ""); // \s : space } (" Hello world ").trim() "Hello world" ~~~ ~~~ Function.prototype.getName = function() { return this.name || this.toString().match(/function\s*([^(]*)\(/ )[1]; } ~~~ ## Classes and Types see classof section Class acts like Type ### `instanceof` operator - see `instanceof` operator section - is `isPrototypeOf()` method ### The constructor property ~~~ ("hello").constructor == String // true ("hello").constructor; // function String() { [native code] } ~~~ ### The Constructor Name ### Duck-Typing ## Object Oriented Techniques in Javascript ### Set ~~~ function Set() { this.values = {}; this.n = 0; this.add.apply(this, arguments); } Set._v2s = function(val) { switch(val) { case undefined: return 'u'; case null: return 'n'; case true: return 't'; case false: return 'f'; default: switch(typeof val) { case 'number': return '#' + val; case 'string': return '"' + val; default: return '@' + objectId(val); } } function objectId(o) { var prop = "|**objectid**|"; if (!o.hasOwnProperty(prop)) o[prop] = Set._v2s.next++; return o[prop]; } }; Set._v2s.next = 100; // Add each of the arguments to the set. Set.prototype.add = function() { for (var i = 0; i < arguments.length; i++) { var val = arguments[i]; var str = Set._v2s(val); if (!this.values.hasOwnProperty(str)) { this.values[str] = val; this.n++; } } return this; } // Remove Set.prototype.remove = function() { for (var i = 0 ; i < arguments.length; i++) { var str = Set._v2s(arguments[i]); if (this.values.hasOwnProperty(str)) { delete this.values[str]; this.n--; } } return this; } // Contain Set.prototype.contains = function(value) { return this.values.hasOwnProperty(Set._v2s(value)); } // Size Set.prototype.size = function() {return this.n; }; // Map Set.prototype.foreach = function(f, context) { for (var s in this.values) if (this.values.hasOwnProperty(s)) f.call(context, this.values[s]); } ~~~ ### Borrowing Methods methods are invoked - "through" - "on" an object e.g. Set object - toArray : give definition - toJSON := toArray Range class borrows `equals()` from generic ~~~ Range.prototype.equals = generic.equals; ~~~ ~~~ var generic = { toString: function() { var s = '['; if (this.constructor && this.constructor.name) s += this.constructor.name + ": "; var n = 0 for (var name in this) { if (!this.hasOwnProperty(name)) continue; var value = this[name]; if (typeof value === "function") continue; if (n++) s += ", "; s += name + '=' + value; } return s + ']'; }, equals: function(that) { if (that == null) return false; if (this.constructor !== that.constructor) return false; for (var name in this) { if ( name === "|**objectid**|") continue; if (!this.hasOwnProperty(name)) continue; if (this[name] !== that[name]) return false; // <== what happen if that[name] does not exist ? } return true; } }; ~~~ ### Private State Java(c++)'s private state in Javascript - private state : accesible only from internal method ~ES5 (not work in ES6) ~~~ function Range(from, to) { this.from = function() {return from;} this.to = function() {return to;} } Range.prototype = { constructor: Range, includes: function(x) {return this.from() <= x && x <= this.to(); }, foreach: function(f) { for(var x = Math.ceil(this.from()), max=this.to(); x <= max; x++) f(x); }, toString: function() {return "(" + this.from() + "..." + this.to() + ")";} }; ~~~ ES6 ~~~ var property = Symbol(); class Something { constructor(){ this[property] = "test"; } } var instance = new Something(); console.log(instance.property); //=> undefined, can only access with access to the Symbol ~~~ ### Constructor Overloading Complex e.g. ~~~ Complex.polar = function(r,theta) { return new Complex(r*Math.cos(theta), r*Math.sin(theta)); }; ~~~ e.g. overloading Set with Array-like object arguments ~~~ function Set() { this.values = {}; this.n = 0; if(arguments.length == 1 && isArrayLike(arguments[0])) this.add.apply(this, arguments[0]); else if (arguments.length > 0) this.add.apply(this,arguments); } ~~~ ## Subclass ### Defining a Subclass ~~~ B.prototype = inherite(A.prototype); // Sybclass inherits from Superclass B.prototype.constructor = B; // Override the ingerited constructor prop ~~~ a function defining subclass ~~~ function defineSubclass(superclass, constructor, methods, statics){ constructor.prototype = inherit(superclass.prototype); constructor.protorype.constructor = constructor; if (methods) extend(constructor.prototype, methods); if (statics) extend(constructor, statics); return constructor; } Function.prototype.extend = function(constructor, methods, statics){ return defineSubclass(this, constructor, methods, statics); } ~~~ e.g. Singleton Set ~~~ function SingletonSet(member) { this.member = member; } SingletonSet.prototype = inherit(Set.prototype); extend(SingletonSet.prototype, { constructor: SingletonSet, add: function() {throw "read-only set";}, remove: function() {throw "read-only set";}, size: function() {return 1;}, foreach: function(f, context) {f.call(context, this.member); }, contains: function(x) {return x === this.member;} }) SingletonSet.prototype.equals = function(that) { return that instanceof Set && that.size()==1 && that.contains(this.member); } ~~~ ### Constructor and Method Chaining subclass modifying little ~~~ function NonNullSet() { Set.apply(this, arguments); } NonNullSet.prototype = inherit(Set.prototype); NonNullSet.prototype.constructor = NonNullTSet; NonNullSet.prototype.add = function() { for (var i = 0; i < arguments.length; i++) if (arguments[i] == null) throw new Error ("No null!"); return Set.prototype.add.apply(this, arguments); }; ~~~ ~~~ var StringSet = filteredSetSubclass(Set, function(x) {return typeof x==="string";}); var MySet = filteredSetSubclass(NonNullSet, function(x) {return typeof x !== "function";}) ~~~ ~~~ function filteredSetSubclass(superclass, filter) { var constructor = function() { superclass.apply(this, arguments); // Chains to the superclass }; var proto = constructor.prototype = inherit(superclass.prototype); proto.constructor = constructor; proto.add = function() { for(var i = 0; i < arguments.length; i++) { var v = arguments[i]; if (!filter(v)) throw("value " + v + " rejected by filter"); } superclass.prototype.add.apply(this, arguments); }; return constructor; } ~~~ ~~~ var NonNullSet = (function() { // Define and invoke function var superclass = Set; // Only specify the superclass once. return superclass.extend( function() { superclass.apply(this, arguments); }, // the constructor { // the methods add: function() { // Check for null or undefined arguments for(var i = 0; i < arguments.length; i++) if (arguments[i] == null) throw new Error("Can't add null or undefined"); // Chain to the superclass to perform the actual insertion return superclass.prototype.add.apply(this, arguments); } }); }()); ~~~ ### Composition Versus Subclassing ## Class in ES5 skip ## Modules skip : 中身が空の抽象 method を持たせるだけ
# Pattern Matching with Regular Expression ~~~ var pattern = /s$/; var pattern = new RegExp("s$"); ~~~ @ES5 - eval : RegExp -> NewObject ### Literal Characters ~~~ \0 The null charactor \u0000 \t tab \u0009 \n Newline \u000A \v Vertical tab \u000B \f Form feed \u000C \r Carriage return \u000D \xnn Hexadecimal number \uxxxx Unicode Charactor \cX The control caractor e.g. \c] is \n ~~~ special characters ~~~ ^ start $ end . arbitrary char * one or more times + zero or more times ? = ! : \ / ( ) [ ] { } ~~~ `@` is not special character backslash ~~~ /\\/ ~~~ ### Character Classes ~~~ /[abc]/ a, b , or c /[^abc]/ not (a,b, or c) ~~~ ~~~ /[a-z]/ /[a-zA-Z0-9]/ ~~~ ~~~ \s unicode whitespace \S not unicode whitespace ~~~ ~~~ \w [a-zA-Z0-9_] \W [^a-zA-Z0-9_] ~~~ ~~~ [...] any one char between the brackets [^...] any one char not between the brackets . any one char except \n or line terminator \d [0-9] \D [^0-9] ~~~ ~~~ [\b] A literal backspace \b <== ? ~~~ ### Repetition how to represent 4 digits ? ~~~ /\d\d\d\d/ // silly answer ! ~~~ answer ~~~ {n,m} // repeating n~m times {n,} // repeating n~ times {n} // repeating n times ? // {0,1} + // {1,} * // {0,} ~~~ e.g. ~~~ /\d{2,4}/ // 2 ~ 4 digits /\w{3}\d?/ // 3 char 0 or 1 digit /\s+java\s+/ // java with space bothsides /[^(]*/ // zero or more characters that are not open parenthesis `(` ~~~ ~~~ ?? +? *? ~~~ e.g. ~~~ "aaa".match(/a+/); // ["aaa"] "aaa".match(/a+?/); // ["a"] "aaab".match(/a+b/) // ["aaab"] "aaab".match(/a+?b/) // ["aaab"] ~~~ ### Alternation, Grouping, Iteration `|` : alteration e.g. ~~~ /ab|cd|ef/ // ab OR cd OR ef /\d{3}|[a-z]{4}/ // 3_digits OR 4_numbers ~~~ ~~~ "java".match( /java(script)?/ ) // ["java", undefined] "javascript".match( /java(script)?/ ) // ["javascript", "script"] ~~~ ~~~ /['"][^'"]*['"]/ // "hoge" "hoge' 'hoge" 'hoge' ~~~ `\1` referes 1st `()` ~~~ /(['"])[^'"]*\1/ // "hoge" 'hoge' ~~~ `\2` refers `(fun\w*)` not `(?:[Ss]cript)` ~~~ r = /([Jj]ava(?:[Ss]cript)?)\sis\s(fun\w*)/ "Java is fun".match(r) ~~~ - `()` numbered grouping - `(?: )` simply for grouping (not numbered) ### Specifying Match Position #### `/^ $/` ~~~ /Javascript/ // find the word /^Javascript$/ // find the line only with single "Javascript" ~~~ #### `(?= )` : do only filter return "javascript" only followed by ":" ~~~ re = /[Jj]ava[Ss]cript(?=\:)/ "javascript".match(re) // null "javascript:".match(re) // ["javascript"] ~~~ ~~~ ^ : the beginning of a line $ : the end of a line \b : word boundary \B : not word boundary (?=p) : positive lookahead assertion (?!p) : negative lookahead assertion ~~~ ### Flags ~~~ i : case-insensitive matching g : global match m : multiline mode : ^[$] matches the beginning[end] of line or string ~~~ ## String Methods for Pattern Matching String has 4 methods for pattern matching - `search()` - `replace()` - `match()` - `split()` ~~~ "Javascript".search(/script/i); ~~~ ~~~ text.replace(/javascript/gi, "JavaScript"); ~~~ ~~~ var quote = /"([^"]*)"/g text.replace(quote, '"$1"'); ~~~ ~~~ var url = /(\w+):\/\/([\w.]\/(\S*)/; var text = "Visit my blog at http://www.example.com/~david"; var result = text.match(url); if (result != null) { var fullurl = result[0]; // "http://www.example.com/~david" var protocol = result[1]; // "http" var host = result[2]; // "www.example.com" var path = result[3]; // "~david" } ~~~ ~~~ "123,456,789".split(",") // ["123","456","789"] "1, 2, 3, 4, 5".split(/\s*,\s*/) // ["1","2","3","4","5"] ~~~ ## The RegExp Object put `\\` if you want to pass `\` into RecExp Constructor ~~~ var zipcode = new RegExp("\\d{5}"), "g"); ~~~ ### RegExp Methods - `exec()` -> returns String - `test()` -> returns Bool ~~~ var pattern = /Java/g; var text = "JavaScript is more fun than Java!"; var result; while((result = pattern.exec(text)) != null ) { alert("Matched '" + result[0] + "'" + " at position " + result.index + "; next serach begins at " + pattern.lastIndex); } ~~~ ~~~ var pattern = /java/i; pattern.test("JavaScript"); // true ~~~ RegExp Object has lastIndexproperty. # JavaScript Subsets and Extensions ## Javascript Subsets ### The Good Parts Javascript subset for security by Douglax Crockford ### Subsets for Security - `eval()` / `Function()` not allowed <== enable arbitrary string code - `this` forbidden <== accessing global object from outside world - `with` often forbidden <== make code verification difficult - certain global variablesa are not allowed - code is not allowd to refer `Window` object - similary , `Document` object , controlling page content - so, use DOM API - certain properties - `caller` `callee` properties of the `Arguments` Object are forbidden - `__proto__` is forbidden - property access operator `[]` often forbidden , use `.` other subsets - [ADsafe](http://adsafe.org) - [dojox.secure](http://www.sitepen.com/blog/2008/08/01/secure-mashups-with-dojoxsevure/) - [Caja](http://code.google.com/p/google-caja) - [FBJS](http://facebook.com) - [Microsoft Web Sandbox](http://websandbox.livelabs.com/) ## Constants .. ## Destructuring Assignment ~~~ let [x,y] = [1] // x = 1 , y = undefined let [x,y] = [1,2,3] // x = 1 , y = 2 let [,x,,y] = [1,2,3,4] // x = 2 , y = 4 let [x,[y,z]] = [1,[2,3],4] // x = 1 , y = 2 , z = 3 ~~~ ~~~ let transparent = {r:0,g:0,b:0,a:1} let {r:red, g:green, b:blue} = transparent // red = 0, green = 0, blue = 0 ~~~ ## Iteration ## Shorthand Functions ## Multiple Catch Clauses ~~~ try { // multiple exception types can be thrown here throw 1; } catch(e if e instanceof ReferenceError) { // Handle reference errors here } catch(e if e === "quit") { // Handle the thrown string "quit" } catch(e if typeof e === "string") { // Handle any other thrown strings here } catch(e) { // Handle anything else here } finally { // The finally clause works as normal } ~~~ ## E4X: ECMAScript for XML e4x : xml for - Rhino - Spidermonkey xml : - differs from DOM - ~~~ // Create an XML object var pt = Hydrogen Helium Lithium pt.element += Beryllium; ~~~ or ~~~ pt = ; var elements = ["Hydrogen", "Helium", "Lithium"]; for (var n = 0; n < elements.length; n++) { pt.element += {elements[n]}; } pt.element += new XML('Boron') pt.element += new XMLList('Carbon' + 'Nitrogen'); ~~~ # Server-Side JavaScript - Rhino : Java-based js interpreter - Node : V8 js interpreter with low-level bindings for POSIX API ## Node (Asynchronous I/O) - Node APIs are asynchronous, so - Node relies on event handlers ### hello world ~~~ $ node hello.js ~~~ hello.js ~~~ setTimeout(()=>{console.log("Hello, Node")}, 3000); ~~~ load file ~~~ $ node > var fs = require('fs') > fs.readFile('hello.js', (e,d)=>(if (e) throw e; data = d.toString();)) > data 'setTimeout(()=>{console.log("hello Node")}, 3000);\n\nprocess.on("exit", ()=>{ console.log("Goodbye"); });\nprocess.on("uncaughtException", (e)=> { console.log(Exception,e); })\nprocess.on("SIGINT", ()=>{ console.log("Ignored Ctrl-C") })\n' > eval(data); hello Node ~~~ ### process process object is an emitter ~~~ $ node > process ... ~~~ ~~~ process.version process.argv process.env process.pid process.getuid() process.cwd() // current working directory process.chdir() // Change directory process.exit() // Quit ~~~ Node's event infrastructure ~~~ emitter.on(eventType, handlerFunction) ~~~ ~~~ emitter.on(name, f) emitter.addListener(name, f) // same as on() emitter.once(name, f) // this event is called once and removed emitter.listeners(name) // list of handler functions emitter.removeListener(name,f) emitter.removeAllListeners(name) ~~~ process is an emitter , so ~~~ // The "exit" event is sent before Node exits. process.on("exit", ()=>{ console.log("Goodbye"); }); process.on("uncaughtException", (e)=>{ console.log(Exception,e); }) // posix signals process.on("SIGINT", ()=>{ console.log("Ignored Ctrl-C") }) process.on("SICHUP", ()=>{ }) process.on("SIGTERM",()=>{ }) ~~~ how to get stream objects for - files - sockets Input stream s ~~~ s.on("data", f); s.on("end", f); s.on("error", f); s.readable s.pause(); s.resume(); // Specify an dncoding if you want strings passed to "data" event handler s.setEncoding(enc); // Output stream s s.write(buffer) s.write(string, encoding) s.end() // close s.end(buffer) // Write final chunk of binary data and close s.end(string, encoding) s.writable; // true if the stream is still open and writable s.on("drain", f) // Call f() when internal buffer becomes empty ~~~ "drain" event : トイレを流し終わった時に発生するイベント -> final ### fs module ~~~ var fs = require("fs"); // synchronously var text = fs.readFileSync("config.json", "utf8") // asynchronously fs.readFile("imagefile", (e,buf) => { if (e) throw e; process(buf); // File contents are in buf }); ~~~ ### Buffer Object ~~~ var bytes = new Buffer(256); for (var i = 0; i < bytes.length; i++) bytes[i] = i; // slice var end = bytes.slice(240,256); end[0] end[0] = 0; bytes[240] // copy subarray var more = new Buffer(8); end.copy(more, 0, 8, 16); more[0] // var buf = new Buffer("2πr", "utf8"); // [50,207,128,114] buf.length // 3 buf.toString() // "2πr" buf = new Buffer(10); var len = buf.write("πr2",4 ) buf.toString("utf8",4, 4+len) buf [0, 0, 0, 0, 207, 128, 114, 50, 0, 0] ~~~ ### net module ~~~ #!/usr/local/bin/node var net = require('net'); var server = net.createServer(); server.listen(2000, ()=>{ console.log("Listening on port 2000") }); server.on("connection", (s)=>{ console.log("Accepting connection from", s.remoteAddress); s.on("data",(d)=>{ s.write(d) }); s.on("end", (d)=>{ console.log("Connection closed") }); }); ~~~ ## e.g. httpserver ~~~ #!/usr/local/bin/node var http = require('http'); var fs = require('fs'); var server = new http.Server(); server.listen(80); server.on("request", (request, response) => { var url = require('url').parse(request.url); if (url.pathname === "/test/delay" ){ var delay = parseInt(url.query) || 2000 ; // 2000 milliseconds response.writeHead(200, {"Content-Type": "text/plain; charset=UTF-8"}); response.write("Sleeping for " + delay + " milliseconds..."); setTimeout( ()=>{ response.write("done."); response.end(); }, delay ); } else if (url.pathname === "/test/mirror"){ response.writeHead(200, {"Content-Type": "text/plain; charset=UTF-8"}); response.write(request.method + " " + request.url + " HTTP/" + request.httpVersion + "\r\n"); for (var h in request.headers) response.write(h + ": " + request.headers[h] + "\r\n" ); response.write("\r\n"); request.on("data", (chunk)=>{ response.write(chunk) }); request.on("end", (chunk)=>{ response.end(); }); } else { var fname = url.pathname.substring(1); var type; switch(fname.substring(fname.lastIndexOf(".")+1)){ case "html": case "htm": type = "text/html; charset=UTF-8"; break; case "js": type = "application/javascript; charset=UTF-8"; break; case "css": type = "text/css; charset=UTF-8"; break; case "txt": type = "text/plain; charset=UTF-8"; break; case "manifest": type = "text/cache-manifest; charset=UTF-8"; break; default: type = "application/octet-stream"; break; } fs.readFile(fname, (e,content)=>{ if (e) { response.writeHead(404, {"Content-Type": "text/plain; charset=UTF-8"}); response.write(e.message); response.end(); } else { response.writeHead(200, {"Content-Type": type}); response.write(content); response.end(); } }) } }) ~~~ copy ~~~ function fileCopy(filename1, filename2, done) { var input = fs.createReadStream(filename1); var output = fs.createWriteStream(filename2); input.on("data", (d) => { output.write(d); }); input.on("error",(e) => { throw e; }); input.on("end", ( ) => { output.end(); if(done) done();}) } ~~~ list ~~~ #!/usr/local/bin/node var fs = require("fs"), path = require("path"); var dir = process.cwd(); if (process.argv.length > 2) dir = process.argv[2]; var files = fs.readdirSync(dir); var len = files.length - 1; var maxtab = 1; var rec = (n) => { var fname = files.shift(); if (fname == undefined ) return; var fullname = path.join(dir,fname); var stats = fs.statSync(fullname); if (stats.isDirectory()) fname += "/"; var strlen = fname.length var quotient = Math.floor(strlen/8) var remainder = strlen%8 maxtab = maxtab < quotient ? quotient : maxtab var tab = (n) => { return n==0 ? "\t" : tab(n-1)+"\t" } var space = (n) => { return n==0 ? " " : space(n-1)+" " } rec(n+1); n == len ? process.stdout.write( "Name" + tab(maxtab) + "Size\tDate\n" ) : ( () => {} )(); process.stdout.write( fname + tab(maxtab - quotient) + stats.size + "\t" + stats.mtime + "\n" ); }; rec(0); ~~~