読者です 読者をやめる 読者になる 読者になる

RubyのClassクラスについてとか、クラスを知るためのメソッドとか、あれこれ(メモ)

Ruby

MyClass.class            # => Class

MyClass.class.class   # => Class

という結果に Σ(・∀・;) となったので調べた。

 (.classはオブジェクトが定義されたクラス名を返す。)

 

まとめ

Rubyでは、定義されたクラスは全て、Classクラスのインスタンスとなる。

Rubyでは、扱われる全ての要素はオブジェクトで(何らかのクラスのインスタンスで)、Objectクラスのインスタンスメソッドを継承している。(Object#classとか)

どうやら、MyClass.classで返る"Class"も、クラスであり、オブジェクトであり、Classクラスのインスタンスとして扱われるため、その結果、MyClass.class.class #=> Class が返るらしい。(難しいなぁ。考え方合ってるのかなぁ。。)

 

やってみよう!

f:id:bambinya:20160110135338p:plain

StringやArrayなどの組み込みクラスも、自分で定義したMyClassも、.classを実行するとClassが返ってくる。

Rubyで扱う全ての値はオブジェクトなので、Objectクラスが持つインスタンスメソッドを継承している。あるクラスが持つインスタンスメソッドを見たいときは、instance_methodsを使う。(↓こんな感じ。)

f:id:bambinya:20160110142407p:plain

 

MyClass.classが返すのは、Classクラスというオブジェクトである。

f:id:bambinya:20160110150442p:plain

Classクラスは"クラス"の一つなので、オブジェクトであり、また、Classクラスのインスタンスであることから、MyClass.class.class #=> Class という結果になるみたい。

 

ちなみに、あるクラスがどんなクラスやモジュールを継承したりインクルードしているかを見るにはancestorsを使う。

出力結果の、配列の順番は、[クラス自身、親クラス、親の親クラス..]となる。クラス名の間にインクルードしているモジュール名がちょこちょこ入ってくる。

実行結果。

Rubyで扱う全ての値はオブジェクトなので、ClassクラスもObjectクラスを継承していることがわかる。)

f:id:bambinya:20160110145829p:plain

 

おしまい。m(__)m

 

emacs key bindingメモ

キーバインドのデフォルトで

C-h がHELPの設定になっていたので、 ~/.emacs.d/init.el ファイルに下記マクロを追加。シンタックスemacs lisp.

(keyboard-translate ?\C-h ?\C-?)

Function: keyboard-translate from to
この関数は、文字コードfromを文字コードtoに変換するように keyboard-translate-tableを変更する。 必要ならばキーボード変換表を作成する。

*1

 

画面操作(ファイル開閉、emacsプロセスの開閉、画面分割と移動、画面削除、ミニバッファから離れる)

  • C-x C-c KILL TASK
  • C-z SUSPEND TASK (fg → foreground)
  • C-x C-f OPEN FILE
  • C-x C-s SAVE FILE
  • C-x 2 split-window-below
  • C-x 3 split-window-right
  • C-x o SELECT ANOTHER WINDOW
  • C-x 0 DELETE SELECTED WINDOW
  • C-] KILL MINIBUFFER

エディタの移動(上下左右の移動)

  • C-p UP
  • C-n DOWN
  • C-b BACK
  • C-f FORWARD
  • C-a GO TO BEGINNING OF LINE
  • C-e GO TO END OF LINE
  • C-o OPEN LINE
  • M-v PAGEUP
  • C-v PAGEDOWN
  • M->(Shift + .) Move to the END of the buffer
  • M-<(Shift + ,) Move to the TOP of the buffer

エディタの操作(文字の削除、行の削除、選択範囲の削除、やり直し)

  • C-h BACKSPACE
  • C-d KILL FORWARD CHARACTER
  • C-k KILL LINE
  • C-w KILL THE REGION(バッファに保存される)
  • C-_ UNDO

 

コピペしたいときのステップ

  1. C+space key(Mark Set)
  2. M+w(copy)
  3. C+y(paste)

 

検索

  • C-r SEARCH

 

置換

  1. M+%(Shift+5)
  2. 置換したいテキスト入力、RET
  3. 新しいテキスト入力、RET
  4. !  (to replace all remaining occurrences without asking again.)

