タグ「javascript」が付けられているもの

[javascript メモ] switchの評価メモ

カンマ演算子が左オペレータ、右オペレータの順に実行し
右オペレータの実行結果を返す性質を利用し
swich文の評価の動作を確認してみます。

// コンマ演算子テスト
console.log("コンマ演算子テスト");
var val = (console.log("1"), a = 1, console.log("3"), (function(){ return 4 }()) ); // 1 3
console.log( a ); // 1
console.log( val ); // 4

// switchのテスト
console.log("switchのテスト");
var i = 3;
switch( i ) {
  case (console.log("t1"), 1):
       console.log("処理1");
       break;
  case (console.log("t2"), 2):
       console.log("処理2");
       break;
  case (console.log("t3"), 3):
       console.log("処理3");
       break;
  case (console.log("t4"), 4):
       console.log("処理4");
       break;
  default:
       console.log("処理5");
       break;
}
実行結果
js_t_comma1.png

参考サイト
oogattaの勉強日記 カンマ演算子と VariableDeclarationList
.
EMCAScript5で追加されたObject.definePropertyとObject.keysを確認してみます。

Object.definePropertyは、プロパティの属性enumerableに関係なくキーを配列で返します。
keysはプロパティの属性enumerable=trueのキーのみ返します。
// ビルトインオブジェクトにプロパティを追加
Object.prototype.testMethod = "TESTMETHOD";
Object.defineProperty( Object.prototype, "testMethod2", { enumerable: false });


// Object Literal
console.log("Object Literal ---");
var obj = { id: 1, nickname: "nic" };
Object.defineProperty( obj, "id", { enumerable: false });
console.log( Object.getOwnPropertyNames( obj ) );
console.log( Object.keys( obj ) );
for (var i in obj) {
  console.log(i);
}


// Array Literal
console.log("Array Literal ---");
var array = ["a", "b", "c"];
console.log( Object.getOwnPropertyNames( array ) );
console.log( Object.keys( array ) );
for (var i in array) {
  console.log(i);
}


// Object.prototype
console.log("Object.prototype ---");
console.log( Object.getOwnPropertyNames( Object.prototype ) );
console.log( Object.keys( Object.prototype ) );

// Array.prototype
console.log("Array.prototype ---");
console.log( Object.getOwnPropertyNames( Array.prototype ) );
console.log( Object.keys( Object.prototype ) );

js_e5_tm1.png
参考サイト
15.2.3.4 Object.getOwnPropertyNames ( O )
15.2.3.14 Object.keys ( O )
MDN getOwnPropertyNames
MDN keys

[javascript ECMAScript5 メモ] get,set

A.
EMCAScript5では、ゲッター、セッターが追加されました。
以下のような書式で記述します。
// Object Literal
console.log("Object Literal ---");
var obj = { _id: 1,
            get id() {
              return this._id;
            },
            set id(value) {
          if( isNaN(value) ) throw new Error("Not Number");
              this._id = value;
            }
          };
console.log( obj.id );
obj.id = 2;
console.log( obj.id );
console.log( Object.keys( obj ) );


// Object.defineProperty
console.log("Object.defineProperty ---");
var obj2 = {
  _id: 1
}

Object.defineProperty(obj2, "id", {
  enumerable: false,
  configurable: false,
  get : function(){
          return this._id;
        },
  set : function(value){
      if( isNaN(value) ) throw new Error("Not Number");
          this._id = value;
        }
});
console.log( obj2.id );
obj2.id = 2;
console.log( obj2.id );
console.log( Object.keys( obj2 ) );

// Private
console.log("Private ---");
var obj3 = {};
(function () {
  var _id = 1;
  Object.defineProperty(obj3, "id", {
    enumerable: false,
    configurable: false,
    get : function(){
            return _id;
          },
    set : function(value){
      if( isNaN(value) ) throw new Error("Not Number");
            _id = value;
          }
  });

})();
console.log( obj3.id );
obj3.id = 2;
console.log( obj3.id );
console.log( Object.keys( obj3 ) );
js_e5_sg1.png

参考サイト
MDN get
MDN set
ECMA-262 ECMA-262-5 in detail. Chapter 1. Properties and Property Descriptors.

[javascript ECMAScript5] オブジェクトのclone

A.
EMCAScript5では、オブジェクトをcloneする時にその属性にも気をつける必要がある。

hachy.net ECMAScript 5 に追加された新しい関数(Object編)さんのサイトを参考に試してみる。
// add clone function
Object.clone = function (o) {
    var n = Object.create(Object.getPrototypeOf(o));
    var props = Object.getOwnPropertyNames(o);
    var pName;
    for (var p in props) {
        pName = props[p];
        Object.defineProperty(n, pName, Object.getOwnPropertyDescriptor(o, pName));
    };
    return n;
};

// clone test
var obj = Object.create(Object.prototype, {
  id: {
    value: 1,
    configurable: true,
    writable: false,
    enumerable: true
  },
  nickname: {
    enumerable: true,
    configurable: false,
    get : function(){
            console.log("get");
            return this._nickname
          },
    set : function(value){
            console.log("set");
            this._nickname = value
          }
  }
});

console.dir( obj );
console.log( Object.getOwnPropertyDescriptor(obj, "id") );
console.log( Object.getOwnPropertyDescriptor(obj, "nickname") );

console.log("clone+++++++++++++++++");

var obj2 = Object.clone( obj );
console.dir( obj2 );
console.log( Object.getOwnPropertyDescriptor(obj2, "id") );
console.log( Object.getOwnPropertyDescriptor(obj2, "nickname") );
実行結果
js_ecma5_clone_1.png
内部属性も同様な状態でコピーできている事が確認できる。

参考サイト
hachy.net ECMAScript 5 に追加された新しい関数(Object編)
IEBlog ECMAScript 5 Part 1: Reusable Code
A.
Property Descriptorsまわりの動作メモ

1. Object.create Property Descriptorデフォルト値の確認
Object.create時にvalueだけ設定した場合configurable,enumerable,writable の値を確認する
var obj = Object.create(Object.prototype, {
  id: { value: 1 }
});
console.log( Object.getOwnPropertyDescriptor(obj, "id") );
console.dir( obj );
結果(Safari 5.0.3 Mac)
jd_pd_1.png

2. オブジェクトリテラルで作成した場合のProperty Descriptorデフォルト値の確認
var obj = {id: 1};
console.log( Object.getOwnPropertyDescriptor(obj, "id") );
console.dir( obj );
結果(Safari 5.0.3 Mac)
js_pd_2.png

3.ゲッター、セッターを使う場合 value, writableは設定できない
get, setとvalueを同時に設定してみる

var obj = Object.create(Object.prototype, {
  id: {
    value: 1,
    enumerable: true,
    configurable: true,
    get : function(){
            return this._id;
          },
    set : function(value){
            this._id = value;
          },
  }
});
結果(Safari 5.0.3 Mac)
js_pd_3.png

