20200927のJavaScriptに関する記事は25件です。

【JavaScript】setTimeoutを使って処理のスケジューリング

JavaScriptで指定時間後に処理を実行するにはsetTimeoutを使用します。

■書き方

第二引数に与えられた実行タイミング(ミリ秒)で、第一引数に定義された処理内容を1度実行します

setTimeout(処理内容,実行タイミング(ミリ秒))

サンプルコード

以下は実行開始から5秒後にアラート表示される処理です。

example.js
var alertMessage = function(){
  alert("5秒経過しました!");
}
setTimeout(alertMessage, 5000);

関数に引数を渡す場合

example.js
function hello(name) {
  alert('Hello,' + name);
}

setTimeout(hello, 5000, 'Taro');

コールバック関数を使用する場合

example.js
function hello(name) {
  alert('Hello,' + name);
}

setTimeout(function() {
 hello('Taro');
}, 5000);

参照

window.setTimeout - Web API インターフェイス | MDN

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptを使ってTwitterのbotを作ってみた その1

JavaScriptを使ってTwitterのbotを作ってみた その1

 プログラミングを勉強し始めて約5ヵ月くらい。そろそろGitHubやQiitaを活用してみようかなと思い、アカウントを作成してみました。
今回は初投稿ということで、何の記事を書こうか迷いましたが、自分がJavaScriptを使ってTwitterのbot作りに挑戦していたときに、割とJavaScriptを使ったTwitterのbot作りに関するサイトが少ないなと感じたので、この記事を書こうと思いました。

 プログラミングでTwitterのアカウントをいじることで、今自分の使っているアカウントにフォロー機能やいいね機能などを自動化させることも出来ますし、この記事を見てくれている方がやろうとしているbot作りだって出来ます。簡単な機能だけしか使わない場合は、Twitterのbotが手軽に作れるサイトで出来ますが、プログラミングで作ることで、さらに凝った機能を搭載したbotを作ることが出来るので、すごくおすすめです!

 なお、TwitterのAPIキーの取得方法や必要なツールのインストール(node.jsやtwitterなど)方法は、他のサイトでも紹介されているので、この記事では、そういった事前作業は完了している前提で、もうコードを書くことが出来る状態から始めていきます。もし、まだAPIキーを取得していなかったり、ツールのインストールが完了していない場合は、こちらのサイトで分かりやすい説明をしてくれているので、そのサイトを参考にして取得してみましょう。

まずはtwitterのライブラリ取得と、APIキーを書くところから

bot.js
'use strict';

let twitter = require('twitter');  // twiiterモジュールを使えるようにする

let bot     = new twitter({        // ここにtwitterのbotのAPIキーを入力する
  consumer_key        : "取得したAPI Key",
  consumer_secret     : "取得したAPI seacret Key",
  access_token_key    : "取得したAccess token",
  access_token_secret : "取得したAccess token secret"
});

 まずはbotをいじるために、初期設定をしていきます。 上記のコードを書くことで、開発をすることが出来ます。

試しにコマンドを書いてみる

 さて、botを開発する際は、twitterモジュールが用意しているgetメソッド、postメソッドなどを使っていきます。(後1つありますが、そちらはほとんど使わないので、省きます。)
 そして、そのメソッドを使って、リツイートをしたり、いいねをしたりするためのコマンドを入力していきます。

bot.js
bot.post('statuses/update', {status: "これはツイートをするためのコードです!"}, function(err, tweet, res) {
  if(err) {
    console.log(err);
  }else{
    console.log(tweet);
  };
});

 言葉で説明しても分かりにくいと思うので、実際に書いてみましょう! 上記のコードは、ツイートをするためのコードです。
まずはpostメソッドを使って、その第1引数にツイートをするためのコマンドを書いています。 コマンドについては、こちらのサイトが日本語で書かれていて、すごく分かりやすいのでおすすめです!
API.jpg
 サイトに移動すると、この画面が表示されると思います。コマンドを確認したいときは、左にある【リファレンス】という項目のところにある【friends】や【favorites】などをクリックすると、見ることが出来ます。

 第2引数には、Twitterの方で決められているパラメータというものを書いていきます。今回は、ツイートをする機能を書いていくので、必須のパラメータであるstatusというキーを書きます。値には、ツイートしたい内容を書きます。

 第3引数には、関数を書いていきます。その関数の引数も3つ指定していきます。1つ目にエラーが起こった際の引数、2つ目が成功した際の引数、3つ目は詳細を表示するための引数です。(3つ目の引数は滅多に使わないと思います。)
その次にif文を書いています。これは、もしエラーが起こってしまったらそのエラーのメッセージを表示するようにしています。よく起こるエラーでは、ツイートする内容の重複が挙げられます。
試しに、自分のアカウントで、何でもいいのでツイートをしてみてください。そしたら、その後すぐに全く同じ内容のツイートをしてみてください。「ツイートが重複しています」と出ませんか?そのエラーが、botを開発する際にも適用されています。

  node bot.js

 では、ツイートが出来たか確認してみましょう。 先ほどのコードを実行するには、コマンドライン(ターミナルとかPowerShellなど)上で上記のコマンドを入力します。(bot.jsの部分はTwitterのbotを開発するファイル名)
console1.jpg
console2.jpg
ツイート内容.jpg
 エラーが起こらかった場合は、上記のようにたくさんのキーや値が表示されます。また、ツイートの方もちゃんとされているのが分かります。
私は百合がすごく大好きなので、百合botを作成しました笑

 ちなみに、成功したときは、
  console.log(tweet);
と入力して、上記の結果が表示されましたが、その結果の中にあるキーを上手く利用することで、機能を書く際に制限を付けることが出来たりするので、ものすごく重宝します。例えば、結果の中にあるtextというキーを使って、
  console.log(tweet.text);
という風に書き換えると、結果にはツイートした内容が表示されます。(今回は「ツイート検証中」)

postメソッドとgetメソッドの違い

 先ほど紹介したpostメソッドとgetメソッドの違いについて。postメソッドを使うときは、実際に機能を行いたいときに使用します。(リツイートしたり、いいねしたり、フォローしたりなど)
 一方、getメソッドは、機能は行わないで、情報だけを取得するときに使用します。(botのフォロワーを確認したり、指定したアカウントのツイート内容を取得したりなど)

まとめ

 まずは1回目として、基本的なTwitterの機能を実装するための方法について紹介していきました。まずは先ほど紹介したサイトでいろいろなコマンドを見てみて、それを実装してみるということから始めてみましょう! 実装するだけでしたら、結構簡単に出来ちゃいます!

 次回は、それらの機能を使った応用編を紹介していきたいと思います。具体的には、1回ツイートするだけでなく、指定した時間ごとに自動ツイートしてくれるようにしたり、ある内容が含まれたツイートだけいいねリツイートするようにしたり、フォロワーを確認して、まだbotがフォローしていないフォロワーのことだけフォローする方法などを紹介していきます。初めてのQiitaでの記事投稿で、うまく書けているか分かりませんが、少しでもお役に立てたらすごく嬉しいです♪ ありがとうございました!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ライブラリレスで0からJavaScriptで手書き数字認識やってみた(MNISTデータ使用)

概要

前回は学習用データとテストデータの読み込みを実装しました。
機械学習メモ - ブラウザ上でMNISTデータファイルをDrag&Dropで受け取って手書き数字をとりあえず表示する - Qiita

今回はバックプロパゲーションを実装し、実際に学習~認識までを試してみました。(中間層は1個だけ。フィルタ層とかは無し。)
ネットワークの学習の様子を可視化したかったですが、エッジ数が数万個になるので断念しました。。

データ読み込み後の画面キャプチャ

image.png

CodePen上で動作するもの

対象のデータをDrag&Dropすると、学習用データ60000個中の20000個分を学習します。※十数秒以上はかかると思います。
今回の実装だと精度は実用には耐えれないレベル。実用レベルにもっていくには結構専門知識が要りそう。

See the Pen Neural Network learning step demo using MNIST by kob58im (@kob58im) on CodePen.

参考サイト

YouTube

音量注意!!

その他


  1. 直リンクを貼るのはよろしくない気がしたので、リンク先から入手してください。今回参考にしたのはai_mook_download.zip\1\Part1\DetectApp の中にあるC#のソースコードです。(移植するのはライセンス的にまずそうだったので、答え合わせ的な使い方をしました。) 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

非同期処理async,awaitについて

非同期処理について

JavaScriptでは非同期処理を行う選択肢は主に3種類あります。
「Promise」「async,await」「Observable」です。
ここではasync,awaitについて記載します。

async,awaitの特徴

async,awaitはPromiseの派生です。
Promiseを簡略化して記載することができます。
また、非同期処理を直列で実行したい場合に入れ子にならない利点があります。
Promiseとasync,awaitは混同して利用することができます。

構文

Promiseで記載した非同期処理をasync,awaitに書き換えます。

Promise

method() {
  asyncFunction(parameter).then(closureOfSucceedCase).catch(closureOfFailureCase);
}

async, await

async method() {
  try {
    const response = await asyncFunction(parameter);
  } catch (error) {
    // 異常系処理
  }
}

PromiseをreturnするasyncFunctionの前にawaitをつけて呼び出すことで、
同期呼び出しのように呼び出すことができます。
responseにはPromiseでthen()で渡されるパラメータがセットされます。
catchケースは、Promiseでcatch()が呼ばれる時に動きます。
また、awaitを利用する処理を書いている関数には必ずasyncを書かなければなりません。
asyncが付いた関数を呼ぶ関数にもasyncをつけなければなりません。

