20200421のJavaScriptに関する記事は18件です。

インクリメンタルサーチを噛み砕く

近況報告

やあ。テックキャンプのリモートワーク化がはじまって四週間目に突入しました。我がチームはついに最終課題をパスし間も無く就職活動に入ります。そこで大きな壁,履歴書の自己開示。わたしが一番苦手とする場所です。「わたしはプログラミングでご飯食べていくってきめたの!」って叫んで内定決まればいいのに笑

さて,今日の記事は個人アプリにインクリメンタルサーチを実装のついでの忘備録です。実況感覚で書いていきます。

インクリメンタルサーチ

なにそれ

 英語でincremental search,直訳は増加検索ですね。通常の検索は検索ボタンを押すとページが更新されて検索結果が出てきますが,この検索は一文字入れるごとに非同期通信で検索結果がぽんぽん出てきます。youtubeやGoogleとか検索の予測がでますね。あれです。文字を打つごとに予測される結果が減るからデクリメンタルサーチでもいいんじゃね。ちなみに,予測の変換に履歴が出てくるのはcookieがかかわるので少々異なります。

非同期通信・・・ユーザーの望むタイミングとは別で行われる通信です。通信自体は行われています 。railsなら,ユーザーのリクエストをMVCで逐一処理してそれに応じたビューをユーザーに届けています。ただ,例えばgoogle検索で「ツイッ」まで書いたところでリダイレクトして予測変換「ツイッター」が記載されたビューに更新されたとします。検索フォームの部分だけ変わればいいのに,変化のないGoogleのロゴとかも更新されるの無駄な気がしません?痒いところに届くのが非同期通信です。私のイメージは,必要な情報だけをビューに上書きする通信です。

なんで必要?

 いちいち検索ボタンを押して読み込むより早く検索結果をユーザーに届けることができます。個人アプリのような小さい規模ではそこまで破壊力があるわけではありません。ただ,ロゴが舌なめずりしている某サイトだと通信が0.1秒遅れると売り上げが1%落ちると聞きました。1兆円の売り上げなら100億円の損失です。まさに時は金なりですね!

環境(前提)

・rails 2.5.2
・ruby 5.2.3
gem 'jquery-rails'
DBに検索対象のレコードが入っている
検索機能の実装完了前提

今回はjqueryのgemを用いるから

gem 'jquery-rails'

からのbundle install。
application.jsでjqueryが使えるように,

//= require jquery

の記述の有無を確認。

これで準備おっけー

実装(実況感覚)

検索フォームに入力するとテーブルのnameカラムを検索する機能を実装していきます。

インデックスの実装

インデックスってなんだっけ?笑

カリキュラムを見直すと,検索の際にどれを検索すればいいのかをピックアップしてくれる機能なんだってさ。
UFOキャッチャーで例えると,UFOが検索するための端末としたらインデックスは商品(レコード)が引っかかりやすくなるために付いているリングみたいな役割なのかな。 ワカリニクイタトエデース

ただ,インデックスは検索に用いるカラムのみを複製して1つのテーブルみたいにしてるから,作りすぎるとデータベースの容量の圧迫になるみたい。

さて,インデックスを追加していきます

$ rails g migration AddIndexTo検索したいテーブルs

実行したら,マイグレーションファイルに飛んで

class AddIndexTo検索したいテーブル名 < ActiveRecord::Migration
  def change
    add_index :検索したいテーブルs, :検索したいカラム, length: 32(最大文字数)
  end
end

を記述したらマイグレート。ミスったらDB:rollbackなれdb:dropとなれ。

APIの準備

インクリメンタルサーチの実装の順番はrailsの実装とあんまり変わりません。
コントローラーに条件分岐の記入

reviews_controller.rb
  def search
    @reviews = Reviews.search(params[:keyword])
    respond_to do |format|
      format.html
      format.json
    end

formatごとのレスポンスで場合分けします。
format.htmlはhtml全部読み込みますよ,format.jsonはJS形式のみ読み込みますよって感じ。この分岐のおかげで非同期通信が可能になります。

コントローラーで条件分岐したら,DBから該当のでーたをビューまで運ぶ箱,jbuilder(パラムスに似てるね)を作成する。検索しているテーブルのビューファイルにフォルダsearch.json.jbuilderを作成。jbuilderを用いると,そのままJSでも用いることができる。

search.json.jbuilder
json.array! @reviews do |review| ←検索に引っかかった各インスタンスを配列でバラすぜ!中身は以下の通りだ!
  json.id review.id
  json.content review.content 
  json.image review.image 
  json.taste review.taste
  json.fragrance review.fragrance
  json.individuality review.individuality
  json.fruity review.fruity
  json.smorky review.smorky
  json.age review.age
  json.user_id review.user_id 
  json.user_sign_in current_user
end

テキストフィールドの実装

次はビューの作成をしていきます。検索フォームはこんな感じ↓

index.html.erb
<%= form_with(url: review_tweets_path, local: true, method: :get, class: "search-form") do |form| %>
  <%= form.text_field :keyword, placeholder: "検索する", class: "search-input" %>
  <%= form.submit "検索", class: "search-btn" %>
<% end %>

ではJSの記述に入ります。記述量が多いので少しずつ刻んでいきます。

search.js
$(function() {
  $(".search-input").on("keyup", function() { ←フォームに何か打ち込まれたら作動するよ
    var input = $(".search-input").val(); ←inputを打ちこまれた文字と定義するよ
    console.log(input); ←JSが動いているか確認。うまく表示されていたら消す。
  });
});

フォームの情報をJSON形式でコントローラーに送る

今までやったことの確認をすると,
・respond_toで行き先決定
・jbuilderでデータベースの情報の引き出し準備
・ビューでフォームの情報をJSで抽出する
うん,MVCだね。railsは非同期通信でも大まかなやることは同じです。もしこれ行こうエラーが発生したらMVCに則ってエラーを解消していきます。

search.js
$(function() {
  $(".search-input").on("keyup", function() {
    var input = $(".search-input").val();
//以下を追加
    $.ajax({ ←ajaxは非同期通信するよ!っていう合図
      type: 'GET', ←HTTPメソッドはDBを得るからGET
      url: '/review/search', ←非同期通信が行われるurl
      data: { keyword: input }, ←さーばーに送信するキー。これを元にインデックスから引っ張ってくる。
      dataType: 'json'←データの形式
    })
  });
});

これでフォームの情報はJSON形式で送られ,コントローラーのrespond_toでJSONに振り分けられてモデルに進みます。多分。

非同期通信がビューまで届いているか確認します。メソッドdoneを用いて届いた情報をみてみる。

search.js
$(function() {
  $(".search-input").on("keyup", function() {
    var input = $(".search-input").val();
    $.ajax({
      type: 'GET',
      url: '/review/search',
      data: { keyword: input },
      dataType: 'json'
    })
    .done(function(reviews) {
      console.log(reviews);
    })
  });
});

事故発生。読み込めてない。。。順番に確認していこう。
JSは読み込めていたから,クラスのミスはない。
ajaxの読み込みミスは、、、url間違えていました、、、
分岐は誤字なし,jbuilderは、、、nameを書き忘れる痛恨のミス!何調べようとしてたんだ

も一回検索フォームにキーワードを打ち込む、、、うん、うまくいった!!!

スクリーンショット 2020-04-21 19.21.46.png

さて,次に進みます。次はJSを利用してHTMLを上書きします。
まずdone以下を以下のように編集します。

search.js
~省略~
    .done(function(reviews) { ←reviewを引張ってきたから以下の実行するよ
      $(".showZone").empty(); ←該当クラスの中の子要素全て消すね
      if (reviews.length !== 0) { ←もし1でもあったら
        reviews.forEach(function(review){ ←1つずつ並べて
          appendReview(review); ←そのレコードを出現させるよ
        });
      }
      else {
        appendErrMsgToHTML("一致するツイートがありません");
      }
    })
