B-Teck!

お仕事からゲームまで幅広く

【JavaScript】スプレッド演算子

配列の展開

const value = [2, 3, 1, 4, 5];
console.log(Math.max(...value));

シャローコピー

// 配列の複製
let a = [1, 2, 3];
let b = [...a];
console.log(b); //[ 1, 2, 3 ]

// シャローコピーなので多次元配列やオブジェクト等は影響を受けてしまう
let c = [[1], [2], [3]];
let d = [...c];
c[0][0] = 0;
console.log(c); // [ [ 0 ], [ 2 ], [ 3 ] ]

配列の連結

let a = [0, 1, 2];
let b = [3, 4, 5];
let c = [...a, ...b];

console.log(c); // [ 0, 1, 2, 3, 4, 5 ]
a.push(...b);
console.log(a); // [ 0, 1, 2, 3, 4, 5 ]

配列の分割代入

let [a, ...other] = [1, 2, 3];
console.log(a, other); // 1 [ 2, 3 ]

iterableなオブジェクトを展開できる

String、NodeList、HTMLCollection等…

let sample = "sample";
console.log([...sample]); // [ 's', 'a', 'm', 'p', 'l', 'e' ]

【JavaScript/jQuery】要素を切り替えるスライダー

しくみ

f:id:beatdjam:20180226022435p:plain

さんぷる

See the Pen VQEZwM by baetdjam (@beatdjam) on CodePen.

こーど

  • js
$(window).on('load',function(){
    class slider{
        constructor(time, slideId, innerArea, prevBtn, nextBtn){
            this.slideId = slideId;
            this.innerArea = innerArea;
            this.defaultLeftVal = $(this.slideId).css("left");
            this.time = time;
            //ボタン制御
            $(prevBtn).click(()=>{this.move(false)});
            $(nextBtn).click(()=>{this.move(true)});
        }
        move(isNext){
            // 実行中は再度実行させない
            if($(this.slideId).css("left") !== this.defaultLeftVal) return;
            // スクロール領域をli要素数+1の大きさで用意する
            $(this.slideId).css("width", parseInt($(this.slideId).css("width")) * ($(this.innerArea+ " li").length + 1));

            // 押されたボタンによって要素を切り替える
            if(isNext){
                var clone = this.slideId + " li:first-child";
                var insertTo = this.slideId + " li:last-child";
                var left = "-=" + $(this.innerArea).css("width");
                // 次へボタンのときはアニメーション前に要素を追加する
                if(isNext) $(insertTo).after($(clone).clone());
            }else{
                var clone = this.slideId + " li:last-child";
                var insertTo = this.slideId + " li:first-child";
                var left = "+=" + $(this.innerArea).css("width");
            }
            $(this.slideId).one("transitionend webkitTransitionEnd oTransitionEnd mozTransitionEnd",()=>{
              if(!isNext) $(insertTo).before($(clone).clone());
              $(clone).remove();  
              $(this.slideId).css({
                left: this.defaultLeftVal,
                WebkitTransition: "",
                MozTransition: "",
                MsTransition: "",
                OTransition: "",
                transition: ""
              });
            });
            $(this.slideId).css({
              left: left,
              WebkitTransition: "left "+ this.time + "ms linear",
              MozTransition: "left "+ this.time + "ms linear",
              MsTransition: "left "+ this.time + "ms linear",
              OTransition: "left "+ this.time + "ms linear",
              transition: "left "+ this.time + "ms linear"
            });
        }        
    }
    var slide = new slider(600, "#slideArea", "#viewableArea", "#prev", "#next");
});
  • css
/* コメントのある行は変えても問題ない箇所 */
#viewableArea {
    overflow: hidden;
    width: 102px; /* itemのwidth+border(100px + 2px) */
}
#slideArea {
    position: relative;
    left: -102px; /* item一つ分左にずらす(102px) */
    width: 306px; /* li要素の個数分(102px * 3) */
}

#slideArea > ul{
    padding-left: 0; /* デフォルトのスタイルシート削除用 */
    list-style: none;
}
.item {
    background-color: #e7e7e7; /* list領域をわかりやすくするため */
    border:1px solid #000; /* list領域をわかりやすくするため */
    float: left;
    width: 100px; /* 変更可 */
}
  • html
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
<div id="viewableArea">
  <div id="slideArea">
    <ul>
      <li class="item">
        hoge
      </li>
      <li class="item">
        fuga
      </li>
      <li class="item">
        hoge2
      </li>
    </ul>     
  </div>  
</div>    
<button id="prev">前へ</button>
<button id="next">次へ</button>

【JavaScript】JavaScriptの変数・関数の巻き上げ(ホイスティング)

ホイスティングとは

JavaScriptは、関数内でvarで宣言した全ての変数が先頭で宣言したことになる。
この、宣言が先頭に移動する仕様をホイスティング、または宣言の巻き上げと呼ぶ。
宣言のみが先頭に移動し、代入された変数は移動しないため、
直感的ではない動作をするケースが有る。

変数の巻き上げ

var scope = 'global';

function test() {
  // 関数内のscopeの宣言のみが巻き上がるので
  // undefinedになる
  console.log(scope); 

  // 宣言は巻き上がっているので代入のみ行われる
  var scope = 'local';
  // 代入されたlocalが出力される
  console.log(scope);
}

test();

見た目上は最初のconsole.log(scope)ではglobalが出力されそうだが、
undefinedが出力される。

その原因は、test()が実際には下記のコードと等価になるせいだ。

function test() {
  // 宣言のみ先頭に移動
  var scope;
  // 値は代入されていないのでundefined
  console.log(scope); 

  scope = 'local';
  // 代入されたlocalが出力される
  console.log(scope);
}

ES2015の場合

実は、ES2015以降ではホイスティングを考慮せず記述することができる。
varではなくletまたはconstで宣言を行うと、宣言より前に使用された変数は
ReferenceErrorが出力されるようになった。

var scope = 'global';

function test() {
  // letで変数が宣言された場合、
  // 宣言は巻き上がらずReferenceErrorとなる
  console.log(scope); 

  let scope = 'local';
  console.log(scope);
}

test();

関数の巻き上げ

関数については、function文で宣言したものについては、その定義ごと巻き上がる。
変数に保持した場合は、変数のときと同様の動作となる。

function文で宣言した場合

定義ごと宣言が巻き上がるため、実行することができる。

function hoge() {
  // fuga()の定義も巻き上がっているので、  
  // 使用することができる。
  fuga();
  function fuga() {
    console.log('fuga');
  }
}

hoge();

varで宣言した場合

宣言のみ巻き上がるが、実行不可能。

function hoge() {
  // fugaの宣言のみ巻き上がるが、
  // undefinedのため関数として実行することができず
  // TypeErrorが発生する
  fuga();

  var fuga = function () {
    console.log('fuga');
  }
}
hoge();

letconstで宣言した場合

巻き上がらないため、実行不可能。

function hoge() {
  // letで宣言しているため定義が巻き上がらず、
  // ReferenceErrorが発生する
  fuga();

  let fuga = () => {
    console.log('fuga');
  }
}

hoge();