動作する順序

下記の順で処理が動きます。
awaitは非同期処理が完了するまで次の行に移りません。

async method() {
  // ①
  try {
    // ②
    const response = await asyncFunction(parameter);
    // ③ (非同期成功時)
  } catch (error) {
    // 異常系処理
    // ③ (非同期失敗時)
  }
  // ④
}

メリット

下記のように非同期処理を連続して実行したい場合に、Promiseのような入れ子にはならず
見易くなる点がメリットです。

const response1 = await asyncFunction1(parameter);
const response2 = await asyncFunction2(parameter);
const response3 = await asyncFunction3(parameter);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSで関数の処理から本質的でない処理を分離するProxyパターン

どのような言語であり汎用的な関数の設計は
SOLID原則の単一責任の原則に基づいたほうがいいと思っています。

ただ、ビジネスロジックが入り込むと特定の処理に対し、ログやメール送信するなど
いわゆる付随する組み合わせ(Compound)な処理になっていきます。
すると、本質的な処理から付随した処理を分離しづらくなっていきます。

このようなオブジェクト指向ではうまく分離できない特徴(クラス間を横断 (cross-cutting) するような機能)をアスペクトと呼びます。

JavaScriptでは関数に対してProxyを使うことで体系的に本質でない処理を関数から分離することが出来ます。

参考:handler.apply()

// 単体テストするのはこっち(本質的な処理)
function sum(a, b) {
  return a + b
}

const handler = {
  // ロギング、メール送信などの処理を分離する
  apply: function(target, thisArg, argumentsList) {

    // 実行前にログを残す
    console.log(`args: ${argumentsList}`)

    // 引数をそのまま渡す
    const result = target(...argumentsList)

    // 結果のログや付随するメール送信などの処理など
    console.log(`result: ${result}`)

    return result
  }
}

const wrapSum = new Proxy(sum, handler)
wrapSum(1, 2)

次のように書いても同じやんと言われたらそうなんですけど、
Proxyのほうが体系的に書けるのがいいのかなと思います。

// 単体テストするのはこっち(本質的な処理)
function sum(a, b) {
  return a + b
}

function wrapSum(target, ...argumentsList) {

  // 実行前にログを残す
  console.log(`args: ${argumentsList}`)

  // 引数をそのまま渡す
  const result = target(...argumentsList)

  // 結果のログや付随するメール送信などの処理など
  console.log(`result: ${result}`)

  return result
}

wrapSum(sum, 1, 2)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

非同期処理Promiseについて

非同期処理について

JavaScriptでは非同期処理を行う選択肢は主に3種類あります。
「Promise」「async〜await」「Observable」です。
ここではPromiseについて記載します。

Promiseの特徴

非同期処理の完了を待ち合わせ、成功した場合、失敗した場合の処理を登録することができます。
また、複数の非同期処理を纏めて実行し、全ての完了を待ち合わせることもできます。

構文

利用側

一つの非同期処理を実行する

asyncFunction(parameter).then(closureOfSucceedCase).catch(closureOfFailureCase);

closureOfSucceedCaseには非同期処理が成功した時の処理を登録し、
closureOfFailureCaseには失敗したときの処理を登録することができます。

(非同期実行結果から受け取るパラメータ) => { 非同期が完了したときの処理 }

例) REST APIを呼ぶときのサンプルコード

// ①
const url = 'http://127.0.0.1:4300/newsfeeds';
// ②
this.httpClient.get(url).toPromise().then(response => {
  // ⑤ (成功時のみ)
  const newsfeeds = new Newsfeeds();
  newsfeeds.decode(response);
  resolve(new Response(newsfeeds));
  // ⑥ (成功時のみ)
}).catch(error => {
  // ⑤ (失敗時のみ)
  console.error(error);
  reject(error);
  // ⑥ (失敗時のみ)
});
// ③
console.log('非同期が終わる前に動く');
// ④

コード内に数字を埋め込みましたが、処理は数字の順に動きます。
⑤⑥は非同期処理が完了したときに呼ばれますので、③や④より後に動作します。
⑤⑥はサーバからレスポンスが返ってきたときに動作します。

複数の非同期処理の完了を待ち合わせる

下記のように記載します。

const promises = [];
promises.push(new Promise((resolve, reject) => {
  // 非同期処理を実行する
  // 非同期処理が成功したらresolve()を呼ぶ
  // 非同期処理が失敗したらreject()を呼ぶ
});
// ↑promisesに必要な分非同期処理を追加する

Promise.all(promises).then(closureOfSucceedCase).catch(closureOfFailureCase);

closureOfSucceedCaseはpromisesに登録した非同期処理が全て成功した場合に呼び出され、
closureOfFailureCaseはpromisesに登録した非同期処理が一つでも失敗した場合に呼び出されます。

提供側

Promiseを提供する処理は下記のように記載します。

asyncFunction(parameter): Promise<型> {
  return new Promise((resolve, reject) => {
    // 何か処理をする
    if (xx) {
      // 成功した場合はresolve()を呼ぶ
      // すると呼び出し元でthen()に設定したクロージャが動き出す
      // 引数にはthen()のクロージャに渡すパラメータを入れる
      resolve(data);
    } else {
      // 失敗した場合はreject()を呼ぶ
      // すると呼び出し元でcatch()に設定したクロージャが動き出す
      // 引数にはcatch()でクロージャに渡すパラメータを入れる
      reject(error);
    }
  });
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Redux ExampleのTodoListをReact Native(expo)に置き換えて解説-ToggleTodo編

Redux ExampleのTodoListをReact Native(expo)に置き換えて解説のToggleTodo編です。
AddTodo編は以下です。
Redux ExampleのTodoListをReact Native(expo)に置き換えて解説AddTodo編

注:僕は掛け出しエンジニアであり、自分の勉強としての投稿という面もあるので、もしミスや勘違い、ベストプラクティスではない、等がありましたら、コメントしていただけると幸いです。

TODOに属性を追加

まずは、todoにcomplete属性を追加してtodoが完了済みなのかactive状態なのかを判定できるようにします。初期値はfalseにしておきます。

reducers/todos.js
const todoReducers = (state = [], action) => {
    switch(action.type){
        case 'ADD_TODO':
            return [
                ...state,
                {
                    id: action.id,
                    text: action.text,
                    completed: false //追加
                }
            ]
        default:
            return state
    }
}

export default todoReducers

Todoのcompleted属性がtrueかfalseによって見た目を変えたいので、TodoListコンポーネントを修正します。

components/TodoList.js
class TodoList extends Component {
  render() {
    return (
      <View>
        <FlatList
          data={this.props.todos}
          renderItem={({ item }) => (
            <View style={styles.todoList}>
              <Text
                style={{ 
                 textDecorationLine: item.completed ? "line-through" : "none",
                }} //追加↑
              >
                {item.text}
              </Text>
            </View>
          )}
          keyExtractor={(item) => item.id.toString()}
        />
      </View>
    );
  }
}

ここで、動作確認のため、reducers/todos.jsのcompleted属性をtrueにしてみましょう。todoに斜線が引かれていると思います。

Actionからcompleted属性を操作する

次に、上記でやったtrue,falseの操作をActionを経由して操作できるようにしましょう。

まずはActionCreatorを作成します。どのtodoに横線を引くかを判別するためにidを取得します。

src/actions/index.js
let nextTodoId = 0
export const addTodo = text => ({
    type: 'ADD_TODO',
    id: nextTodoId++,
    text
})    

//追加
export const toggleTodo = (id) => {
  return {
    type: "TOGGLE_TODO",
    id,
  };
};

reducersも変更します。

reducers/todos.js
const todoReducers = (state = [], action) => {
  switch (action.type) {
    case "ADD_TODO":
      return [
        ...state,
        {
          id: action.id,
          text: action.text,
          completed: true,
        },
      ];
    case "TOGGLE_TODO": //追加
      return state.map((todo) =>
        todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
      );
    default:
      return state;
  }
};

export default todoReducers;

やっていることとしては、stateに保存されている全てのtodoについて、それぞれのidとActionCreatorに渡された、横線を引きたいtodoのidを比べて、一致したらそのtodoのcompleted属性を逆転させるというものです。

ここで、例の如くApp.jsから動作確認をしてみましょう
App.jsに以下を追加してみましょう。

App.js
import { addTodo, toggleTodo } from './actions'

store.dispatch(addTodo('Hello React!'))
store.dispatch(toggleTodo(0))

画面をみてみると斜線が引かれたtodoが追加されているはずです。

Todoをクリックしてcompleted属性を操作できるようにする

それでは、画面上からtodoの完了、未完了の操作ができるようにしましょう。mapDispatchToPropsを作成します。
これはcomponentで(今回で言えばTodoListで)dispatchをpropsとして渡せるものです。

こうすることで、component側ではthis.props.onTodoClick(id)の形で先ほどApp.jsでやったdispatch(toggleTodo(0))みたいなことができるようになります。

containers/VisibleTodoList.js
import { connect } from "react-redux";
import TodoList from "../components/TodoList";
import { toggleTodo } from "../actions"; //追加

const mapStateToProps = (state) => {
  return { todos: state.todoReducers };
};

//追加
const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id));
    },
  };
};

//追加
const VisibleTodoList = connect(mapStateToProps, mapDispatchToProps)(TodoList);
export default VisibleTodoList;

これでTodoListの方でonTodoClickが使えるようになったので、追加してみましょう。