~省略~

次はappendReview(review)に該当する定義を作成してクラスshowZoneに上書きするHTMLを作成します。

search.js

$(function() {

  var search_list = $(".showZone"); ←こういうやつは先に定義にしとく

  function appendReview(review) {
    var html = `<div class="reviewWhisky">
            <a href="/reviews/${review.id}">
            <div class="topZone">
              <div class="topZone__image">
                <img id="goShowPage" src="${review.image.url}" width="180" height="180">
              </div>
             <div class="bottomZone">
             <p>${review.name}</p>
            </div></div></a></div>`
   //htmlは検証からコピーが最速。データベースからの読み込み表示は上の書き方参考にしてね
    search_list.append(html);
  }
  function appendErrMsgToHTML(msg) {
    var html = `<div class='name'>${ msg }</div>`
    search_list.append(html);
  $(".search-input").on("keyup", function() {
    var input = $(".search-input").val();
    $.ajax({
      type: 'GET',
      url: '/reviews/search',
      data: { keyword: input },
      dataType: 'json'
    })
    .done(function(reviews) {
      search_list.empty();
      if (reviews.length !== 0) {
        reviews.forEach(function(review){
          appendReview(review); ←appendHTML召喚のメソッドと覚えておけばOK
        });
      }
      else {
        appendErrMsgToHTML("一致するのがありません");
      }
    })
  });
});

では,もし何も投稿が該当しなかった時用のを用意しましょ。いま一枚もない場合,何も写っていない状態だから,バグじゃないよーてわかるような記述を書きますappendErrMsgToHTMLに意味を持たせます)。

search.js
~省略~
    search_list.append(html);
  }
  function appendErrMsgToHTML(msg) {
    var html = `<div class='name'>${ msg }</div>`←新しい要素なので必要ならCSS
    search_list.append(html);
~省略~
    .fail(function() {←うまく行かなかった時用にエラー表示を準備
      alert('error');
    });
  });
});

これで一通り完成かな。ちなみに中の人はキータ執筆と同時進行で行なっていたのですが,search.jsファイルが読み込まれなくなる不具合に遭遇し2時間詰みました笑

解決策としては別のファイルを作成して作り直したらうまくいきまっした、、よかった、、、ただ,何が原因のエラーだったんだろう。。。

 おわりに

 まあなんとか実装できました。非同期通信のjsはコード1つ1つがわかりやすいので比較的サクッといけますね。非同期通信で重要なのは,通信の根本はMVCであること!

余談

 非同期通信とturbolinks(以下TB)は仲が悪いみたいです。TBってなんやねんって話ですよね。カリキュラムでも無下に扱われていました。この子は名前の通り,リンク先に早くたどり着くため手助けをしてくれます。ただ,早くする方法というのは,余計な動きを削ること,ここではJSを起動しないことです。非同期通信はJSを用いた通信なので,turbolinksが邪魔をしてしまう可能性がある(実際邪魔する)訳ですねー。