GNU Emacs Manual: Query Replace

 

一括インデント

  1. C+space keyで範囲選択
  2. CM+\

 

一括コメントアウト

  1. C+space keyで範囲選択
  2. M+;

 

操作の解除

  • C+g 実行中の全ての操作をキャンセル

おわり

JavaScript 関数のカリー化と部分適用

引数を複数とる関数から、いくつかの引数を固定値で束縛した新たな関数を生成する。これにより、関数を使うたびに同じ値の引数を入力する手間が省け、見た目も簡潔なプログラムになる。

 

カリー化とは、複数の引数を取る関数を、1つの引数のみを取る関数のチェーンに変換する処理のこと。

みてみよう!

js curry function

 

部分適用とは、複数の引数を取る関数を、それより少ない数の引数を取る関数に変換し、除外された引数には最初から値を指定しておく、という処理のこと。

関数に対して複数の引数を部分的に適用し、残りの引数で構成される関数を新たに作成する。

みてみよう!

js bind method

※bind()メソッドは呼び出されたときに新しい関数を生成する。第一引数は新しい関数のthisキーワードにセットされる。第二引数以降は、ターゲット関数の引数として、第一引数から順に与えられる。

 

JavaScriptのthis

jsのthisは、ある関数が呼び出されたときに、その関数を格納していたObjectを指す。

js how does "this" work?

 

関数を単にfunc();という形で単体で実行した場合、thisにはwindowが入る。

f:id:bambinya:20150729190027p:plain

 

new演算子のthis

jsのnewは任意の関数と一緒に呼び出すことができる。

var x = new func();

上の例では、まずnewで新しい空のオブジェクト{}が生成され、次に関数func()が呼び出される。このとき関数func内のthisには新しく生成された空のオブジェクトが渡され、関数実行後、生成されたオブジェクトがnewの実行結果として変数xに代入される。

 

JavaScriptのプロトタイプベースのオブジェクト指向について、調べたこと

jsは(ES6より前は)クラスを持たないオブジェクト指向言語である。クラスの代わりに、プロトタイプというプロパティを作り、そのプロパティを複数インスタンスで共有する。そのためプロトタイプベースのオブジェクト指向言語といわれている。

jsの全てのオブジェクト(関数やプロパティの集合)は、__proto__プロパティに「継承したオブジェクト」のメモリアドレスを格納できる。

jsの全てのオブジェクトは、Object.prototypeを継承している。そのため、__defineSetter__, __defineGetter__, toString, hasOwnPropertyなどのメソッドをデフォルトで使うことができる。 下記はコンソールログでオブジェクトを生成し、継承元のObject.prototypeを表示している。

f:id:bambinya:20150725205934p:plain

 

コンストラクタ関数とnew演算子を使ったオブジェクト生成の例

js create object with new Object()

 

生成したオブジェクトの中身をコンソールで見てみよう!

chromeのコンソールログでまったく同じコードを入力する。

f:id:bambinya:20150725202547p:plain

 

コンストラクタPersonから生成したperson1は、name, a, __proto__の3つのプロパティを持つ。__proto__プロパティには、コンストラクタ関数Personのprototypeのメモリアドレスを格納する。このメモリアドレスを元に、person1はコンストラクタ関数が持つoutputName()を使用することができる。

f:id:bambinya:20150725202911p:plain

図で描くとこんな感じ。person1の__proto__にはPerson.prototypeのメモリアドレスが格納されており、Person.prototypeのプロパティの参照が可能である。

f:id:bambinya:20150725220901p:plain

 

一方、person2が持つプロパティはnameと__proto__のみである。person2.aが定義されていない場合は、継承元である上位のPerson.prototypeを探索しに行く。もし見つからなければ最上位の Object.prototype までプロパティを探索しにいく。

f:id:bambinya:20150725210159p:plain

 

オブジェクトの継承過程をたどる

Personコンストラクタから生成したオブジェクトperson1は、コンストラクタ関数とは別のメモリに格納される。オブジェクトによって、プロトタイプチェーンが異なる。

オブジェクトperson1は、下記のようになる。

 person1 < Person < Object < null (上位の継承オブジェクトがない)