components/TodoList.js
return (
      <View>
        <FlatList
          data={this.props.todos}
          renderItem={({ item }) => (
            <View style={styles.todoList}>
              <Text
                onPress={() => this.props.onTodoClick(item.id)}
                style={{
                  textDecorationLine: item.completed ? "line-through" : "none",
                }}
              >
                {item.text}
              </Text>
            </View>
          )}
          keyExtractor={(item) => item.id.toString()}
        />
      </View>
    );

これでtodoをクリックすると該当のtodoに斜線が引かれます。

ToggleTodo編は完成です!
お手元のシミュレーターでお試しください。
ここまでのソースコードはGitHubに上げていますのでご参考ください。

次回は表示するTodoをcompleted属性によって切り替える「FilterTodo」機能を実装していきます。

参考

Redux ExampleのTodo Listをはじめからていねいに(2)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaでTODOアプリを制作しよう9 TODOの表示を作成日時が新しい順にソートする + 期日のデフォルトを当日の日付にする

こんにちは。
今回の記事では今まで作ってきたTODOの微調整を行います。

TODOアプリ作成リンク集

1: [超基礎の理解] MVCの簡単な説明
2: [雛形を用意する] Spring Initializrで雛形を作ってHello worldしたい
3: [MySQLとの接続・設定・データの表示] MySQLに仮のデータを保存 -> 全取得 -> topに表示する
4: [POST機能] 投稿機能の実装
5: [PATCH機能] TODOの表示を切り替える
6: [JpaRepositoryの簡単な使い方] 検索機能の実装
7: [Thymeleaf テンプレートフラグメントで共通化] Headerの作成
8: [PUT機能] 編集機能の実装
9: TODOの表示を作成日時が新しい順にソートする + 期日のデフォルトを今日の日付にする(今ここ)

TODOの表示を作成日時が新しい順にする

現状の仕様ではTODOリストは作成日時が古い順に表示されるようになっています。

つまり新しいTODOは表示の一番下にくるわけです。

細かいですがこれを登録した日付順(つまり作成日時が新しい順)にソートしましょう!

ソート作業はデータを取り扱う上でついて回る作業なので結構大事です!

TodoRepositoryを編集する

java/com/example/todo/dao/TodoRepository.java
@Repository
public interface TodoRepository extends JpaRepository<TodoEntity, Long> {

    List<TodoEntity> findByTitleContaining(String searchWord);

    //↓追加する
    List<TodoEntity> findAllByOrderByCreateTimeDesc();
}

Repositoryには部分一致検索を実装するメソッドが追加されていましたが、新しくfindAllByOrderByCreateTimeDesc()を追加してやります。

こうすることでJpaRepositoryがDB上にある全データを作成日時がdescending(降順)にソートされた状態で渡してくれます。

超便利ですね!

TodoServiceを編集する

次にサービスクラスを編集します。

java/com/example/todo/TodoService.java
    public List<TodoEntity> findAllTodo() {
        //return todoRepository.findAll();
       return todoRepository.findAllByOrderByCreateTimeDesc();
    }

コメントアウトしている部分が今までの記述でしたが、先ほど作った関数を呼んでやります。

こうすることで/topで表示されているTODOのリストが作成日時の降順になります!

TODO登録フォームの日付を今日の日付にする

JSで今日の日付を取得してformに埋め込む

今回はJSを直接top.htmlに書くことにします(直接書くのはあまり良くないですが、今回はシンプルなアプリなのでよしとしましょうw)

resources/templates/top.html
<script>
    var today = new Date();
    today.setDate(today.getDate());
    var yyyy = today.getFullYear();
    var mm = ("0" + (today.getMonth() + 1)).slice(-2);
    var dd = ("0" + today.getDate()).slice(-2);
    $("#date").val(`${yyyy}-${mm}-${dd}`);
</script>

こんなスクリプトをbodyの閉じタグの直前に書いてやればOKです。

slice(-2)とする事でStringの最後の2桁だけを表示する様にしています。

こうする事で一桁の数字は01, 05のように0がついた状態で表示され、二桁の数字は0がついてない状態で表示されます(012の下2桁だけ表示するという事です。)

このTODOアプリ作成手順を参考にされている方は既に

resources/templates/top.html
<input type="date" id="date" name="deadline" class="col-9 my-0">

となっているかと思いますが、実はここでid="date"としているのでJQueryで今日の日付を渡しています。

以上で今回の微調整となります。

次回以降は例外処理について触れていきたいと思います!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascriptの構文

このチュートリアルでは、Javascriptにおける大文字小文字の区別、識別子、コメント、文、式について学べるように記載しました。

Javascriptにおける大文字小文字の区別

変数、関数、名前、クラス名など含むすべてのJavascriptは、大文字小文字を区別します。
例えば、関数にinstanceofという名前をつけることはできません。
それは、キーワードとして既に使用されているからです。
ただし、instanceOfであれば有効な関数名として使用できます。

識別子

識別子は、変数名、関数名、パラメータ名、クラス名です。識別子は1つあるいは複数の文字から成っており、以下の規則があります。

  • 最初の文字は大文字小文字の全て、アンダースコア、$のみ使用可能
  • 2文字目以降は、上記に加えて数字が使用可能

使用できる文字は、アスキー文字のみに限定されませんが拡張アスキー文字やUnicodeは推奨されていません。
識別子にはキャメルケースを使用するのが最良の方法です。
キャメルケースとは、最初の単語を小文字で開始し、次の意味を成す単語を大文字で開始することです。
以下のような例です。

counter
inArray
beginWith
redirectPage
コメント

Javascriptにおいて、コメントを記載する方法は以下の2パターンがあります。
* コメントが1行のみの場合、文頭に//を入れる
* コメントが複数行の場合、/*で初めて*/で閉じる

// this is a single-line comment

/*
* This is a block comment that can
* span multiple lines
*/
構文

Javascriptは必ずしも文末にセミコロンを必要としないが、使用することが推奨されています。
理由としては、コードが読みやすい、問題が起きたときの対処がしやすいことがあります。

var a = 10;
var b = 20;

複数の構文をまとめる場合、文の最初に中括弧{を記載し、最後に}で閉じる必要があります。

if( a > b) {
   console.log('a is greater than b');
   return 1;
}
計算式

変数aに変数bを足す構文は以下となります。

a + b;
キーワード及び予約語

Javascriptには、いくつかの予約後とキーワードが定義されています。
我々は、これらを識別名として使用はできません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

next.jsでdotenvで環境変数を設定するのは間違い!たった3分で環境変数を設定する方法

概要

・next.jsでは「.env.local」ファイルで環境変数を設定できる。
・クライアント側でも環境変数を設定したいときは接頭語に「NEXT_PUBLIC_」をつける
・開発環境は「.env.development」、本番環境は「.env.production」でそれぞれの環境変数を設定できる

環境変数を設定する(サーバー編)

next.jsでは簡単に環境変数を変更する仕組みがあります。
ルートディレクトリに「.env.local」ファイルを置き、その中で定義した環境変数はアプリの中で使うことができます。

たとえば、開発環境と本番環境で異なるデータベースを使いますよね。そんな時に「.env.local」ファイルに設定すれば環境変数をアプリ内で利用できます。

env.local
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=root
環境変数の使用.js
export async function getServerSideProps(context) {
  console.log(process.env.DB_HOST) //コンソールに「localhost」を出力(サーバー側)
  return {props: {}}
}

環境変数に他の環境変数を設定したい場合

また、「.env.local」で設定した環境変数を別の環境変数で使うには、「$」を使います。
たとえば、ホスト名にポート番号を追加したいときには以下のように定義します。

env.local
PORT=3000
HOST=http://localhost:$PORT
index.js
export async function getServerSideProps(context) {
  console.log(process.env.HOST) //コンソールに「http:localhost:3000」を出力(サーバー側)
  return {props: {}}
}

環境変数を設定する(クライアント編)

先ほどの、「.env.local」で設定した環境変数はnode.jsのみで適用されます。そのため、ブラウザ側で動くプログラムでは使うことができません、
クライアント側でも環境変数を使いたいときにはどうすればいいのでしょうか?

この問題を解決するのが環境変数の接頭語の「NEXT_PUBLIC_」です。環境変数の接頭語に「NEXT_PUBLIC_」をつければ、クライアント側でも使うことができます。
これにより、ブラウザ側、サーバー側どちらでも環境変数を利用できるのです。

env.local
NEXT_PUBLIC_TEST=client-server
index.js
export async function getServerSideProps(context) {
  console.log(process.env.NEXT_PUBLIC_TEST) //コンソールに「client-server」を出力(サーバー側)
  return {props: {}}
}

const index = () => {
  return <p>{process.env.NEXT_PUBLIC_TEST}</p>  //画面に「client-server」を出力(クライアント側)
}

export default index

環境によって読み込むファイルを変更する方法

環境ごとに読み込む環境変数を変更したい場合があります。
たとえば、開発環境では開発用のDBを使うけど、本番環境では本番用のDBを使いたいなど環境ごとにDBを切り替えたい場面などです。

そんな時は環境ごとのenvファイルを用意します。以下の4種類でそれぞれの環境変数を設定できます。
.env:全環境共通の環境変数
.env.development:開発環境(next dev)の環境変数
.env.production:本番環境(next start)の環境変数
.env.local:デフォルトの環境変数(すべての環境変数を上書き)

これの環境変数の優先順位は以下の通りです。
①.env.local
②.env.development/.env.production
③.env

基本的に、「.env」にデフォルトで全ての環境変数を設定して、「.env.development」、「.env.production」で上書きするのがいいのではないでしょうか?