ただ悪い子ではないので見つけ次第gemをコメントアウト!とかしないであげてください。
$(document).on('turbolinks:load', function(){
とJSの初めに打ってあげたり,link_toにつづけて
data:{"turbolinks": :false}
と打ってあげると,JSが動いてくれます

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

Linax環境におけるNode.jsの導入から利用

はじめに

投稿者の備忘録としての活用が主です。
Webの作成において役に立つNode.jsを導入します。

環境

wsl(Windows Subsystem for Linux)にインストールします。

Editor: VSCode
Shell: bash version 4.4.20
Ubuntu: 18.04.4 LTS

目次

  1. nvmの導入 >>
  2. Node.jsの導入 >>
  3. REPLを使ってみる >>
  4. ファイルを実行してみる >>

1.nvmの導入

Node.jsのバージョンを管理するためにまずnvmを導入します。
これにより、現在利用しているNode.jsのバージョンの把握や
別バージョンへの切り替えなどを行えます。

wsl
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash

終了したら、

wsl
$ source ~/.bashrc 

で、.bashrcの内容を読み込んでおきます。

wsl
$ nvm

Node Version Manager

Note: <version> refers to any version-like string nvm understands. This includes:
  - full or partial version numbers, starting with an optional "v" (0.10, v0.1.2, v1)
  - default (built-in) aliases: node, stable, unstable, iojs, system
  - custom aliases you define with `nvm alias foo`
以下略。。。

となれば、インストールが成功しています。

2.Node.jsの導入

今回、Ver. 10.14.2 のNode.jsをインストールしました。

wsl
$ nvm install v10.14.2
Downloading and installing node v10.14.2...
Downloading https://nodejs.org/dist/v10.14.2/node-v10.14.2-linux-x64.tar.xz...
###################################################################### 100.0%Computing checksum with sha256sum
Checksums matched!
Now using node v10.14.2 (npm v6.4.1)
Creating default alias: default -> v10.14.2
$ nvm use v10.14.2
Now using node v10.14.2 (npm v6.4.1)
$ node --version
v10.14.2

指定したバージョンのNode.jsがインストールされていることを確認しました。

3.REPLを使ってみる

Node.js版のコンソールだと思えばいいと思います。
(PythonのPythonコンソール的な感じ)
Ctrl+c二回でREPLを終了できます。

REPL
$ node
> 1+1
2
>
(To exit, press ^C again or type .exit)
> 

4.ファイルを実行してみる

プログラムの書き方は、JavaScriptと同じかきかたをすればいいと思います。
今回単純な足し算プログラムを書いて動かします。

ソースコード

sum.js
'use strict';
function aAdd(num) {
    var res = 0;
    num[0] = 0;
    num[1] = 0;
    for (let s of num) {
        res += parseInt(s);
    }
    console.log(res);
}
aAdd(process.argv);

実行結果

wsl
$ node sum.js 1 2 3 4
10
$ node sum.js      
0

雑に解説

これは、引数の総和をとるプログラムでした。
process.argvに命令がリストとして入っています。
$ node sum.js 1 1 1 2 3を実行したとすると、
リストの中身は、

[ '/home/yosse95ai/.nvm/versions/node/v10.14.2/bin/node',
  '/home/yosse95ai/sum.js',
  '1',
  '1',
  '1',
  '2',
  '3' ]

といった具合になっています。

だから、

num[0] = 0;
num[1] = 0;

の部分で数字以外の文字列部分(パス部分)を、0に置き換えてます。
多分もっとクレバーなやり方があると思います。

おわりに

今回は、かなり初歩的な解説でした。
まだ自分が初心者なので、頭の整理を兼ねて書きました。
おそらく拙い文章でしたが、お付き合いいただきありがとうございました。
さよなら:wave:

参考

関連記事

~Coming soon~

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

Linux環境におけるNode.jsの導入から利用

はじめに

投稿者の備忘録としての活用が主です。
Webの作成において役に立つNode.jsを導入します。

環境

wsl(Windows Subsystem for Linux)にインストールします。

Editor: VSCode
Shell: bash version 4.4.20
Ubuntu: 18.04.4 LTS

目次

  1. nvmの導入 >>
  2. Node.jsの導入 >>
  3. REPLを使ってみる >>
  4. ファイルを実行してみる >>

1.nvmの導入

Node.jsのバージョンを管理するためにまずnvmを導入します。
現在利用しているNode.jsのバージョンの把握
別バージョンへの切り替えなどを行えます。

wsl
$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | bash

終了したら、

wsl
$ source ~/.bashrc 

で、.bashrcの内容を読み込んでおきます。

wsl
$ nvm

Node Version Manager

Note: <version> refers to any version-like string nvm understands. This includes:
  - full or partial version numbers, starting with an optional "v" (0.10, v0.1.2, v1)
  - default (built-in) aliases: node, stable, unstable, iojs, system
  - custom aliases you define with `nvm alias foo`
以下略。。。

となれば、インストールが成功しています。

2.Node.jsの導入

今回、Ver. 10.14.2 のNode.jsをインストールしました。

wsl
$ nvm install v10.14.2
Downloading and installing node v10.14.2...
Downloading https://nodejs.org/dist/v10.14.2/node-v10.14.2-linux-x64.tar.xz...
###################################################################### 100.0%Computing checksum with sha256sum
Checksums matched!
Now using node v10.14.2 (npm v6.4.1)
Creating default alias: default -> v10.14.2
$ nvm use v10.14.2
Now using node v10.14.2 (npm v6.4.1)
$ node --version
v10.14.2

指定したバージョンのNode.jsがインストールされていることを確認しました。

3.REPLを使ってみる

Node.js版のコンソールだと思えばいいと思います。
(PythonのPythonコンソール的な感じ)
Ctrl+c二回でREPLを終了できます。

REPL
$ node
> 1+1
2
>
(To exit, press ^C again or type .exit)
> 

4.ファイルを実行してみる

プログラムの書き方は、JavaScriptと同じかきかたをすればいいと思います。
今回単純な足し算プログラムを書いて動かします。

ソースコード

sum.js
'use strict';
function aAdd(num) {
    var res = 0;
    num[0] = 0;
    num[1] = 0;
    for (let s of num) {
        res += parseInt(s);
    }
    console.log(res);
}
aAdd(process.argv);

実行結果

wsl
$ node sum.js 1 2 3 4
10
$ node sum.js      
0

雑に解説

これは、引数の総和をとるプログラムでした。
process.argvに命令がリストとして入っています。
$ node sum.js 1 1 1 2 3を実行したとすると、
リストの中身は、

[ '/home/yosse95ai/.nvm/versions/node/v10.14.2/bin/node',
  '/home/yosse95ai/sum.js',
  '1',
  '1',
  '1',
  '2',
  '3' ]

といった具合になっています。

だから、

num[0] = 0;
num[1] = 0;

の部分で数字以外の文字列部分(パス部分)を、0に置き換えてます。
多分もっとクレバーなやり方があると思います。

おわりに

今回は、かなり初歩的な解説でした。
まだ自分が初心者なので、頭の整理を兼ねて書きました。
おそらく拙い文章でしたが、お付き合いいただきありがとうございました。
さよなら:wave:

関連記事

参考

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

Prebid勉強メモ

$$PREBID_GLOBAL$$

  • アダプターはPREBID_GLOBAL変数を使用できない。代わりに、必要な関数をロードして直接呼び出す必要があります。 スクリーンショット 2020-04-21 21.23.40.png スクリーンショット 2020-04-21 21.28.26.png
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Kinx ライブラリ - Binary

Binary

はじめに

「見た目は JavaScript、頭脳(中身)は Ruby、(安定感は AC/DC)」 でお届けしているスクリプト言語 Kinx。言語はライブラリが命。ということでライブラリの使い方編。

今回は Binary です。

バイナリ(Binary)は配列(Array)に似ているが、保持できる値が 0x00 ~ 0xFF までのバイト列である点が異なる。内部実装的にも単純にバイトの Vector として実装されており、バイナリデータを格納するのに適している。

Binary 特殊オブジェクト

Binary にも特殊オブジェクト Binary があり、Binary オブジェクトに対して関数定義することができる。尚、後述するがバイナリデータはスプレッド演算子を使って配列と相互変換できる。以下の例はバイナリを配列に変換して配列に対して map している例となる。

Binary.toStringArray = function(bin) {
    return [...bin].map(&(e) => *e);
};
System.println([...<97, 98, 99>]);            // => [97, 98, 99]
System.println(<97, 98, 99>.toStringArray()); // => ["a", "b", "c"]

Binary

ファイル・ロード

バイナリデータは以下のように File.BINARY を指定することでファイルから読み込むこともできる。指定しなかった場合は File.TEXT と同様、文字列としてファイルを読み込む。

var file = File.load("filename", File.BINARY);

組み込み特殊メソッド

Binary には Array と同じようなメソッドが登録されている。が、基本的にバイナリ列に適用することになるため、あまり複雑なことはできない。pushpopunshiftshift は破壊的な操作を行う。

メソッド 意味
Binary.length(bin) バイナリ bin の要素数を返す。
Binary.push(bin, e) バイナリ bin の最後の要素として e を追加する。
Binary.pop(bin) バイナリ bin の最後の要素を返し、要素から削除する。
Binary.unshift(bin, e) バイナリ bin の最初の要素として e を追加する。
Binary.shift(bin) バイナリ bin の最初の要素を返し、要素から削除する。後ろの要素は順次先頭方向に移動する。
Binary.join(bin, sep, fmt) バイナリ bin の要素を全てつなげた文字列として返す。要素と要素の間は sep でつなぐ。fmt が省略された場合 "0x02x" でフォーマットされる。
Binary.reverse(bin) バイナリ bin の要素を逆順にした新たなバイナリを返す。
Binary.toString(bin, sep, fmt) バイナリ bin を文字列化して返す。デフォルトのセパレータは ", "fmt が省略された場合 "0x02x" でフォーマットされる。
Binary.apply(bin, func) func(bin) を実行する。
Binary.each(bin, callback) bin の各要素 e に対して callback(e, index) を実行する。
Binary.map(bin, callback) bin の各要素 e に対して callback(e, index) の結果の集合となる新たなバイナリを返す。
Binary.filter(bin, callback) bin の各要素 e に対して callback(e, index) の結果が真となるもののみの集合として新たなバイナリを返す。
Binary.reject(bin, callback) bin の各要素 e に対して callback(e, index) の結果が偽となるもののみの集合として新たなバイナリを返す。
Binary.reduce(bin, callback, initr) 前の要素までの結果を r (初期値は initr、指定されていなければ null)として、ary の各要素 e に対し callback(r, e) を行った最終結果を返す。
Binary.sort(bin, comp) 任意の bin の要素 e1, e2 に対する comp(e1, e2) の結果を利用して bin 全体をソートした新たなバイナリを返す。
Binary.clone(bin) bin のコピーを作成する。
Binary.println(bin) bin の各要素 e に対して System.println(e) を適用する。

特殊オペレーター

後置 [] オペレーター

バイナリの要素にアクセスする。

var e = ary[5];  // index は 0 はじまりなので 6 番目の要素

左辺値にもなり、バイト列を直接書き換えることができる。

var bin = <1,2,3,4,5>;
bin[2] = 255;
System.println(bin);  // => <0x01, 0x02, 0xff, 0x04, 0x05>

二項 + オペレーター

バイナリ同士をつなげる。右辺値がバイナリではない場合、SystemException("Unsupported Operator") 例外が発生する。

var bin = <1, 2, 3>;
var r = bin + <2, 4>;  // => <0x01, 0x02, 0x03, 0x02, 0x04>

単項 * オペレーター

単項 * オペレーターをバイナリに適用した場合、バイナリを文字列に変換する。

var a = *<97, 98, 99>;  // => "abc"

尚、文字列に単項 * オペレーターを適用すると配列になるため、バイナリには戻らない。代わりに、バイナリは下記のスプレッド演算子で配列と相互変換ができる。

スプレッド演算子

配列とバイナリで相互変換可能。配列からバイナリに変換する際は、数値であれば 0x00~0xFF の値に丸められる。文字の場合は先頭の文字のみ使われる。

var a = <97, 98, 99>; // == <0x61, 0x62, 0x63>
var b = [...a];       // => [97, 98, 99]
var c = <...b>;       // => <0x61, 0x62, 0x63>
var d = <...[1024,1025,1026,"abc"]>;  // => <0x00, 0x01, 0x02, 0x61>
                                      //    0x61 == 97 == 'a'

おわりに

バイナリデータも割と扱いたくなるので、一通り機能を揃えてみました。バイト単位でゴニョゴニョできると良いことあるかもしれない。なんとなく例えば x64 向け JIT ライブラリとか作れそうですね。

では、また次回。

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

[Jquery]ページ内リンク(スクロール)の実装

ページ内リンクへのスクロールの実装

ページ内リンクへのスクロール機能を作ってみたので復習として記録しておきます。
HPの作成などで縦に長くなって来るとスクロールでページ内の移動が出来るととても便利です。

↑こんなやつです。
こちらはヘッダーの各項目がaタグになっていてhref属性にidを指定することにより対応するidのコンテンツに移動することができるようになっています。

実装方法

では早速実装方法について見ていきます。
先ずはヘッダー部分ですが、上で述べているようにaタグのhref属性に各項目のidを指定しています。

index.html
<nav>
 <ul>
  <li ><a href="#home_btn">トップページ</a></li>
  <li ><a href="#about_btn">会社概要</a></li>
  <li ><a href="#works_btn">事業内容</a></li>
  ※省略
  <li ><a href="#contact_btn">お問い合わせ</a></li>
 </ul>
</nav>

こんな感じです。
それに対して、例えばお問い合わせの部分には

index.html
<footer class="footer" id = "contact_btn">
 <div class="content-wrapper">
  <div class="address">
   <h2>お問い合わせ</h2>
  以下省略

という具合にフッター部分のidをcontact_btnに設定してヘッダーのお問い合わせと対応させています。

scrollTopメソッド

ヘッダーの項目をクリックして下のコンテンツに移動させる為にここではscrollTopメソッドを使用します。
scrollTopメソッドとは、

$('html, body').scrollTop(値);

というように記述することにより、ページのTopから値分(px)だけ移動するというメソッドです。
例えば$('html, body').scrollTop(500); ならばトップから下へ500pxだけ移動するというものです。

animateメソッドとの合わせ技

さらに今回はscrollTopメソッドとanimateメソッドを組み合わせてスクロールにアニメーションをつけていきます。
上の記述を少しだけいじくって、

$('html, body').animate({'scrollTop': 値}, 時間); 

ここまでをJSファイルで実装すると

scroll.js
$(function() {
  var contact = $('#contact_btn'); //変数contactを定義
  contact.click(function() { //contactをクリックしたら
   $('html, body').animate({'scrollTop': 1000}, 500); //Topから1000px分だけ0.5秒かけて移動する
 }
);

という感じでしょうか?
取り敢えずこれで実装は完了です。

更に一歩踏み込んで

さて、一応完成したスクロールの実装ですが、このままですとナビゲーションの項目が増えていくと
変数var〇〇を項目の数だけ追加し・・・
それぞれの変数に対してclickイベントを設定し・・・
それぞれのコンテンツの移動距離を調べて・・・
やることが段々増えてきました?

なんとかシンプルにならんもんか?

offsetメソッドの登場

1つ1つ地道に実装するとして、一番面倒なのが移動距離を調べることかなと思われます。
この移動距離めんどくさい問題についてはoffsetメソッドが解決してくれます!!
offsetメソッドは

$('セレクタ').offset(); //上端から〇〇px,左端から〇〇pxの位置

とすることでセレクタの位置情報を取得することが出来ます。

attrメソッドで移動先を取得する。

次に、attrメソッドを使用して移動先を取得します。
attrメソッドとはHTML要素の属性を取得したり設定することができるメソッドになります。
例えば

<h1 id= "test">テスト</h1>

に対して

$('h1').attr('id');

とすると、attrメソッドによって test が取得されます。
今回はまず、attrによってaタグのherf属性から移動先を取得し、取得した移動先への距離をoffsetで取得するというわけです。

scroll.js
$(function() { 
  $('header a').click(function(){  //ヘッダーのaタグをクリック
    var id = $(this).attr('href'); //クリックしたaタグのherfの値(移動先)を取得し変数idに代入
    var position = $(id).offset().top; //上の変数idの上端からの位置情報を取得して変数positionに代入
    $('html,body').animate({'scrollTop': position},500); //0.5秒かけて変数positionで取得した距離を移動
   });
 });

これで完成!!
だいぶスッキリしました。

まとめ

今回の実装では
①各コンテンツにidを設定する。
②ヘッダーの各リンクの飛び先をページ内リンクに設定する
③scrollTop()とanimate()メソッドを使いスクロールを実装。
④attr()でリンク先を、offset()でリンク先への距離を取得し変数にする。
という感じでページ内スクロールの実装を行ってきました。

JSを本格的に勉強し出して1ヶ月弱ですが、このような動きのあるページを作れるようになり楽しくなってきたところです。
コードの書き方など至らぬ点も多々あるかも知れませんが、お気付きの点ご指摘いただけますと幸いです。

最後までお読みいただきましてありがとうございました!!

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

[JQuery]ページ内リンク(スクロール)の実装

ページ内リンクへのスクロールの実装

ページ内リンクへのスクロール機能を作ってみたので復習として記録しておきます。
HPの作成などで縦に長くなって来るとスクロールでページ内の移動が出来るととても便利です。

↑こんなやつです。
こちらはヘッダーの各項目がaタグになっていてhref属性にidを指定することにより対応するidのコンテンツに移動することができるようになっています。

実装方法

では早速実装方法について見ていきます。
先ずはヘッダー部分ですが、上で述べているようにaタグのhref属性に各項目のidを指定しています。

index.html
<nav>
 <ul>
  <li ><a href="#home_btn">トップページ</a></li>
  <li ><a href="#about_btn">会社概要</a></li>
  <li ><a href="#works_btn">事業内容</a></li>
  ※省略
  <li ><a href="#contact_btn">お問い合わせ</a></li>
 </ul>
</nav>

こんな感じです。
それに対して、例えばお問い合わせの部分には

index.html
<footer class="footer" id = "contact_btn">
 <div class="content-wrapper">
  <div class="address">
   <h2>お問い合わせ</h2>
  以下省略

という具合にフッター部分のidをcontact_btnに設定してヘッダーのお問い合わせと対応させています。

scrollTopメソッド

ヘッダーの項目をクリックして下のコンテンツに移動させる為にここではscrollTopメソッドを使用します。
scrollTopメソッドとは、

$('html, body').scrollTop(値);

というように記述することにより、ページのTopから値分(px)だけ移動するというメソッドです。
例えば$('html, body').scrollTop(500); ならばトップから下へ500pxだけ移動するというものです。

animateメソッドとの合わせ技

さらに今回はscrollTopメソッドとanimateメソッドを組み合わせてスクロールにアニメーションをつけていきます。
上の記述を少しだけいじくって、

$('html, body').animate({'scrollTop': 値}, 時間); 

ここまでをJSファイルで実装すると

scroll.js
$(function() {
  var contact = $('#contact_btn'); //変数contactを定義
  contact.click(function() { //contactをクリックしたら
   $('html, body').animate({'scrollTop': 1000}, 500); //Topから1000px分だけ0.5秒かけて移動する
 }
);

という感じでしょうか?
取り敢えずこれで実装は完了です。

更に一歩踏み込んで

さて、一応完成したスクロールの実装ですが、このままですとナビゲーションの項目が増えていくと
変数var〇〇を項目の数だけ追加し・・・
それぞれの変数に対してclickイベントを設定し・・・
それぞれのコンテンツの移動距離を調べて・・・
やることが段々増えてきました?

なんとかシンプルにならんもんか?

offsetメソッドの登場

1つ1つ地道に実装するとして、一番面倒なのが移動距離を調べることかなと思われます。
この移動距離めんどくさい問題についてはoffsetメソッドが解決してくれます!!
offsetメソッドは

$('セレクタ').offset(); //上端から〇〇px,左端から〇〇pxの位置

とすることでセレクタの位置情報を取得することが出来ます。

attrメソッドで移動先を取得する。

次に、attrメソッドを使用して移動先を取得します。
attrメソッドとはHTML要素の属性を取得したり設定することができるメソッドになります。
例えば

<h1 id= "test">テスト</h1>

に対して

$('h1').attr('id');

とすると、attrメソッドによって test が取得されます。
今回はまず、attrによってaタグのherf属性から移動先を取得し、取得した移動先への距離をoffsetで取得するというわけです。

scroll.js
$(function() { 
  $('header a').click(function(){  //ヘッダーのaタグをクリック
    var id = $(this).attr('href'); //クリックしたaタグのherfの値(移動先)を取得し変数idに代入
    var position = $(id).offset().top; //上の変数idの上端からの位置情報を取得して変数positionに代入
    $('html,body').animate({'scrollTop': position},500); //0.5秒かけて変数positionで取得した距離を移動
   });
 });

これで完成!!
だいぶスッキリしました。

まとめ

今回の実装では
①各コンテンツにidを設定する。
②ヘッダーの各リンクの飛び先をページ内リンクに設定する
③scrollTop()とanimate()メソッドを使いスクロールを実装。
④attr()でリンク先を、offset()でリンク先への距離を取得し変数にする。
という感じでページ内スクロールの実装を行ってきました。

JSを本格的に勉強し出して1ヶ月弱ですが、このような動きのあるページを作れるようになり楽しくなってきたところです。
コードの書き方など至らぬ点も多々あるかも知れませんが、お気付きの点ご指摘いただけますと幸いです。

最後までお読みいただきましてありがとうございました!!

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

Agar.ioのAntiBOTがエグすぎるまとめ

Agar.ioは超有名なゲームなので知っている方もいると思います。

agario

今回のお話はアプリ版ではなくブラウザ版のアガリオが対象です
https://agar.io/

現在は残念ながら過疎化が進んでしまいましたが、全盛期は本当に大人気でした(海外では)

人気なゲームゆえに、やはりチート(ボット)を作る人たちがいました。

2015年から始まったゲームですが、つい昨年までずっと「ボットを作る→運営がBOT対策→Bot対策を突破できる新しいBotを作る」が繰り返されてきました。

なので現在のAgar.ioのAntiBotはかなりエグイものになっていますw

私もAgar.ioを解析して独自のクライアントを作ったり、Botも作ったことがあるので、Agar.ioのBot対策がどんなものかをご紹介したいと思います。

はじめに

Agar.ioのAntiBotを紹介する前に。

まず、Agar.ioは自分より小さい敵(細胞)を食べて大きくなっていくゲームです。
たくさん食べれば食べるほど大きくなれます

つまり、Botを大量にスポーンさせて自分に向かってくるようにすれば急速に大きくなれるわけです。

Botはゲームのプロトコルを真似れば(正規のクライアントを全く同じやりとりをすれば)作ることができます。

これをするためには
通信内容を解析したり、JavaScriptで書かれたゲームのコアを解析する必要があります。
補足:Agar.ioはWebSocketを用いたリアルタイムのオンラインゲーム

これを簡単に解析されては困るので運営はBotが作られるたびに解析が困難になるように対策するのです。

Agar.ioのAntiBotまとめ

伝わりづらい部分も多々あると思いますが・・・。
順番に書いていきます

Emscriptenで出力されたコア

JavaScriptが難読化されていても根気よく読めばいける!と思いたいですが、そうでもないんですよね
Agar.ioのゲーム本体のコードはEmscriptenで出力されたJavaScriptなので非常に解読が困難です。
(EmscriptenはC/C++で書かれたコードをJSに変換できるツール)

JavaScript Obfuscatorとかで難読化されたコードなら私でも読めますが、Emscriptenで出力されたら無理です

これのせいで未だに全てのプロトコルの解析ができた人はいません(ほぼできているけど)

クライアントからサーバーに送信するメッセージがすべて暗号化されている

コードを解析できないなら、通信内容を解析すればいいんじゃね?と思いますが、これも対策が施されています

クライアントから送信されるメッセージがすべてXORで暗号化されています。

XORは以下のような性質があります

a ^ b = c
c ^ b = a

2回同じ値でxorすると元の値に戻ります
bが暗号化キーというわけです

クライアントでxor暗号化 -> 送信 -> サーバーでxor計算して複合化

という流れです

「あれ?じゃあ暗号化キー判明すれば、通信内容とのxor計算するだけで複合化されたデータを見れるんじゃね?」
と思うかもしれませんが、
実はキーは一つのパケットを送信するごとに変化するようになっています。

つまり、最初のキーがわかっても複合化できるのは一番最初に送信されるパケットだけになります。
次のパケットを解析したい場合は鍵を同じアルゴリズムで変化させなければならないのです

このアルゴリズムを解析するにはEmscriptenで出力されたコードを解析する必要があります。

サーバーから送られてくるデータも暗号化されており、圧縮されているものもある

サーバー -> クライアントでも同じようにxorで暗号化されたデータが送られてきます。
一番最初に複合化するためのキーが送られてきます

また、一部のデータ(フィールド上のプレイヤーデータなど)は圧縮された状態で送られてきます。

ちなみに、先ほどクライアント -> サーバーのパケットは暗号化されていると書きましたが、
暗号化に使われるキーは、サーバーから送られてくるデータを使って生成されるます。

なので、生成されたものをコアから抜き取るか、サーバーから送られてくるデータを複合化するしかありません。

データにずらしが入っている

botを作っても自分の方向に向かってくるようにしないと意味がありません

これを困難にするために、座標情報がずらされています。
説明が難しいですが、ずらしを考慮して座標パケットを送信しないとbotがスクランブルしてプレイヤーのもとに向かってきません。

reCAPTCHA

有名なbot対策であるGoogle reCAPTCHAが導入されています。

いつごろからかわかりませんが、
reCAPTCHAが導入され、プレイヤーが何度もすぐに死んだり怪しいプロキシを経由して接続すると
reCAPTCHAによる認証が要求されてしまうようになりました

これを回避する方法が発見され、一時期盛り上がりましたが
今度はreCAPTCHA V2に続きV3が導入され、
プレイヤーがスポーンするたびにV3による認証が必要になりました。

これを突破したのが私なのですが、数か月後に対策されて今はもう使えませんTT

さいごに

Agar.ioのantibotを紹介しました。(もしかしたら他にもあったかもしれない)

チートすることの何がおもしろいの?と言う人がいるかもしれませんが、
確かにただのプレイヤーだったら、すぐに飽きる原因になりますし、面白くないかもしれません

しかし、作る側からすればめちゃくちゃ面白いです
antibotを突破できたときの達成感はデカイですし、他の開発者と繋がったりゲームのオーナーと話ができたりして刺激的です。

もちろん褒められたことではありませんが、めちゃくちゃ成長できました。
おわりです

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

yarnのcacheでハマった

めったに起こらないエラーだと思うがyarnのキャッシュでハマった。同じ地雷を踏む人がいないとも限らないので書いておく。

ローカルで開発していたjavascriptのライブラリを

yarn add javascriptのライブラリのパス

でreactに追加して開発をしていたらyarn addの際に以下のエラーが出るようになった。

warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
[1/4] ?  Resolving packages...
[2/4] ?  Fetching packages...
error An unexpected error occurred: "ENOSPC: no space left on device, write".
info If you think this is a bug, please open a bug report with the information provided in "ライブラリのパス/yarn-error.log".
info Visit https://yarnpkg.com/en/docs/cli/add for documentation about this command.

no space left on deviceのエラーメッセージを検索するとメモリの問題だったりinodeの問題のケースもあるみたいだが、今回はディスク容量の問題で、いつの間にか何かが400GB以上、ディスク容量圧迫していて他の作業もまともに進まなくなった。

このmacについて→ストレージを開いて確認するも「その他」の領域のファイルが圧迫していることしかわからない(具体的なパスが出ない)

原因と解決

findとduコマンドで地道に調べていったところ以下のパスにyarnのcacheがたまっていた
$HOME/Library/Caches/Yarn/

開発していたライブラリのパスで
yarn cache clean
を実行して解決。

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

セマンティックバージョニングを正規表現で評価する

公式リンク↓↓

セマンティックバージョニング2.0.0(最後の方に載ってます)

見るのが面倒な人向け↓↓

const regex = new RegExp(/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/);
if(regex.test(hogehoge)){
  console.log("OK")
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

1分でわかるBootstrap4の書き方

Bootstrap4を実際に書き始めるまでの基礎をまとめました。

CDN
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">

<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

 
前提として、Bootstrapの要素はbody直下にcontainerクラスのdivで囲います。

marginとpadding

Bootstrapでは、クラスを用いてmarginとpaddingを表し、プロパティ 上下左右-サイズの型で記述します。(例: mt-4 , p-auto)

プロパティ 内容 上下左右 内容 サイズ 内容
m margin t top 0 0
p padding b bottom 1 *0.25
l left 2 *0.5
r right 3 *1
x l,r 4 *1.5
y t,b 5 *3
t,b,l,r auto auto

グリッドシステム

Bootstrapでは、要素の横1行をrowクラスのdivタグで区切り、12等分した1列をカラムと呼びます。
無題 (2).png
カラムは、クラス名にcol-画面サイズ-サイズの型で記述します。(例: col-md-6 , col-10)

画面サイズ 内容 サイズ 内容
<540px 1 1/12rem
sm 540px 2 2/12rem
md 720px 3 3/12rem
lg 960px 4 4/12rem
xl 1140px ...
offset 余白 12 1rem

参考文献

詳しい内容やコンポーネントは公式ドキュメントが参考になります↓ ↓
公式ドキュメント

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

Object destructuring / Javascript

オブジェクトから値を取り出す方法

例えばJavascriptのオブジェクトから値を取り出すときどのように取り出しますか。

const product = {
  destination: 'hawaii',
  price: 59800,
  stock: 20
}

私は今まで以下のようにしていました。

const dst = product.destination
const price  = product.price

これでも問題なく出力されます。

console.log(dst, price)
>> hawaii 59800

ショートハンド

再定義するのが冗長な感じがするので、以下のようなショートハンドで記載可能です。

const { destination: dst, price } = product

同じ結果が得られます。

console.log(dst, price)
>> hawaii 59800

順を追って書き直すとイメージしやすいです。

// 1. {}という変数にproductオブジェクトを定義
const {} = product
// 2. 
const { destination, price } = product
// 3. 新しい変数への割り当て
const { destination: dst, price } = product

プロパティの追加

また、既存のオブジェクトにないプロパティの追加も可能です。

const { destination: dst, price, rating } = product

このままだとエラーが出ます。

console.log(dst, price, rating)
>> hawaii 59800 undefined

ratingに5という値を入れてみましょう

const { destination: dst, price, rating = 5 } = product
console.log(dst, price, rating)
>> hawaii 59800 5

ratingが表示されました。

関数の引数として取り出す

const addHotel = (hotel, myProduct) => {
  const { destination: dst, price } = myProduct; 
  console.log(hotel, dst, price)
}

addHotel('yhrm Hotel', product)

>> yhrm Hotel hawaii 59800

または、引数に直接記載します。

const addHotel = (hotel, { destination: dst, price }) => {
  console.log(hotel, dst, price)
}

addHotel('yhrm Hotel', product)

>> yhrm Hotel hawaii 59800

まとめ

整理すると

  1. ショートハンドとして書ける
  2. 新しい変数名の割り当てができる
  3. 既存のオブジェクトにないプロパティを追加できる

参考

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

javaScriptのArrayをまとめる

初めに

Arrayに対する理解が曖昧だったため改めて整理することにした、

Array

Arrayオブジェクトは、配列型の値を扱うためのオブジェクト。
配列に対して要素の追加削除結合並べ替えなどを行うための機能を提供する。

生成

生成の方法は、①リテラル表現で生成する方法と②コンストラクタで生成する方法がある。

①リテラル表現

array.js
var ary = ['本田','香川','岡崎'];

②コンストラクタ

array.js
var ary = new Array('本田','香川','岡崎');

どちらを使うか

例えばコンストラクタで生成する場合、下記はどのような意味を持つだろうか?

array.js
var ary = new Array(10);

考えられるのは「長さが10の配列」か「10という要素を持つ配列」のどちらか。

正解は「長さが10の配列」である。

この様に、コンストラクタで生成してしまうと可読性が下がるので、配列リテラルで生成するほうが良い
なお、空の配列を作る方法は下記である。

array.js
var ary = [];

代表的なArrayオブジェクトのメンバー(一部)

array.js
var ary = ['本田','香川','岡崎'];
var ary2 = ['遠藤','長谷部','長友'];

//基本形
console.log(ary);                      //(3) ["本田", "香川", "岡崎"]
console.log(ary.length);               //3 配列のサイズ
console.log(Array.isArray(ary));       //true 配列かどうか
console.log(ary.indexOf(`岡崎`))       //2 要素のキーの開始位置を取得

//加工
console.log(ary.concat(ary2));         //(6) ["本田", "香川", "岡崎", "遠藤", "長谷部", "長友"]  //配列の連結

//追加と削除
console.log(ary.pop(),ary);            //岡崎 ←削除した要素 //(2) ["本田", "香川"] ←削除後
console.log(ary.push('内田'),ary);      //4 ←追加後の要素数 // (4) ["本田", "香川", "岡崎", "内田"] ←追加後の配列


代表的なArrayオブジェクトのメンバー(コールバック)

Arrayオブジェクトで代表的なコールバック系のメソッドを3つ説明する。

forEach

forEachメソッドは指定した関連で順に処理するメソッドである、
①配列の要素を順番に取り出す。
②ユーザー定義関数のcallbackに渡す。
③渡された要素を処理する。

foreach.js
var ary = ['本田','香川','岡崎'];

ary.forEach(function(value, index, array){
            console.log(value);
            console.log(index);
            //console.log(array)
        })
//本田
//0
//香川
//1
//岡崎
//2

第一引数 valueは要素の値
第二引数 indexはインデックスの番号
第三引数 arrayは元の配列

なお、console.log(array)は毎回元の配列を吐き出す。(冗長になるのでコメントアウトした)

map

mapメソッドは配列を指定された関数で加工することが出来る。
callbackで受け取る引数はforEachと同じだが、戻り値(return)は新しい配列を作るために必要になる。

map.js
var ary = ['本田','香川','岡崎'];

var member = ary.map(function(value, index, array){
                 return value+"選手";           
             })
console.log(member);  //(3) ["本田選手", "香川選手", "岡崎選手"]

もしreturnしなかったら…

map.js
var ary = ['本田','香川','岡崎'];

var member = ary.map(function(value, index, array){
             // return value+"選手";         
             })
console.log(member);  //(3) [undefined, undefined, undefined]

当然にundefinedになる。

filter

指定された関数で個々の要素を判定し、条件に合致した要素だけを取り出すメソッド

filter.js
var ary = ['本田','香川','岡崎'];

var member = ary.filter(function(value, index, array){
                 return value.indexOf('') >= 0 
                 //indexOfは該当の文字があればその位置、なければ-1を返す。
             })
console.log(member);    //["本田"]

callbackがtrueを返した時だけ、その時の要素を配列に書き戻す。
上記では本田だけtrueになるので、本頼みの配列が出来上がる。

終わりに

Arrayオブジェクトで使用できるコールバック関数は上記の他にsomeeverysort等がある。

参考

javascript本格入門

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

javascript の Object のメソッドにおける列挙可能とか直接所有とかの扱い

javascriptのObjectのプロパティにはいろんな種類がある。
[[Enumerable]](列挙可能性)みたいな属性がついていたり、「直接所有(own)」か「継承したもの」かの違いだったり、キーがStringだったりSymbolだったりとかする。
キーや値を取得したり色々するメソッドはいくつかありそれらについての扱いが異なる。
hasOwnPropertyとかassignとかentriesとかそんなのでどのように扱われているかしらべた。
目的は継承もふくめて取得すること。

実行したコード

var syms={
    // Symbol の一覧
    '   Own    Enumerable Symbol':Symbol('   Own    Enumerable Symbol'),
    '   Own nonEnumerable Symbol':Symbol('   Own nonEnumerable Symbol'),
    'nonOwn    Enumerable Symbol':Symbol('nonOwn    Enumerable Symbol'),
    'nonOwn nonEnumerable Symbol':Symbol('nonOwn nonEnumerable Symbol'),
};
// own:直接所有 enumerable:列挙可能性
function C(){
    // 直接所有のプロパティを設定
    Object.defineProperty(this   ,     '   Own    Enumerable String' ,{value: 11,enumerable: true});
    Object.defineProperty(this   ,     '   Own nonEnumerable String' ,{value: 22,enumerable:false});
    Object.defineProperty(this   ,syms['   Own    Enumerable Symbol'],{value: 44,enumerable: true});
    Object.defineProperty(this   ,syms['   Own nonEnumerable Symbol'],{value: 55,enumerable:false});
    return this;
}
// プロトタイプを設定
Object.defineProperty(C.prototype,     'nonOwn    Enumerable String' ,{value:123,enumerable: true});
Object.defineProperty(C.prototype,     'nonOwn nonEnumerable String' ,{value:345,enumerable:false});
Object.defineProperty(C.prototype,syms['nonOwn    Enumerable Symbol'],{value:678,enumerable: true});
Object.defineProperty(C.prototype,syms['nonOwn nonEnumerable Symbol'],{value:890,enumerable:false});
// オブジェクト生成   上で定義した 直接所有/継承 列挙可能/不可能 String/Symbol それぞれのプロパティを持つ
var obj=new C();
// 以下調べるための実行
console.log('entries              :',Object.entries              (obj));
console.log('getOwnPropertyNames  :',Object.getOwnPropertyNames  (obj));
console.log('getOwnPropertySymbols:',Object.getOwnPropertySymbols(obj));
console.log('keys                 :',Object.keys                 (obj));
console.log('values               :',Object.values               (obj));
var keys=[];
for(let key in obj)keys.push(key);
console.log('for ... in           :',keys);
console.log('getOwnPropertyDescriptors:',Object.getOwnPropertyDescriptors(obj));
console.log('assign:',Object.assign(Object.create(null),obj));
console.log('hasOwnProperty       :    Own    Enumerable String',obj.hasOwnProperty      (     '   Own    Enumerable String' ));
console.log('hasOwnProperty       :    Own nonEnumerable String',obj.hasOwnProperty      (     '   Own nonEnumerable String' ));
console.log('hasOwnProperty       : nonOwn    Enumerable String',obj.hasOwnProperty      (     'nonOwn    Enumerable String' ));
console.log('hasOwnProperty       : nonOwn nonEnumerable String',obj.hasOwnProperty      (     'nonOwn nonEnumerable String' ));
console.log('hasOwnProperty       :    Own    Enumerable Symbol',obj.hasOwnProperty      (syms['   Own    Enumerable Symbol']));
console.log('hasOwnProperty       :    Own nonEnumerable Symbol',obj.hasOwnProperty      (syms['   Own nonEnumerable Symbol']));
console.log('hasOwnProperty       : nonOwn    Enumerable Symbol',obj.hasOwnProperty      (syms['nonOwn    Enumerable Symbol']));
console.log('hasOwnProperty       : nonOwn nonEnumerable Symbol',obj.hasOwnProperty      (syms['nonOwn nonEnumerable Symbol']));
console.log('propertyIsEnumerable :    Own    Enumerable String',obj.propertyIsEnumerable(     '   Own    Enumerable String' ));
console.log('propertyIsEnumerable :    Own nonEnumerable String',obj.propertyIsEnumerable(     '   Own nonEnumerable String' ));
console.log('propertyIsEnumerable : nonOwn    Enumerable String',obj.propertyIsEnumerable(     'nonOwn    Enumerable String' ));
console.log('propertyIsEnumerable : nonOwn nonEnumerable String',obj.propertyIsEnumerable(     'nonOwn nonEnumerable String' ));
console.log('propertyIsEnumerable :    Own    Enumerable Symbol',obj.propertyIsEnumerable(syms['   Own    Enumerable Symbol']));
console.log('propertyIsEnumerable :    Own nonEnumerable Symbol',obj.propertyIsEnumerable(syms['   Own nonEnumerable Symbol']));
console.log('propertyIsEnumerable : nonOwn    Enumerable Symbol',obj.propertyIsEnumerable(syms['nonOwn    Enumerable Symbol']));
console.log('propertyIsEnumerable : nonOwn nonEnumerable Symbol',obj.propertyIsEnumerable(syms['nonOwn nonEnumerable Symbol']));

出力

多少見やすいように成型
GoogleChromeとFirefoxで差はなし。

entries              : [Array(2)]
    0: (2) ["   Own    Enumerable String", 11]
getOwnPropertyNames  : (2) ["   Own    Enumerable String", "   Own nonEnumerable String"]
getOwnPropertySymbols: (2) [Symbol(   Own    Enumerable Symbol), Symbol(   Own nonEnumerable Symbol)]
keys                 : ["   Own    Enumerable String"]
values               : [11]
for ... in           : (2) ["   Own    Enumerable String", "nonOwn    Enumerable String"]
getOwnPropertyDescriptors: {...}
          "   Own    Enumerable String": {value: 11, writable: false, enumerable:  true, configurable: false}
          "   Own nonEnumerable String": {value: 22, writable: false, enumerable: false, configurable: false}
    Symbol(   Own    Enumerable Symbol): {value: 44, writable: false, enumerable:  true, configurable: false}
    Symbol(   Own nonEnumerable Symbol): {value: 55, writable: false, enumerable: false, configurable: false}
assign: {...}
          "   Own    Enumerable String": 11
    Symbol(   Own    Enumerable Symbol): 44
hasOwnProperty       :    Own    Enumerable String true
hasOwnProperty       :    Own nonEnumerable String true
hasOwnProperty       : nonOwn    Enumerable String false
hasOwnProperty       : nonOwn nonEnumerable String false
hasOwnProperty       :    Own    Enumerable Symbol true
hasOwnProperty       :    Own nonEnumerable Symbol true
hasOwnProperty       : nonOwn    Enumerable Symbol false
hasOwnProperty       : nonOwn nonEnumerable Symbol false
propertyIsEnumerable :    Own    Enumerable String true
propertyIsEnumerable :    Own nonEnumerable String false
propertyIsEnumerable : nonOwn    Enumerable String false
propertyIsEnumerable : nonOwn nonEnumerable String false
propertyIsEnumerable :    Own    Enumerable Symbol true
propertyIsEnumerable :    Own nonEnumerable Symbol false
propertyIsEnumerable : nonOwn    Enumerable Symbol false
propertyIsEnumerable : nonOwn nonEnumerable Symbol false

結果

enumerable own String/Symbol 動作 列挙可/不可能性 直接所有/継承
entries true true String 取得 可能のみ 直接所有のみ
getOwnPropertyNames true/false true String 取得 両方 直接所有のみ
getOwnPropertySymbols true/false true Symbol 取得 両方 直接所有のみ
keys true true String 取得 可能のみ 直接所有のみ
values true true String 取得 可能のみ 直接所有のみ
for ... in true true/false String 取得 可能のみ 両方
getOwnPropertyDescriptors true/false true String/Symbol 取得 両方 直接所有のみ
assign true true String/Symbol 代入 可能のみ 直接所有のみ
hasOwnProperty true/false true String/Symbol 検査 両方 直接所有のみ
propertyIsEnumerable true true String/Symbol 検査 可能のみ 直接所有のみ

結論

直接所有/継承の両方を取得するにはfor ... inを使うことになりそう。
ただしSymbolが含まれないのでそれを含めようと思ったら面倒くさいことになりそう。
列挙可/不可能性,直接所有/継承,String/Symbolをそれぞれ指定できるやつがあればいいんだけど。
コードが冗長なのは気にしない。

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

【ReactNative】WebViewを使って既存資産を使い回す

はじめに

ReactNativeを使って既存Webサービスのアプリ版を開発している場合、一部のアプリ独自の機能(例えばプッシュ通知やカメラ)を除いては既存ソースを流用できる場合があります。
例でいうと、ユーザ情報画面は既存のWebのマイページをそのまま表示するとかです。
その場合、WebViewを使うことになると思います。
ReactNativeでいうところのWebViewreact-native-webviewを使うことになりますが、ここで問題になってくるのがReactNative側のコードとWebView側のコードの連携処理です。
先のマイページの例でいうと、WebView側のマイページ画面のソースコードにReactNative側からユーザ情報を渡してあげなければ成立しません。
今回はreact-native-webviewを導入した上で、WebViewとの値の受け渡し方法について調べました。

環境情報

"react-native": "0.61.5",
"react-native-webview": "^9.2.1",

インストール

react-native-webviewをインストールしていない場合はインストール。

yarn add  react-native-webview

WebViewに値を渡す

WebViewに値を渡す場合はinjectedJavaScriptを使います。
injectedJavaScriptには文字列型でJavascriptのコードを渡せます。

WebViewComponent.tsx
import React from 'react';
import { WebView } from 'react-native-webview';

// WebViewに渡すコード
const injectedCode : string = `
    function fireInjectedJavaScript(){
        alert('ReactNativeから渡されたコードを実行しました!');
    }
`;

// WebViewで表示させるHTML
const html : string = `
      <html>
      <head>
      </head>
      <body>
        <h1>Title</h1>
        <form name="test">
            <input type="button" value="injectedJavaScript" onClick="fireInjectedJavaScript()">
        </form>
      </body>
      </html>
`;

// ...割愛

render(
    <WebView source={{html : html}} injectedJavaScript={injectedCode} />
);

html中のボタンでfireInjectedJavascript()を実行していますが、これはReactNative側から渡された関数です。
よって、アプリで表示された場合のみ特定の処理を行うような作りにすることもできます。

渡したコードはWebViewが描画された後に実行されるため、jQuerydocument.getElementByIdなんかを使ってWebView側の特定のフォームの値や表示をいじることもできます(上記のマイページの例ではこの方法を使ってユーザ情報を渡す)。

WebViewから値を貰う

逆にWebView側から何らかのデータを受け取りたい場合はonMessageを使います。

WebViewComponent2.tsx
import React from 'react';
import { WebView, WebViewMessageEvent } from 'react-native-webview';

// WebViewで表示させるHTML
const html : string = `
      <html>
      <head>
        <script>
            // WebViewが読み込まれた時にデータを送信
            window.onload = function() {
                window.ReactNativeWebView.postMessage("onload")
            };

            // 定期的に実行(ポーリングなんかに使える??)
            setInterval(function () {
                window.ReactNativeWebView.postMessage({hoge : "setInterval"})
            }, 2000)

            // 特定の処理実行時にデータを送信
            function firePostMessage(){
                window.ReactNativeWebView.postMessage("button click")
            }
        </script>
      </head>
      <body>
        <h1>Title</h1>

        <form name="test">
            <input type="button" value="postMessage" onClick="firePostMessage()">
        </form>
      </body>
      </html>
`;

// ...割愛

// onMessage発火時処理
public onMessageFromHtml(event : WebViewMessageEvent) {
    console.log(event.nativeEvent.data);
}

render(
    <WebView source={{html : html}} onMessage={onMessageFromHtml} />
);

上記の例ではWebView読み込み時に実行と、定期的に実行、ボタンを押した時に実行、と3パターンを盛り込んでいます。
いずれの場合もwindow.ReactNativeWebView.postMessageを実行しており、ReactNative側ではWebViewMessageEvent型で受け取ります。
渡された値自体はWebViewMessageEventnativeEvent.dataの中に格納されています。
nativeEvent.datareactBaseSyntheticEventのジェネリクスとなっているため型は自由です(setIntervalのようにオブジェクトを渡すこともできます)。

おわりに

今回はreact-natiev-webviewをインストールし、ReactNativeWebView間でのデータの受け渡し方法を紹介しました。
既存のソースを使いまわせるので非常に有効な手ではないかと思います。

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

Shikha Dating Services in bangalore

image.png
image.png

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

JavaScriptの基礎知識・文法

背景

JavaScriptの基礎知識を備忘録として残す。

よく使う基礎知識・文法

・出力の仕方

console.log(“文字列”or数値);

・コメントアウト
//を最初につける

// コメントアウト

・変数の定義

let 変数名=値;

・定数の定義

const 定数名=値;

・テンプレートリテラル(変数展開)
※バッククオーテーションで囲む。

const name=tanaka;
console.log(`こんにちは${name}さん`);

・if文の書き方

if (条件式){
    処理;
}

・比較演算子

a===b  // aとbは等しい
a!==b  // aとbは異なる

・else ifとelseの書き方

If (条件式){
    処理;
}
else if(条件式){
処理;
}
else{
処理;
}

・switch文の書き方

switch(変数名){
    case “値”;
        処理;
        break;
    default:
        処理;
        break;
}

・while文の書き方

while(変数名){
    繰り返し処理;
}

・for文の書き方

for(変数の定義;条件式;変数の更新){
    処理;
}

・オブジェクトの作り方(ハッシュ)

定数名={プロパティ名1:1,プロパティ2:値2,}

・関数の作り方(メソッド)

const 関数名=()=>{
    まとめたい処理;
};

・引数を受け取る関数の作り方

const 関数名=(引数名)=>{
    まとめたい処理;
};
関数名(引数);

・戻り値を受ける方法

const 関数名=(引数名等)=>{
    return 処理;
}
const 定数名=関数名(引数等);

・クラスの作り方
※インスタンス生成

class クラス名(最初は大文字){

}
const 定数名=new クラス名();

・コンストラクタの作り方
※クラス内に書く

constructor(){
    処理;
}

(インスタンス生成時に始めにされる処理)

・thisの使い方
コンストラクタ内に書くことでプロパティ(変数的なもの)と値を使えるようになる。

this.プロパティ=;

・クラスの継承方法

class 子クラス extends 親クラス{
}

・他ファイルでもクラスや関数等を使う方法

export default クラス名(関数名等)             // 使いたいクラスがあるファイルで。
import クラス名 from ./ファイル名(関数名等)   // クラスを使いたいファイルで。

・名前付きエクスポート
※インポートは同手順。

export {値の名前};

・.forEachメソッド

配列.forEach((引数)=>{処理});
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptで四捨五入、切り上げ、切り捨て

メモ

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Math/ceil
の、10進補正 (Decimal adjustment) のところを丸ごとコピペする。
※50行目からの使用例をみると使い方がわかる

標準の関数もあるけど(Math.ceil()とか)、やりたい事とマッチしないはず(具体的にどうだったかは忘れたけど。。)

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