get, setとwritableを同時に設定してみる
var obj = Object.create(Object.prototype, {
  id: {
    writable : true,
    enumerable: true,
    configurable: true,
    get : function(){
            return this._id;
          },
    set : function(value){
            this._id = value;
          },
  }
});
結果(Safari 5.0.3 Mac)
js_pd_4.png

4. preventExtensionsで新たにプロパティが追加できなくなるか?
var obj = Object.create(Object.prototype, {
  id: { value: 1,
        configurable: true,
        writable: true,
        enumerable: true
      }
});

// preventExtensionsを設定
console.log( Object.isExtensible( obj ) );
Object.preventExtensions( obj );
console.log( Object.isExtensible( obj ) );

// definePropertyは可能か
Object.defineProperty(obj, "id", {
  configurable: false
});

// 既存のプロパティの値の変更は可能か
console.log( obj.id );
obj.id = 2;
console.log( obj.id );

// 新しくプロパティを追加できるか?
obj.nickname = "max";
/*
Object.defineProperty(obj, "nickname", {
  value : 1
});
*/
結果(Chrome 10.0.648.126 Mac)
js_pd_5.png

5. sealでpreventExtentionsとconfigurableがどのように変わるか
var obj = Object.create(Object.prototype, {
  id: { value: 1,
        configurable: true,
        writable: true,
        enumerable: true
      }
});

// preventExtensionsを設定
console.log( Object.isExtensible( obj ) );
console.log( Object.isSealed( obj ) );
Object.seal( obj );
console.log( Object.isExtensible( obj ) );
console.log( Object.isSealed( obj ) );


// definePropertyは可能か
console.log( Object.getOwnPropertyDescriptor(obj, "id") );
Object.defineProperty(obj, "id", {
  configurable: true
});
console.log( Object.getOwnPropertyDescriptor(obj, "id") );


// 既存のプロパティの値の変更は可能か
console.log( obj.id );
obj.id = 2;
console.log( obj.id );

// 新しくプロパティを追加できるか?
obj.nickname = "max";
結果(Chrome 10.0.648.126 Mac)
js_pd_6.png

6. freezeでpreventExtentionsとconfigurable,writableがどのように変わるか
  id: { value: 1,
        configurable: true,
        writable: true,
        enumerable: true
      }
});

// preventExtensionsを設定
console.log( Object.isExtensible( obj ) );
console.log( Object.isSealed( obj ) );
console.log( Object.isFrozen( obj ) );
Object.freeze( obj );
console.log( Object.isExtensible( obj ) );
console.log( Object.isSealed( obj ) );
console.log( Object.isFrozen( obj ) );

console.log( Object.getOwnPropertyDescriptor(obj, "id") );

// definePropertyは可能か
/*
console.log( Object.getOwnPropertyDescriptor(obj, "id") );
Object.defineProperty(obj, "id", {
  configurable: true
});
console.log( Object.getOwnPropertyDescriptor(obj, "id") );
*/

// 既存のプロパティの値の変更は可能か
console.log( obj.id );
obj.id = 2;
console.log( obj.id );
結果(Chrome 10.0.648.126 Mac)
js_pd_7.png

参考になるサイト
15.2.3.8 Object.seal ( O )
15.2.3.9 Object.freeze ( O )
ECMA-262-5 in detail. Chapter 1. Properties and Property Descriptors.
ECMAScript 5:The Definitive Slides
prog*sig Chapter 16. JavaScript Objects
MSDN Object.defineProperty Function (JavaScript)
ECMA Script 5 の Property Descriptor について話してきました
ECMAScript 5 に追加された新しい関数(Object編)
枕を欹てて聴く ES5, Property Descriptor解説

[javascript DOM] Q. ノードを操作するには?

A.
createElementでノードオブジェクトの作成を行い
要素ノード.appendChild(追加したいノードオブジェクト)
で追加します。

ノードの操作に関するメンバ
プロパティ名 説明
要素ノード.appendChild(追加したいノードオブジェクト) 要素ノードの子ノードの最後に追加します
要素ノード.insertBefore(追加したいノードオブジェクト, 直前に挿入したい対象のノード) 第1引数で指定したノードオブジェクトを第2引数で指定したノードの前に追加します
要素ノード.replaceChild(ノード, 置換対象ノード) 要素ノードの子ノードを第2引数に指定したノードを第1引数のノードと置換します
要素ノード.removeChild(削除したいノード) 指定した子ノードを削除します

実際に試してみましょう。
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>DOM</title>
  <script type="text/javascript">

  // メッセージを表示するdivを用意する
  window.onload = function() {
    var messages = document.createElement('div');
    messages.id = "messages"; // id属性を設定
    messages.className = "messages"; // class属性を設定
    messages.innerHTML = "メッセージの表示<br />";
    messages.style.backgroundColor = '#ccc'; // styleを設定
    document.getElementsByTagName("body")[0].appendChild(messages);
  }

  // クリアを押した時の処置
  function clearMessage() {
    if( confirm("本当に削除しますか?") ){
      while (messages.firstChild) {
        messages.removeChild(messages.firstChild);
      }
    }
  }

  // 送信ボタンを押した時の処理
  function sendMessage(){
    // メッセージを表示するノードを取得する
    console.dir(messages.childNodes);

    // テキストノードを作成
    var message = document.createTextNode(messageform.message.value);
    messages.appendChild(message);

    // br を作成
    var br = document.createElement('br');
    messages.appendChild(br);

    // inputを空にする
    messageform.message.value = '';

    return false;
  }
  </script>
  <style type="text/css">
  #messages {
    border: 1px solid #000;
  }
  .messages {
    width: 500px;
    height: 100px;
  }
  </style>
</head>
<body>
<form action="./" method="get" name="messageform" id="messageform" onsubmit="return sendMessage()">
   <label>ひとことめっせーじ: <input type="text" name="message" id="messgae" size="43"></label>
  <input type="submit" value="送信"><input id="clear" type="button" value="クリア" onclick="clearMessage()">
</form>
</body>
</html>
js_dom_s3.png

参考サイト
MDN document.createElement
MDN Node.appendChild
W3C DOM 2 Core: createElement
A. 属性にアクセスする方法として一番簡単な方法は、
要素ノードのプロパティとしてアクセスする方法です。

要素ノード.属性の名前;
要素ノード.属性の名前 = 属性の値;
*classはclassNameでアクセスする

要素の属性に関するメンバ
プロパティ名 説明
getAttribute() 要素の属性を取得
setAttribute() 要素の属性を設定
removeAttribute() 要素の属性を削除
createAttribute() 属性ノードを設定
atttributes すべての属性を取得
hasAttribute() 要素に属性が設定されてるか調べる
属性ノード.nodeName 属性の名称を取得
属性ノード.nodeValue 属性の値を取得
属性ノード.nodeType 2:属性ノード