参考

next.jsの環境変数の設定

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

jQueryのプラグインを複数追加したら動かない

はじめに

自分の振り返りを兼ねて、ここに記していきたいと思います。
jQueryのプラグイン「drawer.js」を新たに実装したとき、ディベロッパーツールでエラーが起きていることを発見しました。
原因と解決方法を記していきたいと思います。

原因

Uncaught TypeError: $(...).drawer is not a function at HTMLDocument. (index.html:747)
一体なんだ?と詳しくみてみると
エラー箇所はHTML内の下記に示されていました。
ただし、コード自体に誤りはなさそうでした。

<script>
$(document).ready(function() {
  $('.drawer').drawer();
});
</script>

上記の場合だけでは、反映することができず、ドロワーメニューは開くことができません。
いろいろ調べた結果、、、
今回の場合は、他のプラグインを入れていることで動かなくなっている
つまり、コンフリクト(プラグイン同士の競合) が原因でした。

解決方法

先ほどのコードに下記のコードを追加しました。

<script>
jQuery.noConflict(); 
(function($) {

$(document).ready(function() {
  $('.drawer').drawer();
});
})(jQuery);
</script>

jQuery.noConflict();を追加することで解決することができました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavascriptにおけるHello Worldの例

概要

このチュートリアルは、HTMLページにJavascriptコードを埋め込む方法について示します。

HTMLページにJavascriptを記述するには<script>要素を使用します。
HTMLページにJavascriptを記述する方法は、以下の2つがあります。

  • HTMLページに直接Javascriptコードを埋め込む
  • 外部にJavascriptコードを記載したファイルを作成し、それを参照する
HTMLページへのJavascriptコードの埋め込み

HTMLページに直接Javascriptコードを埋め込むことは、推奨されていません。
この方法で記載する場合は、検証目的にみにするべきであります。
<script>要素に記載されたJavascriptコードは、上から下まで解釈されます。

<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <title>JavaScript Hello World Example</title>
    <script>
        alert('Hello, World!');
    </script>
</head>
<body>
</body>
</html>

上の例では、<script>要素の中でalert()関数を使用することによりHello, World!メッセージを画面に表示します。

外部Javascriptファイルの読み込み

以下に、外部Javascriptファイルを使用する方法を記載します。
1.拡張子.jsのファイルを作成する(例:main.js)
2.jsファイルを保存するフォルダーを作成し、1で作成したフィアルをその中に保存する
3.HTMLファイルの<script>タグ内にsrc属性で2で作成したファイルを指定する

HTMLファイルの記載例

default.html
<!DOCTYPE html>
<html lang="jp">
<head>
    <meta charset="UTF-8">
    <title>JavaScript Hello World Example</title>
    <script src="js/mail.js"></script>
</head>
<body>
</body>
</html>

main.jsファイルに以下の内容を記載し、default.htmlを開くと"Hello, World!"とメッセージが表示される。

main.js
alert('Hello, World!');

1つのページに複数のJavascriptファイルを読み込ませる場合、表示されている順に実行される。

<script src="js/main1.js"></script>
<script src="js/main2.js"></script>

この例では先にmain1.jsが実行されその後、main2.jsが実行される。
Javascriptファイルを読み込ませる記述は、</body>タグの直前に記載するほうがよい。
それは、ページのレンダリングフェーズにおいてブランクページが表示されるからです。

async及びdefer属性

Javascriptコードのロードと実行する方法を変えるために、<script>要素内にasync及びdefar属性を使用することができます。

これらの属性はJavascriptファイルを外部に置く場合のみ作用します。
async属性は、Webブラウザに非同期にJavascriptを実行するように指示するものです。
この属性は、Javascriptファイルを順番に実行することを保証しないものです。
以下の例で言えば、必ず最初にmain.jsが実行されるわけではないということになります。

<script async src="main1.js"></script>
<script async src="main2.js"></script>

defar属性を使用すると、ドキュメントが全て解析された後にJavascriptファイルが実行されます。

default.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>JavaScript defer demonstration</title>
    <script defer src="main.js"></script>
</head>
<body>
</body>
</html>

このページでは、HTMLファイルの中でJavascriptを使用する方法について記載しました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

InstagramのDMを保存する方法

背景

最近は、LINEよりもインスタグラムのDMを使用する方が増えてきたようです。
しかし、インスタグラムのDMはメッセージを検索したり、遡りすることができません。
そこで、インスタグラムの画面から、JavaScriptを実行して、テキストとして保存する方法をご紹介します。(利用規約的にもセーフだと思います。アウトだったら消します)

手順

手順を示します。途中で失敗したら、ブラウザの更新ボタンを押して、やり直してください。

  1. PCブラウザで保存したいDM画面を開きます。https://www.instagram.com/direct/t/[番号]
  2. ブラウザの検証機能を開き、コンソール画面を開きます。
  3. 以下のコードを実行して、保存したいところまで遡ります。(量が多いと時間かかります)
timer = setInterval(() => {
  document.getElementsByClassName('frMpI  -sxBV')[0].scrollBy(0, -window.innerHeight);
}, 100)

4.保存したいところまで来たら、以下のコードで止めます。

clearInterval(timer);

5.テキストファイルとして保存します。

out = document.getElementsByClassName('VUU41')[0].innerText
let blob = new Blob([out],{type:"text/plan"});
let link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'out.txt';
link.click();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

初心者が今はやりの技術を調べてみた

目的

今回、Node.jsを使ってQiitaAPIを使っていろいろやってみようということで、今、初心者向けには何が流行っているのかを調べてみました。

調査方法

QiitaAPIを使って、「初心者」という単語を含んでいる記事を検索しました。
プログラム実行時点(2020年9月27日11時30分時点)で投稿時間が新しいものから上位100件を対象としています。

コード

// axiosモジュールを読み込む
const axios = require('axios');