コンストラクタPersonは、下記のようになる。

 Person < Empty < Object < null (上位の継承オブジェクトがない)

 

コンソールで見てみよう。

f:id:bambinya:20150725211359p:plain

f:id:bambinya:20150725211713p:plain

function Empty()のプロトタイプにはapplyやcallメソッドが定義されている。

f:id:bambinya:20150725212118p:plain

 

値渡し(call by value)とポインタ渡し(call by pointer)について

C言語では、関数を呼び出す際に、値渡しという方法で引数を渡す。

 

値渡しは、仮引数に実引数の値をコピーすること。

ポインタ渡しは、仮引数に実引数のメモリアドレスの値をコピーすること。メモリアドレスの"値をコピーする"、という点ではポインタ渡しも値渡しといえる。呼び出された関数内では、コピーしたメモリアドレスを元に、実引数の値を見ることができ、かつ実引数の値を変更することができる。

 

実引数(argument)と仮引数(parameter)とは

実引数とは関数呼び出し時に引き渡す引数のこと。func( argument_a, argument_b );

仮引数とは関数定義時に使用される引数のこと。func( parameter_a, parameter_b ){ };

 

やってみよう!

変数aを定義して、関数funcAは値渡し、関数funcBはポインタ渡しで呼び出す。

それぞれの関数内で仮引数iの値を変更すると、結果はどうなるか。 

difference between call by value and call by point ...

 

f:id:bambinya:20150725084051p:plain

 

最初に、変数aには1が代入され、 メモリアドレスは0012FF5Cだと分かる。

funcAでは、実引数から仮引数に(代入された)値をコピーしているだけである。funcAが呼び出されると仮引数iのメモリ領域が変数aとは別に確保される。そのため、仮引数iの値を7に変更しても、変数aの値は1のままである。またiのメモリアドレスは0012FF58であり、変数aとは違うことがわかる。

一方、funcBでは、実引数から仮引数にメモリアドレスを渡しているので、仮引数iの値を222に変更すると、変数aの値も222になる。またiのメモリアドレスは0012FF5Cであり、変数aと同じことがわかる。

 

(以下は調べたけど、まだちゃんと検証してない) 

Javaでは、実引数が基本型(プリミティブ型)なら値渡し、クラスから作成したオブジェクトであれば参照渡しとなる。

プリミティブ型とは、データを格納するための、最も基本的な型である。 整数値や実数値といった、具体的な「値」を格納するための変数を作るための型が「プリミティブ型」である。プリミティブ型の変数は、変数用に割り当てられたメモリ領域の先頭アドレスがわかれば、CPUがメモリを読み書きできる。それに対しオブジェクトには、オブジェクトが含むメンバ変数が格納されるメモリ領域の先頭アドレスの値が入っている。オブジェクトを実引数として関数を呼ぶ場合、仮引数にはメンバ変数が格納されたメモリ領域の先頭アドレスがコピーされる。そのため、呼び出された関数内で仮引数を変更すると実引数の値も変更される。

文字列が実引数として渡される場合、文字列はStringクラスのオブジェクトなので、オブジェクトの先頭アドレスの値がコピーされる。しかし、仮引数に新しく文字列を代入すると、新しくオブジェクトが作られ、その先頭アドレスが仮引数に代入される。文字列の場合は、仮引数の値を変更しても、実引数の値は変更されない。

 

 

Javascriptでclosureと、applyメソッド、callメソッドを使う

jsが持つ関数スコープを利用してクロージャー(関数閉包)を書くことができる。

js closure

上記の例では、関数countの中のローカル変数iを参照できるのは、無名関数が入っている変数xを実行したときのみである。変数iをグローバル変数にすると他の関数からの参照が可能になり、意図せずに値を変更してしまう可能性がある。

 

jsの全ての関数は組み込み関数Functionを継承しており、組み込み関数Functionが持つapplyメソッド、callメソッドも継承している。

callメソッド:現在のオブジェクトが持っていないメソッドを適用する。

js use call method

applyメソッド:callメソッドと同じように現在のオブジェクトの代わりに、他のオブジェクトのメソッドを適用できる。引数に可変長の配列をひとつとる点がcallと異なる。以下のような感じ。

js use apply method