実際に試してみる
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>DOM</title>
  <script type="text/javascript">
  window.onload = function() {
    // 基準となるノードを取得する
    var example = document.getElementById('example');
    console.log( "// document.getElementById('example')" );
    console.dir(example.attributes);

    console.log( "\n// example.attributes.length" );
    console.dir(example.attributes.length);
    var length = example.attributes.length;

    console.log( "\n// nodeValusで取得" );
    for(var i = 0; i < length; i++){
      // attributes[配列インデックス].nodeValue
      console.log( example.attributes[i].nodeName + ":"
                   + example.attributes[i].nodeValue );
    }

    // NamedNodeMapオブジェクト.item(インデックス番号)
    console.log( "\n// NamedNodeMapオブジェクト.item(インデックス番号)" );
    console.log( example.attributes.item(1) );

    // NamedNodeMapオブジェクト.getNamedItem('属性名');
    console.log( "\n// NamedNodeMapオブジェクト.getNamedItem('属性名')" );
    console.log( example.attributes.getNamedItem('src').value );

    // 要素ノード.属性の名前で取得
    console.log( "\n// 要素ノード.属性の名前で取得" );
    console.log( example.src );

    // getAttribute('属性の名前')で取得
    console.log( "\n// getAttribute('属性の名前')で取得" );
    console.log( example.getAttribute('src') );

    // 要素ノード.属性の名前 = 属性の値で設定
    /*console.log( "\n// 要素ノード.属性の名前 = 属性の値で設定" );
    example.src = 'http://memo.yoshimax.net/assets_c/2011/02/js_dom_node_w3-thumb-421x672-176.png';
    example.width = "421";
    example.height = "672"; */

    // setAttribute('属性の名前', '属性の値')で設定
    console.log( "\n// setAttribute('属性の名前', '属性の値')で設定" );
    example.setAttribute('src', 'http://memo.yoshimax.net/assets_c/2011/02/js_dom_node_w3-thumb-421x672-176.png');
    example.setAttribute('width', 421);
    example.setAttribute('height', 672);
  };
  </script>
</head>
<body>
<img alt="js_prototype_proto_1.png" src="http://memo.yoshimax.net/assets_c/2011/02/js_prototype_proto_1-thumb-544x454-140.png" width="544" height="454" class="mt-image-none" style="" id="example" />
</body>
</html>

コンソールログ
js_dom_get_set_1.png

参考サイト:
三等兵 JavaScriptのDOM Core基礎
DOM Level 2 Core: getAttribute
DOM Level 1 Core
HTML 5: APIs in HTML documents
MDN Nodeのメンバー一覧
MDN NamedNodeMapのメンバー
A.
DOMでは、getElementByIdなどで直接ノードを取得する以外にも
相対的にノードを取得する事が可能です。このように相対的に
ノードを取得する方法をノードウォーキング言います。

ノードウォーキングでよく使われるNodeオブジェクトのメンバーを確認してみます。

ノードウォーキングで使われるメンバー
プロパティ名 説明
firstChild 最初の子ノードを取得
lastChild 最後の子ノードを取得
perviousSibling 直前のノードを取得
nextSibling 直後のノードを取得
childNodes.length 子ノードに含まれるノード数を取得
parentNode 親ノードを取得


これらのNodeオブジェクトのメンバーを図に表すと次のようになります。
js_dom_node_w1.png

ここで実際のHTMLをみて確認してみます。
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>DOM childNodes</title>
  <script type="text/javascript">
  window.onload = function() {
    // 基準となるノードを取得する
    var ulnode = document.getElementById('item');
    console.dir(ulnode.childNodes);

    // 子ノードの1番最初を取得
    var first_child = ulnode.firstChild;
    console.dir(first_child);

    // 子ノードの2番目ノードを取得
    var next = first_child.nextSibling;
    console.dir(next);

    // 子ノードの一番最後のノードを取得
    var last_child = ulnode.lastChild;
    console.dir(last_child);

    // 子のノードの最後から2番目を取得
    var	before = last_child.previousSibling;
    console.dir(before);
  };
  </script>
  <style type="text/css">
  ul, li, div {
    border: 1px solid #f00;
    padding: 5px;
  }
  </style>
</head>
<body>
<h1>一覧</h1>
<div id="list">
  <ul id="item">
    <li>アイテム1</li>
    <li>アイテム2</li>
    <li>アイテム3</li>
  </ul>
</div>
</body>
</html>
実行結果は次のようになります。
js_dom_node_w3.png

実行結果を確認すると子ノードの1番最初を取得するとTextになっています。
ここでHTMLを修正してもう一度確認してみます。
ulのインデントを無くして一行で記述します。
<body>
<h1>一覧</h1>
<div id="list"><ul id="item"><li>アイテム1</li><li>アイテム2</li><li>アイテム3</li></ul></div>
</body>
</html>
実行結果は次のようになります。
js_dom_node_w4.png
HTMLをインデントした場合タグとタグの間の改行や空白も
Nodeリストに入るのでノードウォーキングの際は注意が必要です。

この影響を考慮するのはnodeTypeの確認を行いnodeType=1の要素ノードの時のみ処理を行ったり
nodeType=3テキストノードを取り除いたりします。

このような影響があるのでノードウォーキングは扱いにくかったのですが、
Element Traversalと言うAPIが定義されました。

Element Traversalを確認してみましょう
ElementTraversal API
プロパティ名 説明
firstElementChild 最初の子要素ノードを取得
lastElementChild 最後の子要素ノードを取得
perviousElementSibling 直前の要素ノードを取得
nextElementSibling 直後の要素ノードを取得
childElementCount 子ノードに含まれる要素ノード数を取得
parentNode 親ノードを取得

図に表すと以下のようになります。
js_dom_node_w5.png
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>DOM childNodes</title>
  <script type="text/javascript">
  window.onload = function() {
    // 基準となるノードを取得する
    var ulnode = document.getElementById('item');

    // childNode
    console.dir(ulnode.childNodes);

    // children
    console.dir(ulnode.children);

    // 子ノードの1番最初を取得
    var first_child = ulnode.firstElementChild;
    console.dir(first_child);

    // 子ノードの2番目ノードを取得
    var next = first_child.nextElementSibling;
    console.dir(next);

    // 子ノードの一番最後のノードを取得
    var last_child = ulnode.lastElementChild;
    console.dir(last_child);

    // 子のノードの最後から2番目を取得
    var before = last_child.previousElementSibling;
    console.dir(before);
  };
  </script>
  <style type="text/css">
  ul, li, div {
    border: 1px solid #f00;
    padding: 5px;
  }
  </style>
</head>
<body>
<h1>一覧</h1>
<div id="list">
  <ul id="item">
    <li>アイテム1</li>
    <li>アイテム2</li>
    <li>アイテム3</li>
    </ul>
  </div>