// main()関数を定義する
async function main() {
    // QiitaAPIで「初心者」という単語で記事を検索する
    let response = await axios.get('https://qiita.com/api/v2/items?per_page=100&query=' + encodeURIComponent('初心者'));
    // 結果を出力する
    for (let i=0; i<response.data.length; i++) {
        console.log(response.data[i].tags[0].name);
}

main();

結果

2020年9月27日11時30分時点の結果をExcelで集計しています。
image.png

考察

やはり、初心者向けはPythonやJavaScriptの記事が多いことが分かりました。
次に多いのがPHPやRubyということで、いまだに根強い人気があるのかなという印象です。
※私が勉強したことあるJavaについては少なくなってきているという印象です。

今後

今回はExcelを使って分析しましたが、Python使って分析できるようになってみようと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptの基礎

JavaScriptの基礎を復習しました。

まだまだHTMLとCSSを組み合わせて、カレンダーを作ることを目指しています。

学習したコード

var firstName = 'myname';
var age = 32;
console.log(firstName + '' + ' is' + age);

var job, is front engineer;
job = 'driver';
is front engineer = false;

console.log(firstNa me + 'is a ' + age + ' year old ' + job +'.Is I front engineer? ' + is front engineer);
// Variable mutation
age = 'thirty two';
job ='office worker';

alert(firstName + 'is a ' + age + ' year old ' + job +'.Is I front engineer? ' + is front engineer);
 var lastName = prompt('What is my last name?');
 console.log(firstName + ' ' +lastName);

alertのメッセージをクリックして、 promptにlastName(苗字)を入力できる。

C#をJavaScriptに変換する。

var seireki=0;
        var heisei=0;
        for( seireki=1989; seireki<=2017; seireki++)
        {
            Console.log("西暦 " + seireki + "年は、");
            heisei = seireki - 1988;
            Console.log("平成 " + heisei + "年");

上のコードは、エラーが出るかもしれません。For, loopのコードを調べてみます。

今日の振り返り

JavaScriptの基礎固めして、カレンダー作りに必要なコードを覚える。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #4 サインアップページの作成

Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #3 個別記事ページの作成

サインアップ(登録)ページの作成

サインアップページ及びそのロジックを作っていきますが、難易度が一気に上がります。
一気にすべて理解しようとせず、少しずつコードを読み解いていってください。

まずはサインアップページを作ります。

pages/sign_up.vue
<template>
  <v-app id="inspire">
    <v-main>
      <v-container
        class="fill-height"
        fluid
      >
        <v-row
          align="center"
          justify="center"
        >
          <v-col
            cols="12"
            sm="8"
            md="4"
          >
            <form @submit.prevent="signUp">
              <v-card class="elevation-12">
                <v-toolbar
                  color="primary"
                  dark
                  flat
                >
                  <v-toolbar-title>SignUp form</v-toolbar-title>
                </v-toolbar>
                <v-card-text>
                  <ul v-if="errors">
                    <li v-for="(message, i) in errors.full_messages" :key="i">
                      {{ message }}
                    </li>
                  </ul>
                  <v-text-field
                    id="name"
                    v-model="name"
                    label="name"
                    name="name"
                    prepend-icon="mdi-account"
                    type="text"
                  />

                  <v-text-field
                    id="email"
                    v-model="email"
                    label="email"
                    name="email"
                    prepend-icon="mdi-email"
                    type="email"
                  />

                  <v-text-field
                    id="password"
                    v-model="password"
                    label="Password"
                    name="password"
                    prepend-icon="mdi-lock"
                    type="password"
                  />
                </v-card-text>
                <v-card-actions>
                  <v-spacer />
                  <v-btn color="primary" type="submit">
                    登録
                  </v-btn>
                </v-card-actions>
              </v-card>
            </form>
          </v-col>
        </v-row>
      </v-container>
    </v-main>
  </v-app>
</template>

<script>
export default {
  data () {
    return {
      name: '',
      email: '',
      password: '',
      errors: []
    }
  },
  methods: {
    async signUp () {
      try {
        const data = await this.$store.dispatch('signUp', {
          name: this.name,
          email: this.email,
          password: this.password
        })
        this.$store.commit('setUser', data.data)
        this.$router.push('/')
      } catch (e) {
        this.errors = e.data.errors
      }
    }
  }
}
</script>

フォームを送信するとsignUp()メソッドが発火し、storeのsignUpアクション(この後作ります)でRails APIにPOSTし、正常終了したらsetUserでユーザーデータをstoreに保存(この後作ります)。
エラーが起きたらcatchしてエラーを出力している、という形です。

参考:Vue Material Component Framework — Vuetify.js

store側の実装

ログインに関わる処理はサイト全体で共通して使いそうなので、store/index.jsに書いていきます。

store/index.js
export const state = () => ({
  user: null,
  auth: {},
  logged_in: false
})

export const getters = {
  user (state) {
    return state.user
  },
  logged_in (state) {
    return state.logged_in
  },
  auth (state) {
    return state.auth
  }
}

export const mutations = {
  setUser (state, value) {
    state.logged_in = !!value
    state.user = value
  },
  setAuth (state, value) {
    state.auth = value
  }
}

export const actions = {
  async signUp (_c, user) {
    return await this.$axios.$post('/v1/auth', user)
  }
}

ログインしているかどうかの判定に使うlogged_inに注目。
setUser(state, value) {
state.logged_in = !!value
state.user = value
},

ユーザー情報セットの際、二重否定を使うことでuserの中身があればtrue, なければfalseが入るようにしています。

axiosの拡張

続いてaxiosのデフォルト挙動を変えます。
axiosでサーバサイドと通信する度にgetter['auth']してヘッダに付与するのは冗長かつしんどいので共通化します。
また、レスポンスが返ってくるたびにアクセストークンをstoreに保存するのも毎度書いていたら辛いので一緒に共通化します。

plugins/axios.js
export default ({ $axios, store }) => {
  $axios.onRequest((config) => {
    config.headers = store.getters.auth
  })

  $axios.onResponse((response) => {
    if (response.headers['access-token']) {
      const authHeaders = {
        'access-token': response.headers['access-token'],
        client: response.headers.client,
        expiry: response.headers.expiry,
        uid: response.headers.uid
      }
      store.commit('setAuth', authHeaders)
    }
  })

  $axios.onError((error) => {
    return Promise.reject(error.response)
  })
}

nuxt.config.js
   plugins: [
+    '~/plugins/axios'
   ],

これで、以後axiosを使う度、リクエストにはアクセストークンが自動付与されて、レスポンス後はトークンがstoreに自動保存されます。

セッション永続化の準備

今のままだと認証情報はstoreに入れているだけなので、画面遷移する分には問題ないのですが、F5押下のようにリロードするとログアウト状態になってしまいます。

これを永続化するためにはトークン情報をcookieかWebStorageに保存する必要があります。

今回は簡易的な機能のためlocalStorageを使いますが、トークンをlocalStorageに保存することはセキュリティ的には弱いため、ちゃんとしたプロダクトでは避けた方が良いかもしれません。

参考:HTML5のLocal Storageを使ってはいけない(翻訳)

  • cookie:サーバサイド・クライアントサイドどちらでも読み込み書き込みできるため、SSRでも使える。ただし値セットが面倒
  • WebStorage(LocalStorage):クライアントサイドのみのため、SSRでは使えない。そのため一瞬未ログイン画面が出てしまうデメリットがあるが、pluginを入れれば超簡単にstoreを永続化できる

今回は手軽さを取ってLocalStorageを使います。

$ yarn add vuex-persistedstate
nuxt.config.js
   plugins: [
-    '~/plugins/axios'
+    '~/plugins/axios',
+    { src: '~/plugins/localStorage.js', ssr: false }
   ],
plugins/localStorage.js
import createPersistedState from 'vuex-persistedstate'

export default ({ store }) => {
  createPersistedState({
    key: 'bbs_session',
    paths: [
      'auth'
    ]
  })(store)
}

これだけの設定で、state.authbbs_sessionというlocalStorageのkeyで保存されます。
特にlocalStorageを意識することなくstate.authに値をセットするとlocalStorageにもセットされるというすぐれものです。

とはいえこれだけでは保存しているだけで、画面リロード時に読み込む処理が入っていません。
そのロジックは共通レイアウトに入れてしまいます。

共通レイアウトの修正

ここまでで機能の大部分はできました。
ですが共通レイアウトが暗く見づらい上、不要なサイドバー等があるので作り直す勢いで修正します。

また、前述の通り画面リロード時のセッション復元も作ります。

layouts/default.vue
<template>
  <v-app>
    <v-app-bar
      fixed
      app
    >
      <n-link to="/">
        <v-toolbar-title v-text="title" />
      </n-link>
      <v-spacer />
      <span v-if="logged_in">
        {{ current_user.name }}さん
      </span>
      <v-btn
        v-if="logged_in"
        icon
      >
        <v-icon>mdi-logout</v-icon>
      </v-btn>
      <v-btn
        v-else
        icon
        to="/sign_up"
        nuxt
      >
        <v-icon>mdi-account-plus</v-icon>
      </v-btn>
    </v-app-bar>
    <v-main>
      <v-container>
        <nuxt />
      </v-container>
    </v-main>
    <v-footer
      app
    >
      <span>&copy; {{ new Date().getFullYear() }}</span>
    </v-footer>
  </v-app>
</template>

<script>
export default {
  data () {
    return {
      title: 'Sample bbs'
    }
  },
  computed: {
    current_user () {
      return this.$store.getters.user
    },
    logged_in () {
      return this.$store.getters.logged_in
    }
  },
  async beforeMount () {
    const session = JSON.parse(window.localStorage.getItem('bbs_session'))
    if (session && Object.keys(session.auth).length) {
      await this.$axios.$get('/v1/auth/validate_token')
        .then(data => this.$store.commit('setUser', data.data))
        .catch(() => {
          this.$store.commit('setUser', null)
          this.$store.commit('setAuth', {})
        })
    }
  }
}
</script>

beforeMount()はCSR(クライアントサイドレンダリング)でのみ最初に実行されます。
localStorageはサーバサイドで使えないので、クライアントサイド描画されるタイミングでセッションの値を取得し、authが保存されている場合(画面更新直前までログイン状態だった場合)にvalidate_tokenを叩きにいき、user情報とauthの更新をしてログイン状態を復帰します。
無効なauthパラメータだった場合はuserとauthをクリアします(自動的にlocalStorageもクリアになります)。

ここまで組み込めば、ログイン後に画面更新してもセッション復帰する状態になるはずです。
ページを開いた直後は未ログイン状態ですが、ちょっと待てばログインになります。
このタイムラグが気になる場合はcookieで実装が必要になります。

nuxt.config.js
   vuetify: {
     customVariables: ['~/assets/variables.scss'],
     theme: {
-      dark: true,
+      dark: false,
       themes: {
-        dark: {
+        light: {
           primary: colors.blue.darken2,
           accent: colors.grey.darken3,
           secondary: colors.amber.darken3,

そして色変え。これでだいぶスッキリするはずです。

参考

Rails devise token authとNuxt.jsを連携(Twitter認証)
Nuxt.jsのStoreによるデータ保存 [vuex-persistedstate][js-cookie]

続き

Nuxt.jsで認証認可入り掲示板APIのフロントエンド部分を構築する #5 ログイン・ログアウトの実装
連載目次へ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】人生いろいろ 配列操作もいろいろ ~初級編~

こんにちは、どいこです。

タイトル、島倉千代子を意識しましたが語呂が悪い。
(♪人生いろいろ 男もいろいろ~)

今回はJavaScriptの配列操作のメソッドと
それを使った関数の例を取り上げていきます。

※「処理の流れ」はイメージしやすさを考慮して書いたため
  厳密にいうと実際の処理順とは異なる場合があります。

findIndex()

findIndex() メソッドは、配列内の指定されたテスト関数を満たす最初の要素の位置を返します。
テスト関数を満たす要素がない場合を含め、それ以外の場合は -1 を返します。
Array.prototype.findIndex() -MDN web docs

関数例

配列arrayの中から指定した文字charを部分文字列として持つ
最初の要素のインデックスを返す
ただし、配列の中に該当する要素が見つからなかった場合は-1を返す

function findIndexOfIncludeChar(array, char) {
  const result = array.findIndex(item => {
      return item.includes(char)
    })
  return result
}

処理の流れ

① findIndex()で配列の要素を頭から順番にチェック
② includes()で要素をチェック ⇒ char(該当の文字)が含まれる場合はtrueが返される
③ trueの場合は該当する要素のインデックスを返し処理を終了
  含まれる要素が見つからなかった場合は-1が返される

filter()

filter() メソッドは、与えられた関数によって実装されたテストに合格したすべての配列からなる
新しい配列を生成します。
Array.prototype.filter() -MDN web docs

関数例

与えられた配列arrayの要素から
偶数のみを取り出して新しい配列を返す
偶数値がなかった場合は空の配列を返す

function filterEvenNumber(array) {
  const evenValue = 2
  const result = array.filter(value => {
    return value % evenValue === 0
  })
  return result
}

処理の流れ

① filter()で配列の要素を順番にチェック
② 偶数(2で割り切れる値)だった場合はtrueとなり新しい配列に追加される
  奇数だった場合はfalseとなりスキップされる
③ チェックが終わったら新しい配列を返す

map()

map() メソッドは、与えられた関数を配列のすべての要素に対して呼び出し
その結果からなる新しい配列を生成します。
Array.prototype.map() -MDN web docs

関数例

配列arrayの各要素の値を2倍した新しい配列を返す

function multiplyDouble(array) {
  const doubleValue = 2
  const result = array.map(value => {
    return value * doubleValue
  })
  return result
}

処理の流れ

① map()で配列の要素に対して順番に処理を行う(値に2をかける)
② 処理を行うごとに処理後の値が新しい配列に追加される
③ 処理が終わったら新しい配列を返す

あとがき

よく使うであろう配列操作のメソッドを取り上げてみました。
次回は中級編と題して、少し難易度が上がるものを紹介する予定です。

記事を読んでいただいて、「こう書いた方がわかりやすいのでは?」などアドバイスありましたら
お気軽に頂けると幸いです。
(言い方は優しくしてくれると喜びまする :blush:

お読みいただき、ありがとうございました◎

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Webブラウザでシリアル通信を行う

他の投稿はこちら

シリアル通信を行うアプリを開発する場合、通常はネイティブアプリを選択すると思います。
今回は、Webブラウザでシリアル通信を行い、LEDを点灯させてみたいと思います。
(いわゆるLチカです)

概要

構成は以下の通りです。

Lチカ_03.png

  • シリアル通信を行うネイティブアプリを作成する
  • LEDとプログラムを組み込んだArduinoを用意する
  • ネイティブアプリ上でWebSocketサーバーを立ち上げる
  • ブラウザからネイティブアプリのWebSocketサーバーにローカルホスト接続する
  • ネイティブアプリからArduinoにシリアル通信接続する
  • ArduinoからLEDを点灯させる

デモ

VID_20200916_231755_1.gif

上記デモはFirefoxで動作しています。
通常、Webブラウザでシリアル通信というと、NodeJSや、ActiveXを使用する事が多いと思います。
また、Chromeではシリアル通信APIが実装されているようですね。

今回ご紹介した実装方法なら、特定のブラウザに依存せず、シリアル通信を実装できます。

まとめ

さて、今回はブラウザでLチカを行いましたが
WebアプリでLチカが出来るということは、Webアプリで機械制御が出来るということです。

機械制御を伴うアプリは、機械への命令の送信といった、低レイヤーのアクセスを必要とする性格上、通常はネイティブアプリとして実装します。

しかし、今回のような実装方法ですと、低レイヤーの部分だけネイティブアプリで実装し
データ分析やフロー制御など高レイヤーの部分をWebアプリに切り出すことが可能です。

機械制御の最低限の命令だけをネイティブアプリに実装し、
命令の組み合わせなど他の部分をWebアプリで実装すると
開発保守をWebアプリに寄せることが出来るので、メンテナンスコストの低下が期待できます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

nullや空文字列を厳格に判定すること

空文字列を渡したいという場合がある。(あった)
その場合、

const testFunc = (value?: string) => {
 if(value){
  //何か処理
 }
}
const result = testFunc("")

こうすると文字列はnullともundefinedとも区別されずFalseとみなされてしまう。
=こうする

const testFunc = (value?: string) => {
 if(value === ""){
  //何か処理
 }
}
const result = testFunc("")

当たり前っちゃ当たり前の話。
nullだろうが""だろうがfalseになるんだから比較省略した方が短くかけて素敵やんと思ってたが
コードの意図もわからないしバグにも繋がりかねないので厳格に判定した方が良いことを再認識。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

constで定数管理するのはヤバい!?値の変更を禁止するたった1つの方法!

概要

・constは再代入できないが参照型は変更が可能
・参照型はObject.freezeメソッドで不変な値にできる

constは変更できる

まず初めに、constで定数を定義すると再代入・再宣言ができません
そのため、次のコードでは「TypeError: Assignment to constant variable.」というエラーが発生します。

定数が変更できない例.js
const teisu = "定数です。"
teisu = "変更しました"    //エラー発生
console.log(teisu)

しかし、constは再代入することができないだけでプロパティの一部を変更することができます

定数が変更できる例.js
const teisu = ["定数です。"]
teisu[0] = "変更しました"
console.log(teisu[0])   //「変更しました」が出力

なぜconstを変更できたのか?

なぜStringは変更できなかったのに、配列の要素は変更できたのでしょうか?

これには2種類のデータ型が関連しています。
・基本型(プリミティブ型)
・参照型

テーブル.png

この2つの型は値の保存方法が異なります。
基本型は値を直接格納するのに対し、参照型は定数値の格納先のアドレスを格納します。
・基本型 ⇒ 値を格納
・参照型 ⇒ アドレスを格納

参照型と基本型.png

定数は値を変更することができません。そのため、基本型は変更すればエラーが発生しました。
しかし、参照型はアドレスを変更せず、アドレスが指している値を変更しているため変更が可能なのです。

参照先の変更.png

参照型の変更を禁止するには?

アプリを作ると定数ファイルを用意して、共通の値を管理したいことが出てきます。その場合、参照型の値も保持したい場面が出てくるでしょう。

しかし、参照型はconstで定義しても変更することができるのでした。それでは本来の目的である不変な値を維持することができません。
どうすればいいのでしょうか?

この問題を解決するのが、Object.freezeメソッドです。
このメソッドを使って定義すれば、プロパティの変更・追加・削除をしても内容が反映されません。

次のソースでは配列で定義した値をソース上は変更していますが、値を出力すると変更されていないことがわかります。

freezeメソッドで変更を禁止.js
const teisu = Object.freeze(["定数です。"])
teisu[0] = "変更しました"
console.log(teisu[0])   //「定数です。」が出力

また、Strictモードにすると TypeError エラーが発生させることができます。
これにより、定数を書き換える処理をテストの段階で取り除けるため、無駄な記述を減らせて可読性が上がります。

strictモードのエラー.js
"use strict"

const teisu = Object.freeze(["定数です。"])
teisu[0] = "変更しました"   //エラー発生
console.log(teisu[0])  

ただし、Object.freezeメソッドを使うには注意点が必要です。このメソッドはobjectの直下のプロパティーのみに適応されます。
そのため、入れ子になっているプロパティーの値は変更することができます。

入れ子のプロパティは変更可能.js
const teisu = Object.freeze(["定数です。", ["定数の中の値"]])
teisu[1][0] = "変更しました"   
console.log(teisu[1][0])   //"変更しました"

この問題を解決するために公式ではdeepFreezeメソッドを紹介しています。
このメソッドを使えば、入れ子になっている値も変更することができません。

入れ子のプロパティも変更できない.js
function deepFreeze(object) {

  // オブジェクトで定義されたプロパティ名を取得
  var propNames = Object.getOwnPropertyNames(object);

  // 自分自身を凍結する前にプロパティを凍結
  for (let name of propNames) {
    let value = object[name];

    //「値がある かつ オブジェクト型」の場合、freezeを適用
    object[name] = value && typeof value === "object" ? 
      deepFreeze(value) : value;
  }

  return Object.freeze(object);
}

var obj2 = {
  internal: {
    a: null
  }
};

deepFreeze(obj2);

obj2.internal.a = 'anotherValue'; // 非 strict モードでは暗黙に失敗
obj2.internal.a; // null

参考

MDN web docs

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript でも Python みたく`range()`したい!

はじめに

for i in range(10):
    print(i)
    # かっこいい

理屈はいいから早く見せろ!

/**
 * @param  {...number} args
 */
const range = (...args) => {
  const rangeGen = function* (from = 0, to = Infinity, step = 1) {
    for (let v = from; v < to; v += step) {
      yield v;
    }
  };

  return args.length === 0
    ? rangeGen(undefined, undefined, undefined)
    : args.length === 1
    ? rangeGen(undefined, args[0], undefined)
    : args.length === 2
    ? rangeGen(args[0], args[1], undefined)
    : rangeGen(...args);
};

for (const v of range(2, 10)) {
  console.log(v);
  // 2 ~ 9までが順番に出力される
}

なにやってんだよ?

range関数はジェネレータ関数を実行した結果を返します。引数をジェネレータ関数に振り分けるだけのラッパーです。
rangeGenがジェネレータ関数です。

  • ジェネレータってなんだよ
    • ES2015 で追加された JavaScript の比較的新しい機能です
  • 何をジェネレートすんだよ
    • 反復可能オブジェクトをジェネレートします
  • 反復ってなんだよ
    • for-of
    • スプレッド構文(...iterator)
    • 分割代入(const [hoge, huga] = iterator;)
    • とかです。多分
  • 配列じゃだめなの?
    • 無限を扱えます

詳しいジェネレータ関数の使い方は、各位ググるなりMDN読むなりしてください。

とりあえずここでは、fromからtoまでの数字を列挙することのできるやつを作っています。

おわりに

これで JavaScript でもfor (const i of range(10)) {できます。

おまけ

個人的には Python のソレは引数の順番に気を使わないといけなくて面倒だったりします。
というわけで以下(TypeScript)。

const range = function* ({
  start = 0,
  stop = Infinity,
  step = 1,
}: {
  start?: number;
  stop: number;
  step?: number;
}) {
  while (start < stop) {
    yield start;
    start += step;
  }
};

for (const v of range({ stop: 10 })) {
  console.log(v);
}

以上です。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript で Intersection Observer API を使って要素が表示されているか調べる

はじめに

JavaScript で Intersection Observer API を使って要素がビューポート内に表示されているか調べました。

概略

(async () => {
  /**
   * @param {Element} elem
   */
  const isDisplaying = (elem) => {
    return new Promise((r) => {
      const iObserver = new IntersectionObserver(([{ isIntersecting }]) => {
        r(isIntersecting);
        iObserver.unobserve(elem);
      });
      iObserver.observe(elem);
    });
  };

  console.log(
    await Promise.all(
      [...document.body.querySelectorAll('*')].map(async (elem) => ({
        elem,
        isDisplaying: await isDisplaying(elem),
      }))
    )
  );
})();

詳細

Intersection Observer API とは

スクロールによって要素(Element)がビューポート(ブラウザの表示領域)の端と「交差」するのを監視する API。
画像などの遅延読み込みや無限スクロールなどが簡単に実装できます。

↓ 簡単な使い方

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Intersection Observer API Demo</title>

    <style>
      #targetTop,
      #targetBottom {
        border: 1px solid black;
      }
    </style>
  </head>
  <body>
    <div id="targetTop">
      <p>#targetTop</p>
    </div>
    <div>
      <p>適当なスペース</p>
      <p>適当なスペース</p>
      <p>適当なスペース</p>
      <p>適当なスペース</p>
      <p>適当なスペース</p>
      <p>適当なスペース</p>
      <p>適当なスペース</p>
      <p>適当なスペース</p>
      <p>適当なスペース</p>
      <p>適当なスペース</p>
    </div>
    <div id="targetBottom">
      <p>#targetBottom</p>
    </div>

    <script>
      document.addEventListener('DOMContentLoaded', () => {
        const $targetTop = document.getElementById('targetTop');
        const $targetBottom = document.getElementById('targetBottom');

        const iObserver = new IntersectionObserver((changes) => {
          for (const change of changes) {
            console.log(change);
          }
        });
        iObserver.observe($targetTop);
        iObserver.observe($targetBottom);
      });
    </script>
  </body>
</html>

ウィンドウサイズを小さくした上でスクロールしてみてください。
#targetTop#targetBottomが画面に映ったり映らなくなったりするたびに callback が実行されIntersectionObserverEntryconsole.logされます。

Promise で同期的に扱えるようにする

概略のところでは、Promiseresolveを callback 内で呼び出すことで、awaitを使って同期的にIntersectionObserverEntryを得ることができるようにしました。
Promise.allを使って Web ページのbodyより下にあるすべての要素について一気に調べています。

おわりに

この API は実験的であるため動作が変更されるかもしれません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

通知がしたいだけならPWAでいいじゃない

本当にあるかもしれない怖い話

作成したウェブサイトを活性化させたい、サイトの更新を知らせる仕組みがあれば活性化するはず。プッシュ通知と言えばアプリ。WebViewアプリを作りましょう。ブラウザと通知機能だけだから簡単にできるでしょ?

はい分かりましたとアプリ開発経験がなかった開発会社は安い見積を提出してしまいました。

…あなたが開発会社の窓口だとしたらどうしますか?

アプリプロジェクトの難しさ

顧客が本当にやりたいことは、今までできたことが普通にできることに加えて 『通知をしたい』 だけなので安い見積しか通らない。それにも関わらずプロジェクトの難易度が高い点を以下にあげてみます。

難しさ 1. Android / iOS 両対応

コード量は大変少ないものの、Android Studio で Java(Kotlin)、Xcode で Swift も書ける要員を確保しないといけない。こんな事ができる要員はなかなかいない。

難しさ 2. WebView

WebView は標準のブラウザに比べて不自由なことだらけ。タブは複数開けないし、戻るや進むボタンもなければ、ピンチズームなんかも制限されてたり。
工数をかけて元のサイトより品質の悪い物を作ることになりがち。

難しさ 3. 開発者登録 / 開発環境

開発者登録費用(Android: 2500円くらい/初回 / iPhone: 1万円くらい/毎年)も必要、バイナリを作成して申請するのにMacも必要。

難しさ 4. OSバージョンアップ

OSのバージョンが上がった時に色々と不具合が出る可能性がある。
いつ上がるか分からないOSのバージョンアップのために開発要員を抱え続けられない。

Webプッシュ

顧客が本当にやりたいことが 『通知をしたい』 だけであれば、『アプリを作る』ことは妥当でしょうか?顧客のビジネスに全く関係のないところでリスクを増やしたり、開発物に対しては妥当だが要件に対して無駄に高額な費用を請求することになっていないか?

通知をしたいだけでよければ、Webプッシュができればよいので、既存のWebサイトをPWA化することも視野に入れて良いのではないでしょうか?

※色々書きましたが、2020/9時点では、iOS は Push通知非対応の模様。顧客とよく話し合ってください。

既存サイトの PWA (Progressive Web Apps)化

いささか大げさでしたが、PWAを知らない人に向けて『なぜ』PWAを使うのかを書いてみました。わたしも顧客との距離を縮めて妥当な提案をするべく勉強していますが、誤り等あったらご指摘頂けますと助かります。

既存のWebサイトが https のサイトであれば、いくつかのファイルを追加するだけで簡単に PWA 化できます。

  1. manifest ファイル追加
  2. icon ファイル追加
  3. service worker ファイル追加
  4. service worker 登録

https のサイトを作るのは面倒に思えますが、github のリポジトリを github pages で公開する設定にすれば、費用も手間も不要で簡単に作成できます。

github-pages.png

実際に非PWAサイトをPWA化したソースコードをgithubに公開しています。よろしければ、あわせてご参照ください。

砂漠のひつじ : github

PWA 構成

PWA化に際して追加したファイルは以下で、前述の通り非常に少ないです。
PWAフォルダの中に全部配置してポータビリティを上げたかったのですが、service worker 本体と manifest ファイルは、公開サイトのルートに配置する必要があるようでした。

manifest.json   # PWAアプリの設定。entry point など記述
sw.js           # offline でも動作可能とする service worker。
                # いくつかのイベントハンドラを記述する必要がある
pwa/
  main.js       # service worker 登録処理。定形処理。
  icons/
    icon-192x192.png    # Home Screen に配置するアイコン
    icon-512x512.png    # 起動スプラッシュアイコン

manifest ファイル追加

このファイルは特に難しくはないです。
start_url には、FQDN部分以降の起動ページの path を記述します。

https://kaku3.github.io/the-sheep-in-the-desert/ なので、
/the-sheep-in-the-desert/index.html?utm_source=homescreen と記述します。

manifest.json
{
    "name":"砂漠のひつじ",
    "short_name":"砂漠のひつじ",
    "icons": [{
        "src": "pwa/icons/icon-192x192.png",
        "sizes":"192x192",
        "type": "image/png"
      }, {
        "src": "pwa/icons/icon-512x512.png",
        "sizes":"512x512",
        "type": "image/png"
      }],
    "start_url": "/the-sheep-in-the-desert/index.html?utm_source=homescreen",
    "display": "standalone",
    "background_color": "#FFFFFF",
    "theme_color": "#FFFFFF"
}

また、index.html を修正して、manifest.json を読み込む様にします。

index.html
<head>
    ...
    <link rel="manifest" href="manifest.json">
    ...
</head>

icon ファイル追加

このファイルも特に難しくないです。
Home Screen と、起動スプラッシュ2種類用意してください。
ひょっとしたら起動スプラッシュは画像がなくても大丈夫かもしれません。

service worker ファイル追加

簡単と書きましたが、このファイルは難しいです。
ただ書くだけなら難しくないのですが、『キャッシュするファイル』を正しく管理するには、webpack などで、キャッシュ対象ファイルのバージョンを管理できる仕組みが必要と思われます。

Service Worker の処理の記述には、Workbox を利用するのがよさそうです。

sw.js 自体は、webpack を利用していない場合は urls 以外の部分はそのまま利用できるかと思います。

sw.js
// CDN から Workbox を読み込み
importScripts('https://storage.googleapis.com/workbox-cdn/releases/5.1.2/workbox-sw.js');
workbox.loadModule('workbox-strategies');

const precacheController = new workbox.precaching.PrecacheController();

// キャッシュするファイルを定義する。
const baseUrl = location.href.replace(/\/sw.js$/, '');
const urls = [
    ...
    { url:'/css/fonts.css', revision: '0.01' },
    ...
].map(o => {
    o.url = baseUrl + o.url;
    return o;
})

precacheController.addToCacheList(urls);

self.addEventListener('install', (event) => {
    event.waitUntil(precacheController.install());
});
self.addEventListener('activate', (event) => {
    event.waitUntil(precacheController.activate());
});
self.addEventListener('fetch', (event) => {
    event.respondWith(
        caches
            .match(event.request)
            .then(function(response) {
                return response ? response : fetch(event.request);
            })
    );
});

キャッシュ容量はブラウザにより異なり、ブラウザによっては50MB程度であるためサイト内のどのファイルをキャッシュするかは設計が必要になると思います。

キャッシュは以下のような形で保存されます。

cache.png

上記より分かる通り、?__WB_REVISION__={revision} パラメータつきでキャッシュするため、読み込みタグも同様に?__WB_REVISION__={revision} をつける必要があります。

index.html
<link rel="stylesheet" href="css/fonts.css?__WB_REVISION__=0.01">
main.css
.game {
    ...
    background-image: url("../image/bg.png?__WB_REVISION__=0.01");
    ...
}

読み込むファイル数にもよりますが、この部分を手動で更新するのは難しいと思いますので、実務レベルでは「パフォーマンスを確認した上で全てキャッシュしない」か「webpack」を利用するという判断になるのかなあと思います。

service worker 登録

別ファイルにする必要もなかったのですが、再利用しやすい様に別ファイルとしました。

index.html
<script src="pwa/main.js"></script>
pwa/main.js
if('serviceWorker' in navigator) {
    // service worker のファイル名を変更するのであればこの行を修正。
    const serviceWorkerJs = `${location.href}sw.js`
    console.info('register service worker : ', serviceWorkerJs)
    navigator.serviceWorker.register(serviceWorkerJs)
    .then((r) => {
        console.info('Service worker registered.', r)
    })
}

動作させるまでには試行錯誤が必要になると思います。
https 環境ではないと動作しないとありますが、localhost については http でも大丈夫でした。
また、初回のみキャッシュされる動作をしますが、毎回キャッシュを消して確認するのが大変だったので、適当に php でサーバを立てて開発しました。

php -S localhost:8000
php -S localhost:8001
php -S localhost:8002
php -S localhost:8003
...

ローカルで動作確認が済んだら、github に push して確認してみてください。
A2HS(Add to Home Screen) ダイアログが確認できれば実装完了です。
おつかれさまでした。

a2hs.jpg

おわりに

通知についての記事のはずでしたが、PWA実装確認までで時間切れでした。
次回は通知について書きたいと思います。

参考

大変分かりやすかったです。ありがとうございました。
https://qiita.com/umamichi/items/0e2b4b1c578e7335ba20

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Salesforce】VisualforceではJavaScriptだけでレコードを取得できる

SObjectModelを使う

スクリプトタグ内で以下のようにインスタンス化させる。

var contact = new SObjectModel.Contact();

あとはcontact.retrieveでレコードを取得できる。

サンプルコード

image.png

<apex:page showHeader="false" standardStylesheets="false" sidebar="false" applyHtmlTag="false" applyBodyTag="false" docType="html-5.0">
    <html xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" lang="en">

    <head>
        <meta charset="utf-8" />
        <meta http-equiv="x-ua-compatible" content="ie=edge" />
        <title>Salesforce Lightning Design System Trailhead Module</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <!-- Import the Design System style sheet -->
        <apex:slds />
    </head>
    <apex:remoteObjects>
        <apex:remoteObjectModel name="Contact" fields="Id,Name,Title,LastModifiedDate,PhotoUrl" />
    </apex:remoteObjects>

    <body>
        <!-- REQUIRED SLDS WRAPPER -->
        <div class="slds-scope">
            <!-- MASTHEAD -->
            <p class="slds-text-heading_label slds-m-bottom_small"> Salesforce Lightning Design System Visualforce Workshop </p>
            <!-- / MASTHEAD -->
            <!-- PAGE HEADER -->
            <div class="slds-page-header">
                <!-- LAYOUT GRID -->
                <div class="slds-grid">
                    <!-- GRID COL -->
                    <div class="slds-col slds-has-flexi-truncate">
                        <!-- HEADING AREA -->
                        <!-- MEDIA OBJECT = FIGURE + BODY -->
                        <div class="slds-media slds-no-space slds-grow">
                            <div class="slds-media__figure">
                                <svg aria-hidden="true" class="slds-icon slds-icon-standard-contact">
                                    <use xlink:href="{!URLFOR($Asset.SLDS, 'assets/icons/standard-sprite/svg/symbols.svg#contact')}"></use>
                                </svg>
                            </div>
                            <div class="slds-media__body">
                                <p class="slds-text-title_caps slds-line-height_reset">Contacts</p>
                                <h1 class="slds-page-header__title slds-m-right_small slds-align-middle slds-truncate" title="My Contacts">My Contacts</h1>
                            </div>
                        </div>
                        <!-- / MEDIA OBJECT -->
                        <!-- /HEADING AREA -->
                    </div>
                    <!-- ACTION BUTTONS -->
                    <div class="slds-col slds-no-flex slds-grid slds-align-top">
                        <div class="slds-button-group" role="group">
                            <button class="slds-button slds-button_neutral"> Add Contact </button>
                            <button class="slds-button slds-button_neutral"> More </button>
                        </div>
                    </div>
                    <!-- / ACTION BUTTONS -->

                </div>
                <!-- / LAYOUT GRID -->
                <!-- PAGE HEADER DETAIL ROW -->
                <ul class="slds-grid slds-page-header__detail-row">
                    <li class="slds-page-header__detail-block">
                        <p class="slds-text-title slds-truncate slds-m-bottom_xx-small" title="Field 1">Field 1</p>
                        <p class="slds-text-body_regular slds-truncate" title="Description that demonstrates truncation with a long text field">Description that demonstrates truncation with a long text field.</p>
                    </li>
                    <li class="slds-page-header__detail-block">
                        <p class="slds-text-title slds-truncate slds-m-bottom_xx-small" title="Field2 (3)">Field 2 (3)
                            <button class="slds-button slds-button_icon" aria-haspopup="true" title="More actions">
                                <svg aria-hidden="true" class="slds-button__icon slds-button__icon_small">
                                    <use xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#down"></use>
                                </svg>
                                <span class="slds-assistive-text">More Actions</span>
                            </button>
                        </p>
                        <p class="slds-text-body_regular">Multiple Values</p>
                    </li>
                    <li class="slds-page-header__detail-block">
                        <p class="slds-text-title slds-truncate slds-m-bottom_xx-small" title="Field 3">Field 3</p>
                        <a href="javascript:void(0);">Hyperlink</a>
                    </li>
                    <li class="slds-page-header__detail-block">
                        <p class="slds-text-title slds-truncate slds-m-bottom_xx-small" title="Field 4">Field 4</p>
                        <p>
                            <span title="Description (2-line truncation—must use JS to truncate).">Description (2-line truncat...</span>
                        </p>
                    </li>
                </ul>
                <!-- / PAGE HEADER DETAIL ROW -->
            </div>
            <!-- / PAGE HEADER -->
            <!-- PRIMARY CONTENT WRAPPER -->
            <div class="myapp slds-p-horizontal_medium">
                <ul id="contact-list" class="slds-has-dividers_bottom-space"></ul>
            </div>
            <!-- / PRIMARY CONTENT WRAPPER -->
            <!-- FOOTER -->
            <footer role="contentinfo" class="slds-p-around_large">
                <!-- LAYOUT GRID -->
                <div class="slds-grid slds-grid_align-spread">
                    <p class="slds-col">Salesforce Lightning Design System Example</p>
                    <p class="slds-col">&copy; Your Name Here</p>
                </div>
                <!-- / LAYOUT GRID -->
            </footer>
            <!-- / FOOTER -->
        </div>
        <!-- / REQUIRED SLDS WRAPPER -->
        <!-- JAVASCRIPT -->
        <script>
            (function () {
                var contact = new SObjectModel.Contact();
                var contactList = document.getElementById('contact-list');
                /* FUNCTION createTile */
                function createTile(record) {
                    return [
                        '<li class="slds-item">',
                        '<div class="slds-tile slds-media">',
                        '<div class="slds-media__figure">',
                        '<img class="slds-avatar slds-avatar_medium" src="', record.get('PhotoUrl'), '" alt="" />',
                        '</div>',
                        '<div class="slds-media__body">',
                        '<h3 class="slds-truncate" title="', record.get('Name'), '"><a href="javascript:void(0);">', record.get('Name'), '</a></h3>',
                        '<div class="slds-tile__detail slds-text-body_small">',
                        '<p class="slds-truncate">', record.get('Title'), '</p>',
                        '</div>',
                        '</div>',
                        '</div>',
                        '</li>'
                    ].join('');
                }
                /* FUNCTION createTile */
                contact.retrieve({
                    orderby: [{
                        LastModifiedDate: 'DESC'
                    }],
                    limit: 810
                }, function (error, records) {
                    if (error) {
                        alert(error.message);
                    } else {
                        contactList.innerHTML = records.map(createTile).join('');
                    }
                });
            })();
        </script>
        <!-- JAVASCRIPT -->
    </body>

    </html>
</apex:page>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでnew Date()で日付と時刻を取得する

プログラミング勉強日記

2020年9月27日
JSでnew Date()を使って現在の日付・時刻を取得する方法をまとめる。

基本的な使い方

 以下のようにnew Date()で現在の日付・時刻する。

var nowDate = new Date();
console.log(nowDate);
コンソール結果
Sun Sep 27 2020 09:22:20 GMT+0900 (日本標準時)

〇〇年〇月〇日を表示する

 2020年9月27日を表示するためには、getFullYear(), getMonth(), getDate()を使う。getMonth()は1月が0、2月が1となるので、getMonth()+1とする。

var nowDate = new Date();
var year = nowDate.getFullYear();
var month = nowDate.getMonth()+1;
var date = nowDate.getDate();

var today = year + '' + month + '' + date + '';
console.log(today);
コンソール結果
2020年9月27日

曜日を取得する

 曜日の取得にはgetDay()を使う。getDay()は日曜が0、月曜が1と返ってくる。

var nowDate = new Date();
var year = nowDate.getFullYear();
var month = nowDate.getMonth()+1;
var date = nowDate.getDate();

/* 曜日追加 */
var day_array = ['','','','','','','']
var day = day_array[now.getDay()];

var today = year + '' + month + '' + date + '' + '' + day + '';
console.log(today);
コンソール結果
2020年9月27日(日)

参考文献

new Date()で現在の日付・時刻を取得する【JavaScript】

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む