</body>
</html>
js_dom_node_w6.png
要素ノードのみを取得する事が可能な事が確認できました。

対応ブラウザは、以下のサイトから確認できます。
W3C DOM Compatibility - Traversal

参考サイト:
XML DOM Node Types
MDN Element.children
三等兵 Element Traversal API
A.
DOMはHTMLをツリー構造で表します。
以下のHTMLのツリー構造をみてみましょう。
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>TITILE</title>
  <script type="text/javascript">
  var log = "";

  window.onload = function() {
    getChild( document.getElementsByTagName('body')[0], 0 );
//    getChild( document.getElementsByTagName('head')[0], 0 );
    console.log(log);
  };

  function getChild( nodes, lv ){
    for(var num in nodes.childNodes){
      if(nodes.childNodes[num].nodeName && nodes.childNodes[num].nodeType != 3){
         log += Level(lv) + nodes.childNodes[num].nodeName + "\n";
        if( nodes.childNodes[num].length != 0 ) getChild( nodes.childNodes[num], lv+1 );
      }
    }
  }

  function Level(vl){
    var mes = '';
    while(vl--) mes += '-';
    return mes;
  }
  </script>
</head>
<body>
<h1>一覧</h1>
<ul>
  <li>アイテム1</li>
  <li>アイテム2</li>
  <li>アイテム3</li>
</ul>
<form action="./" method="get" name="userform" id="userform" onsubmit="return confirm();">
   <label>ニックネーム: <input type="text" name="nickname" id="nickname"></label>
  <input type="submit" value="送信">
</form>
</body>
</html>
nodeType=3以外のノード
js_dom_t1.png

これらのログからDOMのツリー構造を図で表してみます。

DOMのツリー構造の図
js_dom_t2.png ブラウザによって、DOMの解釈が異なります。
タクとタグの間にある空白や改行が無視されるかは
最も大きな違いとして認識されています。

参考サイト:
三等兵 jsのDOMによるノード取得
MDN Whitespace in the DOM
JavaScriptのDOM Core基礎

[javascript] DOMLevel0とは?

A. ブラウザ上で動くJavaScriptでは、HTMLの要素にアクセスし
データの取得や変更を行いたい事があります。

現在のブラウザでは、HTMLを解析しDOMという形でアクセスを行う事ができます。
しかしDOMが実装される前にも独自の方法でHTMLの要素にアクセスが行えました。
この昔からのアクセス方法はDOM以前の方式という意味から
レガシーDOMまたはDOMLevel0という呼び方で呼ばれています。

DOMではHTMLの要素すべてがアクセスできるのに対して、
レガシーDOMではアクセスできる要素が限られています、

フォーム要素、img要素、リンク要素などにアクセス可能です。
レガシーDOMは、現在でもフォーム要素のバリデーションの為に
利用されている場合もあるので確認して起きましょう。

ブラウザのオブジェクト
js_domlevel0_1.png

ここで実際フォームの要素にアクセスの方法を確認します。
レガシーDOMを利用する場合フォーム要素のname属性を使い名前をつける事が重要です。
この名前を利用し、要素へのアクセスを行います。
1. document.forms["フォーム名"].elements["要素名"]
2. document.forms[インデックス番号].elements[インデックス番号]
3. document.フォーム名.要素名
4. document.['フォーム名'].['要素名']
ここでinputフォームにアクセスを確認してみます。
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <script type="text/javascript">
  function confirm() {
    //  document.forms["フォーム名"].elements["要素名"]
    var nick = document.forms["userform"].elements["nickname"].value;

    // document.forms[インデックス番号].elements[インデックス番号]
    var nick2 = document.forms[0].elements[0].value;

    // document.フォーム名.要素名
    var nick3 = document.userform.nickname.value;

    // document.['フォーム名'].['要素名']
    var nick4 = document['userform']['nickname'].value;

    console.dir(nick);
    console.dir(nick2);
    console.dir(nick3);
    console.dir(nick4);
    return false;
  }
  </script>
</head>
<body>
<form action="./" method="get" name="userform" id="userform" onsubmit="return confirm();">
   <label>ニックネーム: <input type="text" name="nickname" id="nickname"></label>
  <input type="submit" value="送信">
</form>
</body>
</html>
コンソールログの値
js_form_t1.png

このようにinput要素の値を取り出せる事が確認できました。
取り出した要素にどのようなプロパティやメソッドがあるのかを調べたい場合
レガシーDOMでは、共通な仕様はありませんでしたが、
HTML5の取り組みとして新たにHTML5 specificationとして規定されました。

どの要素にどのようなプロパティやメソッドがあるかのAPIの確認は
HTML5 specification the-input-elementをまず確認しておくと良いかもしれません。

Safari Windowオブジェクトメンバー一覧
Safari form inputオブジェクトメンバー一覧
Safari imagesオブジェクトメンバー一覧

参考サイト
Web Forms 2.0
HTML5 specification
DOM Level0
mozilla Web 開発者資料
NetScape Client-Side JavaScript Reference

WHATWG 4.8.1 The img element
WHATWG 4.10 Forms
A.
オブジェクトを複製する際にオブジェクト内部のプロパティに参照型の値設定されている場合
参照のままコピーするのをシャローコピー(浅いコピー)といい、内部のプロパティまでコピーするのを
ディープコピー(深いコピー)といいます。

ECMAScript 5 Part 1: Reusable CodeECMAScript 5 Part 1: Reusable CodeDeep Cloning an Object
参考にディープコピーとシャローコピーを試してみます。

実際にシャローコピーとディープコピーを確認します。

// deep copy
// http://bytes.com/topic/javascript/answers/715567-deep-cloning-object
function clone_obj(obj) {
    var c = obj instanceof Array ? [] : {};
    for (var i in obj) {
        var prop = obj[i];

        if (typeof prop == 'object') {
           if (prop instanceof Array) {
               c[i] = [];

               for (var j = 0; j < prop.length; j++) {
                   if (typeof prop[j] != 'object') {
                       c[i].push(prop[j]);
                   } else {
                       c[i].push(clone_obj(prop[j]));
                   }
               }
           } else {
               c[i] = clone_obj(prop);
           }
        } else {
           c[i] = prop;
        }
    }

    return c;
}

// shallow copy
// http://www.browserwire.com/?p=33099
function naiveClone (obj) {
  var n = {};
  for (var p in obj) {
    n[p] = obj[p];
  };
  return n;
}

Object.clone = function (o) {
  var n = Object.create(Object.getPrototypeOf(o));
  var props = Object.getOwnPropertyNames(o);
  var pName;
  for (var p in props) {
    pName = props[p];
    Object.defineProperty(n, pName, Object.getOwnPropertyDescriptor(o, pName));
  };
  return n;
};

// shallow copy
var a = { name:'nic', nums:[1,2,3] };
var b = a;
var c = naiveClone(a);
var d = Object.clone(a);

// deep copy
var e = clone_obj(a);

//
a.name = 'yaki';
console.log(a.name);
console.log(b.name);
console.log(c.name);
console.log(d.name);
console.log(e.name);

//
a.nums.shift();
console.log(a.nums);
console.log(b.nums);
console.log(c.nums);
console.log(d.nums);
console.log(e.nums);
コンソールログ
js_obj_copy_1.png
ディープコピーの場合は中身を再帰的に確認し、
空のオブジェクトを作成しプロパティをループしてコピーする必要があります。

[javascript メモ] 継承に関するメモ

A.
プロトタイプに親のインスタンスを指定して継承する方法
子のprototypeに親のインスタンスを渡すことで
プロトタイプチェーンを使い継承します。
// 親のコンストラクタ
var A = function(nickname){
  this.nickname = nickname;
};

// 親のコンストラクタにメソッドの追加
A.prototype.getName = function(){
  return this.nickname;
}

// 子のコンストラクタ
var B = function(nickname, age){
  this.age = age;
  // 親のコンストラクターを呼んでプロパティを引き継ぐ
  A.apply(this, [nickname]);
};

// プロトタイプチェーンを設定
// 親のオブジェクトをプロトタイプにつなげる
B.prototype = new A(); 

// 子にprototypeを追加したい場合 親をつなげてから
// つなげたオブジェクトに対してメソッドを追加する
B.prototype.getAgeName = function(){
  return 'Age:' + this.age  + ' Nick:' + this.nickname;
}

// 親のメソッドと結合する
B.prototype.getName = function(){
  var name = A.prototype.getName.call(this);
  return name + '(' + this.age + ')';
}

// 親のオブジェクトのプロパティが重複するので必要なら削除する
//  delete B.prototype.nickname; 
// コンストラクタを本来あるべきものに戻す
B.prototype.constructor = B; 

// インスタンスの作成
var obj = new B('nic', 20);
var obj2 = new B('yaki', 30);
console.log( obj.getName() );
console.log( obj.getAgeName() );
console.log( obj2.getName() );
console.log( obj2.getAgeName() );

console.dir( obj );
コンソールログは以下のようになります
js_inherit_1.png

結果を図で表してみると以下のようになります
js_inherit_2.png


親のコンストラクタのプロパティをcallし親のコンストラクタのprototypeをコピー
// 親のコンストラクタ
var A = function(nickname){
  this.nickname = nickname;
};

// 親のコンストラクタにメソッドの追加
A.prototype.getName = function(){
  return this.nickname;
}

// 子のコンストラクタ
var B = function(nickname, age){
  this.age = age;
  // 親のコンストラクターを呼んでプロパティを引き継ぐ
  A.apply(this, [nickname]);

  for(var p in A.prototype){
    var proto = this.constructor.prototype;
    if(!proto[p]) proto[p] = A.prototype[p];
  }
};

// メソッドを追加する
B.prototype.getAgeName = function(){
  return 'Age:' + this.age  + ' Nick:' + this.nickname;
};

// 親のメソッドと結合する
B.prototype.getName = function(){
  var name = A.prototype.getName.call(this);
  return name + '(' + this.age + ')';
}

var obj = new B('nic', 20);
var obj2 = new B('yaki', 30);
console.log( obj.getName() );
console.log( obj.getAgeName() );
console.log( obj2.getName() );
console.log( obj2.getAgeName() );

console.dir( obj );
コンソールログは以下のようになります
js_inherit_3.png

結果を図で表してみると以下のようになります
js_inherit_4.png
親のプロパティをnew時にコピーするので、あとから追加しても反映されません。
A.
JavaScriptは、コンストラクタ用に用意した関数をnewすると
オブジェクトのインスタンスを作ることが可能です。

newを行うとコンストラクタ関数の内のthisにインスタンス自身が
代入されるので、thisのプロパティに対して変数を設定する事で
インスタンス変数を作成する事ができます。

同じようにthisのプロパティに対して関数を代入するとインスタンス
メソッドの作成が行えます。

  var Person = function(nickname){
    this.nickname = nickname;
  };
  Person.prototype.getName = function(){
    return this.nickname;
  }
  var per = new Person('nicnic');


  // プロトタイプが何を示しているのか
  console.log('#プロトタイプ');
  console.log(per.__proto__ === Person.prototype); // true
  console.log(per.__proto__.__proto__ === Object.prototype); // true

  // コンストラクタが何を示しているのか
  console.log('#コンストラクタ'); 
  console.log(per.constructor === Person); // true
  console.log(per.__proto__.constructor === Person); // true
  console.log(per.__proto__.__proto__.constructor === Object); // true

  // プロトタイプ
  console.log(per.__proto__);
  console.log(per.__proto__.__proto__);
  console.log(per.__proto__.__proto__.__proto__); // null

 // ログ
  console.log('#ログ');
  console.dir(per);
  console.dir(per.getName());


上記のログから以下の図のようになっているのが確認できる
js_new_log_1.png

js_new_log_2.png

インスタンスメソッドを追加したい
コンストラクタでは、thisがインスタンスになるので
プロパティにメソッドを追加するとインスタンスメソッドを
設定する事が可能です。

  var Person = function(nickname){
    this.nickname = nickname;
    this.getName = function(){
      return this.nickname;
    }
  };
  var per1 = new Person('nic');
  var per2 = new Person('yaki');
  var per3 = new Person('star');

インスタンスを作成すると作成毎にプロパティ、
メソッドがコピーされてメモリ上に確保されます。
js_new_log_3.png

プロパティはそれぞれインスタンス毎の値を持つ必要がありますが
メソッドにおける処理はどのインスタンスでも同じなので
インスタンス作成毎にコピーして複製をつくるのはメモリ資源
の無駄使いになってしまいます。

この問題を解決するには、コンストラクタのthisにメソッドを設定
するのではなく、コンストラクタ関数.prototypeプロパティに
メソッドを追加します。

prototypeプロパティに追加したメンバは、
生成されたインスタンスから暗黙の参照されメンバの利用が可能になります。
  var Person = function(nickname){
    this.nickname = nickname;
  };
  Person.prototype.getName = function(){
    return this.nickname;
  }
  var per1 = new Person('nic');
  var per2 = new Person('yaki');
  var per3 = new Person('star');

インスタンスに指定したメンバが存在しない場合、
prototypeをたどりprototypeに指定したメンバが存在するか確認します。
js_new_log_4.png

プロトタイプの動的な特性
また、インスタンスからプロトタイプへは参照なので
プロトタイプのメンバ情報の変更はリアルタイムに
インスタンスに反映されます。

  var Person = function(nickname){
    this.nickname = nickname;
  };

  Person.prototype.getName = function(){
    return this.nickname;
  };

  var per = new Person('nic');
  var per2 = new Person('yaki');

  // メソッドをインスタンス生成後に作成
  Person.prototype.getNameHello = function(){
    return "Hello! " + this.nickname;
  };

  console.log( per.getNameHello() );
  console.log( per2.getNameHello() );

js_new_log_5.png

プロトタイプにプロパティを設定して上書きすると?
プロトタイプにプロパティを設定した場合はどうでしょう?
プロパティはインスタンスでも読み込み可能です。
インスタンスでプロパティの値を変更した場合は
プロトタイプにプロパティの変更にはならず、
インスタンスに新規にプロパティが生成されます。

プロトタイプにプロパティを設定し値を変更して確認してみます。
var Person = function(){};

Person.prototype.getName = function(){
  return this.nickname;
};

// prototypeにプロパティを設定
Person.prototype.nickname = "mike";

// インスタンスを作成
var per = new Person('nic');
var per2 = new Person('nic');

// nicknameを上書き
per.nickname = "taro";

console.log( per.getName() );
console.log( per2.getName() );

console.log( per );
console.log( per2 );

この時のコンソールログは以下のようになります
js_prototype_proto_2.png

ログの結果からnicknameに値を代入するとインスタンスのプロパティに
新規に値が作成されprototypeの値は変更されない事が確認できます。

従ってプロトタイプチェーンによってプロトタイプのプロパティを検索する前に
インスタンスのプロパティとして先に検索されるので、
nicknameに値を代入するとそれぞれ別の値を持つ事になります。
この事を図に表すと以下のようになります。
プロトタイプにプロパティを設定し上書した時の図
js_prototype_proto_1.png

関数オブジェクトのprototypeプロパティとは?
関数オブジェクトはprototypeプロパティをもっています。
関数オブジェクトがコンストラクタとして呼び出された場合
インスタンスの内部__prototype__の初期化に利用されます。

Functionオブジェクトを確認する
var Person = function(){};
console.log( typeof Person );
console.log( typeof Person.prototype );
console.dir( Person );
関数オブジェクトのprototypeプロパティ
js_log_n1.png

ECMA-262 3rd Edition翻訳 15.3 Function オブジェクト prototypeにこの仕様が定義されています。

実際にコンストラクタのプロパテ prototype と作られたオブジェクトである
インスタンスの内部プロパティ[[prototype]](__proto__)を比較してみます。
var Person = function(nickname){
  this.nickname = nickname;
};

// メソッドの作成
Person.prototype.getName = function(){
  return this.nickname;
}

// プロパティの作成
Person.prototype.myname = 'myname';

// インスタンスの作成
var per = new Person('nicnic');

// インスタンスの内部プロトタイプ[[prototype]]
console.log( per.__proto__);

// コンストラクタのプロパティ prototype
console.log( Person.prototype );

// コンストラクタのprototypeとインスタンスの__proto__を比較
console.log( per.__proto__ === Person.prototype ); // true
js_prototype_proto_3.png
コンストラクタのprototypeとインスタンスの__proto__は同じになる事が確認できました。
これによりコンストラクタのprototypeにメンバーを追加
した際に動的に反映される事しくみが理解できます。



ここからは調査メモ(未検証で不正確かもしれません)
newで何が行われているかを確認してみる。
いままでで確認したのは以下の事項である
1.新しいObjectを作成する
2.内部の[[prototype]]にコンストラクタのprototypeを代入する
3.コンストラクタを新しいObjectのコンテキストで実行する
実際試してみる
var Person = function(nickname){
  this.nickname = nickname;
};

// メソッドの作成
Person.prototype.getName = function(){
  return this.nickname;
}

// インスタンスの作成
var per = new Person('nicnic');

// newっぽい動作を真似してみる
var per2 = {};
per2.__proto__ = Person.prototype;
Person.apply(per2, ['nicnic']);

// ログ
console.log(per);
console.log(per2);

console.log(per.getName());
console.log(per2.getName());
js_prototype_proto_4.png 動作は正しそうですが、これについては正しいかは未検証です。
chromeのconsole.logのオブジェクトの名前はどこから解決してるのだろう?などは課題です。

ECMA-262 3rd Editionの仕様は、JavaScript の new 演算子の意味が参考になります。

ECMAScript5のObject.createでは第一引数に渡したオブジェクトを
プロトタイプとし、新しいオブジェクトを作ります。
従って以下のように書き換えが可能です。
var Person = function(nickname){
  this.nickname = nickname;
};

Person.prototype.getName = function(){
  return this.nickname;
}

var per = Object.create(Person.prototype);
Person.apply(per, ['nicnic']);

console.log(per);
console.log(per.getName());
js_create_cp_1.png
誤ってコンストラクタの呼び出しにnewを付け忘れた場合、thisの値が
グローバルオブジェクトになってしまうので、インスタンスプロパティのはずが
グローバルオブジェクトのプロパティに上書してしまうかもしれないので、注意が必要です。

参考サイト:
ECMA-262 3rd Edition翻訳 15.3 Function オブジェクト

[javascript] Q. 識別子とは?

A.
変数や関数、ラベルの名前はあらかじめ決められた命名規則に従って
つける必要があります。

Fifth Edition of ECMA-262 では以下のように定義されています。


1文字目に利用できる文字
UnicodeLetter
$
_
\ UnicodeEscapeSequence

2文字目以降に利用できる
IdentifierStart
UnicodeCombiningMark
UnicodeDigit
UnicodeConnectorPunctuation
\ UnicodeEscapeSequence
UnicodeLetterとは
any character in the Unicode categories "Uppercase letter (Lu)", "Lowercase letter (Ll)", "Titlecase letter (Lt)", "Modifier letter (Lm)", "Other letter (Lo)", or "Letter number (Nl)".
Uppercase letter (Lu)は字の大文字
Lowercase letter (Ll)は字の小文字
Titlecase letter (Lt)は見出し文字に使うアルファベット
Modifier letter (Lm)は文字修飾子
Letter number (Nl)はローマ数字

UnicodeCombiningMarkとは
any character in the Unicode categories "Non-spacing mark (Mn)" or "Combining spacing mark (Mc)"
Non-spacing mark (Mn)は、アクセント記号
Combining spacing mark (Mc) 他の文字

UnicodeDigitとは
any character in the Unicode category "Decimal number (Nd)"
Decimal number (Nd)は数字

UnicodeConnectorPunctuationとは
any character in the Unicode category "Connector punctuation (Pc)"
Connector punctuation (Pc)は句読点
になります。

unicodeを意識しないのであれば、
1文字目には、英字、アンダースコア、ドル記号
2文字目以降は、それに加えて数字
で識別子を決めておけば最低限の要件は満たされます。

また、あらかじめJavaScript内で使われているキーワードは利用できません。
どのようなキーワードが利用できないか確認してみましょう。

予約語
break do instanceof typeof
case else new var
catch finally return void
continue for switch while
debugger function this with
default if throw
delete in try


将来的に予約語として使われる可能性があるキーワード
class enum extends super
const export import


Strictモード用に予約されている
implements let private public yield
interface package protected static


その他にもJavaScriptのプログラム実行時にグローバルオブジェクトに追加される
標準グローバルオブジェクトのプロパティやビルトイン関数や実行環境で展開されるプロパティや関数にも注意する必要があります。

参考:Safariで展開されるキーワード
参考:Safariで展開されるキーワード2
参考:Safariで展開されるキーワード3

標準グローバルオブジェクトで追加される使われるキーワードは
以下のようになります。

グローバルオブジェクト/コンストラクタ
Boolean Number String Array
Object Function RegExp Date

グローバルオブジェクト/エラー
Error EvalError RangeError ReferenceError
SyntaxError TypeError URIError

グローバルオブジェクト/非コンストラクタ関数
decodeURI decodeURIComponent encodeURI encodeURIComponent
eval isFinite isNaN parseFloat
parseInt

グローバルオブジェクト/その他
Infinity Math NaN undefined


参考サイト:
ECMAScript web site [雑記] 識別子名に使える文字
MDN JavaScript Reference

[javascript ECMAScript5] Q. Strict Mode

A.
ECMAScript5ではStrictモードが追加されました。
Strictモードではいくつかの機能が制限されたり、
より多くの例外が投げられるようになり、
プログラムのミスがより気づきやすくなりデバックの効率の改善が期待されます。

Strictモードを利用するには文字列リテラルで"use strict" とスクリプトの先頭に記述します。
(Strictモードに対応していないブラウザでもエラーが発生しないように
文字列リテラルで表記する事になっています。)
"use strict";

Firefox 4.0b10で Strictモードを試してみます。

宣言を行っていない変数への代入
"use strict";
a = 1;
js_strict_1.png



書き込み不可のプロパティへの代入
Object.defineProperty(obj, "a", { value : 1,
                                    writable : false,
                                    enumerable : true,
                                    configurable : true});
obj.a = 2;
js_strict_2.png



削除不可のプロパティを削除
var obj = { d:1 };
Object.defineProperty(obj, "b", { value : 1,
                                    writable : false,
                                    enumerable : true,
                                    configurable : false});

delete obj.b;
js_strict_3.png


拡張不可に設定されているオブジェクトを拡張
console.log( Object.isExtensible(obj) );
Object.preventExtensions(obj);
console.log( Object.isExtensible(obj) );
obj.c = 1;
js_strict_4.png


削除不可のプロパティを削除
console.log( Object.isSealed(obj) );
Object.seal(obj);
console.log( Object.isSealed(obj) );
delete obj.d
js_strict_5.png


arguments.calleeは使えない
function test(a){
  arguments.callee;
}
test(1);
js_strict_6.png


use strict中の関数のthisはundefinedになる
function test(){
  console.log( this );
}
test();
js_strict_7.png


オブジェクトリテラルで同じプロパティ名を使う
function test(a){
  arguments.callee;
}
test(1);
js_strict_8.png


8進数リテラルは例外発生
var oct = 011;
js_strict_9.png


undefinedに代入不可
undefined = 1;
js_strict_10.png


NaNには代入できない
NaN = 1;
js_strict_11.png


Infinityには代入できない
Infinity = 1
js_strict_12.png


参考サイト:
MDN Strict モード
ECMAScript 5 strict mode in Firefox 4

[javascript] Q. 変数の宣言したい

A.
JavaScriptで変数を宣言するには var キーワードを使います。
var 識別子;
複数の値を一度に宣言するにはカンマ(,)で区切ります。
var 識別子, 識別子, 識別子;
変数を宣言して、その変数に代入を行ってみます。
var a;
a = "A";
変数の宣言と代入を同時に行ってみます。
var a = "A";
b = "B";
varを付けないで変数を宣言しない場合は厳密には違いがあります。
その違いを確認してみます。

まずは、宣言した変数がどの段階で利用できるようになるのか確認しましょう。

varを付けて宣言した場合
console.log(a); // undefined
var a = "A";
console.log(a); // A
宣言より前で利用できる状態になっています。
これは、varで宣言された場合変数はプログラムが実行される前の段階で
Globalオブジェクトのプロパティに値はundefinedで設定されるからです。

var無し宣言した場合
console.log(a); // ReferenceError: Can't find variable: a
a = "A";
代入の実行段階でGlobalオブジェクトのプロパティに設定するという
意味になるので、実行以前に呼び出すとエラーが発生します。

varで宣言した変数はdeleteできない
var a = "A";
b = "B";
console.log( delete a ); // false
console.log( delete b ); // true
varで宣言した変数はECMAScript3実装の用語で表すと内部属性のDontDelete属性で
Globalオブジェクトのプロパティに設定されます。
この属性が設定されているプロパティは削除する事ができないので
deleteがfalseになります。

ECMAScript5では、オブジェクトの属性が変更できるようになりました。
ECMAScript3のDontDelete属性は、ECMAScript5 Configurableという属性 で表されています。
実際にvarをつけた場合と無しの場合の値を確認してみましょう。
var a = "A";
b = "B";
console.log( Object.getOwnPropertyDescriptor(this, "a") );
console.log( Object.getOwnPropertyDescriptor(this, "b") );
console.log( delete a ); // false
console.log( delete b ); // true
実行結果
js_val_1.png
varを付けた宣言の場合は configurableがfalseになっているのが
確認できます。falseの場合はプロパティの削除はできません。

参考サイト
ECMA-262-5 in detail. Chapter 1. Properties and Property Descriptors.
ECMA-262-3 in detail. Chapter 2. Variable object.
MDN getOwnPropertyDescriptor

[javascript] Q. クロージャとは

A.
function closure() {
  var  count = 0;
  return function() {
    return ++count;
  }
}
var counter = closure();
console.log( counter() ); // 1
console.log( counter() ); // 2
console.log( counter() ); // 3

このプログラムの動作を確認してみましょう。
1. closure関数を実行して、グローバル変数counterに返却された無名関数を代入します。
2. counterには無名関数が入っているので実行するとcountの値がインクリメントされます。

プログラムの内部ではどのように動作しているのでしょうか?
1.でclosure関数を実行した際にActivationオブジェクトが生成されます。
返却された無名関数の中でActivationオブジェクトに関連づけられている変数countが
利用されているのでActivationオブジェクトが生き続けます。
故にスコープチェーンが生き続け変数countの値が保持されつづけます。

closure関数を実行して別の変数にも返却された無名関数を代入して動作を確認してみましょう。
function closure() {
  var  count = 0;
  return function() {
    return ++count;
  }
}
var counter = closure();
console.log( counter() ); // 1
console.log( counter() ); // 2

var counter2 = closure();
console.log( counter2() ); // 1
console.log( counter() ); // 3

countの値はそれぞれ独立して増えている事が確認できます。
これは関数を実行した時に新たにActivationオブジェクトが生成され
そのオブジェクトのプロパティとして新規にcount変数が作られ
新しくスコープチャーンも作られる為にcountの値はそれぞれ別の値になります。

[javascript] Q. スコープチェーンとは?

A.
JavaScriptはスクリプトが実行されるとグローバルオブジェクトを作成し、
グローバル関数、グローバル変数を使えるように準備します。
グローバル関数は、グローバルオブジェクトのメソッド
グローバル変数は、グローバルオブジェクトのプロパティ
であると言い換える事ができます。

ローカル変数についてみてゆきましょう。
JavaScriptでは関数が呼び出されると内部的にActivationオブジェクト(Callオブジェクト)が生成されます。
ローカル変数は、Activationオブジェクトのプロパティであると言い換える事ができます。

Activationオブジェクトは関数が呼び出させると自動的に作成され、
関数が使われてないと判断した時点で自動的に削除されます。

グローバルオブジェクトとActivationオブジェクト
js_scope_c1.png

これらのグローバルオブジェクトとActivationオブジェクトを入れ子に作成した場合
生成した順にリストに連結したリストをスコープチェーンと呼びます。
変数の解決にはこのスコープチェーンが利用されています。
スコープチェーンの先頭のオブジェクトにプロパティが定義されているか確認し、
見つからなければチェーンの次のオブジェクトに移りプロパティが定義されているか確認します。
グローバルオブジェクトまで検索し、見つからなかった場合 未定義 を返します。

js_scope_c2.png
A.
JavaScriptの関数の引数は幾つでも渡すことができます。
関数に定義されている引数と呼び出す際に渡す引数の数が異なっても
エラーは発生せず実行されます。

定義されている仮引数が2つの関数に引数を4つで呼び出してみます。
// 関数を作成
function totalprice(price, unit){
  return price * unit * 1.05;
}
// 関数を使う
var sum = totalprice(1000, 5, 200, 1000);
console.log(sum); // 5250
引数の数が異なっていてもエラーは発生しません。
渡された引数の最初の2個だけ利用されます。

関数の仮引数で指定していない残り2つの値の取得はできないのでしょうか?
関数の内部では "arguments" というオブジェクトが自動的に生成されます。
argumentsには関数の呼び出し時に渡された引数が格納されています。

argumentsの中身を確認してみましょう
// 関数を作成
function totalprice(price, unit){
  console.log(arguments);
  return price * unit * 1.05;
}
// 関数を使う
var sum = totalprice(1000, 5, 200, 1000);
argumentsオブジェクトの中身
js_arguments_1.png
arguments.lengthで引数に渡された数が確認できます。
引数の数が想定外の場合この値を利用し例外処理を行うなどが考えられます。

関数で定義した仮引数より呼び出しの引数が少ない場合の仮引数の値を確認してみます。

関数の仮引数が呼び出しの引数の数より大きい場合
// 関数を作成
function totalprice(price, unit){
  console.log(unit); // undefined
  return price * unit * 1.05;
}
// 関数を使う
var sum = totalprice(1000);
js_arguments_2.png
undefined になる事が確認できました。
undefinedになる事を利用して以下のようにデフォルト値を設定する事ができます。
// 関数を作成
function totalprice(price, unit){
  if(price == undefined) { price = 120 };
  unit = unit || 5;
  return price * unit * 1.05;
}
// 関数を使う
var sum = totalprice();
console.log(sum); // 630

[javascript] Q. 変数のスコープとは?

A.
変数を参照できる範囲を"スコープ"と呼びます。

JavaScriptのスコープは大きく分けて2つのスコープがあります。
グローバルスコープ
ローカルスコープ

グローバルスコープに属する変数はプログラムのどの部分からも参照が可能です。
JavaScriptでは関数の外側宣言した変数はグローバルのスコープになります。
関数外で宣言された変数をグローバル変数と呼びます。

ローカルスコープに属する変数は、ローカルスコープの有効範囲内でのみ参照が可能です。
JavaScriptでは関数を作成するとその関数内がローカルのスコープになります。
関数内で宣言された変数をローカル変数と呼びます。

実際に変数のスコープを確認してみましょう。

グローバル変数とローカル変数をそれぞれ別の変数名で宣言
var a = 'global'; // グローバル変数

function testFunction() {
  var b = 'local'; // ローカル変数を作成
  console.log(a); // global
  console.log(b); // local
}

// 関数を実行
testFunction();

console.log(a);	// global
console.log(b);	// Can't find variable: b
関数内(ローカル)で宣言された変数は関数外(グローバル)では参照できない事が確認できます。

グローバル変数とローカル変数をそれぞれ同じの変数名で宣言
var a = 'global'; // グローバル変数

function testFunction() {
  var a = 'local'; // ローカル変数を作成
  console.log(a); // local
}

// 関数を実行
testFunction();

console.log(a);	// global
スコープが異なるので、同じ変数名が使われても別の変数として扱われます。

グローバル変数とローカル変数をそれぞれ同じの変数名だがvar命令なしで宣言
var a = 'global'; // グローバル変数

function testFunction() {
  a = 'local'; // var命令を使わない
  console.log(a); // local
}

// 関数を実行
testFunction();

console.log(a);	// local が表示される
変数名にvar 宣言をつけない場合グローバル変数として扱われるので
関数内でも同じ変数として認識されるので注意が必要です。

またJavaScriptにはブロックにおけるスコープは無いので他の言語で
この概念に慣れている人は注意が必要になります。
var a = 'hoge';
if (true) {
  var a = 'test';
}
console.log(a); // test

関数の仮引数のスコープについて
仮引数とは関数が呼び出される時に渡される値を一時的に保存する変数です。
関数の仮引数は、ローカル変数として処理されます。
var x = 10;
function calc(x){
  x = x * 10;
  return x;
}
console.log(calc(10)); // 100
console.log(x); // 10
関数の内部でxの値が100になります。
しかしながら関数の外ではxはグローバル関数なので
変更の影響を受けず10のままです。

仮引数に基本型の値をを渡した場合については、
仮引数の内容を変更してもグローバル変数で定義した値に影響を
及ぼさない事は確認できました。

参照型で渡される場合についても確認してみましょう。
var ref = ['apple', 'orange', 'remon'];
function test(ref) {
  console.log( ref.toString() ); // apple,orange,remon
  ref.shift();
  return ref;
}
console.log(test(ref).toString()); // orange,remon
console.log(ref.toString());  // orange,remon
参照型の変数が渡されると仮引数には参照値が渡されます。
仮引数で保存されているのは、渡された変数の参照なので
仮引数の操作を加えると、参照元の実際の値が操作されるので
呼び出し元の変数も影響は受けます。

関数の仮引数で、参照型の値を使い値を操作する時には
呼び出し元の変数の値にも影響するので注意して操作を行う必要があります。