読んだ

Think Simple―アップルを生みだす熱狂的哲学

Think Simple―アップルを生みだす熱狂的哲学

ある問題を解決しようとして、最初に考えだした解決策がとても複雑だったとしよう。ほとんどの人はそこで考えるのをやめてしまう。だが、そこでやめずに考えつづけて、タマネギの皮をむくようにムダなものをそぎ落としていくと、とても洗練されたシンプルな解決策にたどり着くことがよくある。

リファクタリングのことですね。わかります。何事もそうですね。

シンプルであることは複雑であることよりもむずかしい。物事をシンプルにするためには、懸命に努力して思考を明瞭にしなければならないからだ。だが、それだけの価値はある。なぜなら、ひとたびそこに到達できれば、山をも動かせるからだ。

随分前にOracleの検証をJunit使ってテストした時の垂れ流しコードのメモを一応貼っとこう

もしかしたら何かに使う可能性があるかもしれないから。それにしてもだなー。その時の自分から今の自分に謝りたいと思います。やっつけなコードで大変申し訳ございません。以後気をつけたいと思います。

package jp.co.suda.oracle;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Types;

import jp.co.suda.oracle.Exception.Runtime.OracleAddUserException;
import oracle.jdbc.OracleTypes;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class OracleTest1 {

	private static Connection conn;

	private static Statement nowStatement;

	private static PreparedStatement nowPstatement;

	private static CallableStatement cs;

	private static ResultSet result;

	private static String sql;

	private static int testno = 1;

	private static String connectionUser = "suda";

	private static String connectionPass = "hogesuda";

	private static String targetUser = "odu";

	private static String targetUserPass = "hogeodu";

	/**
	 * 
	 * ドライバの読み込み コネクションの取得
	 * 
	 * @throws ClassNotFoundException
	 * @throws SQLException
	 */
	@BeforeClass
	public static void setup() throws ClassNotFoundException, SQLException {
		Class.forName("oracle.jdbc.driver.OracleDriver");
		conn =
			DriverManager.getConnection(
				"jdbc:oracle:thin:@localhost:1521:sudaorcl",
				connectionUser,
				connectionPass);
		nowStatement = conn.createStatement();
		System.out
			.println("ユーザ" + conn.getMetaData().getUserName() + "で接続します。");
		System.out.println("スキーマ" + targetUser + "に対してオブジェクト操作します。");
		System.out.println("");
	}

	@Before
	public void setUpMethod() {
		System.out.println("");
		System.out.println("==================================== "
			+ testno
			+ " つめのテストを開始します ====================================");
	}

	@Test
	public void testAll() throws SQLException {
		testA();
		testB();
		testC();
	}

//	 @Test
	public void deleteAll() throws SQLException {
		deleteA();
		deleteB();
		deleteC();
	}

//	 @Test
	public void testA() throws SQLException {
		try {
			createTable();
			createTable2();
			insertData();
			selectData();
			deleteData();
			alterTable();

			System.out.println("\n\n\n");

			createView();
			selectView();

			System.out.println("\n\n\n");

			createSequence();
			selectSequence();
			alterSequence();

			System.out.println("\n\n\n");

			createIndex();
			alterIndex();

			System.out.println("\n\n\n");

		} catch (Exception e) {
			OracleAddUserException oracleAddUserException =
				new OracleAddUserException("testAでエラーが発生しました!", e);
			throw oracleAddUserException;
		}

	}

//	 @Test
	public void testB() throws SQLException {
		try {

			createProcedure();
			execProcedure();

			System.out.println("\n\n\n");

			createFunction();
			execFunction();

			System.out.println("\n\n\n");

			createType();

			System.out.println("\n\n\n");

			createPackage();
			createPackageBody();
			execPackage();

			System.out.println("\n\n\n");

		} catch (Exception e) {
			OracleAddUserException oracleAddUserException =
				new OracleAddUserException("testAでエラーが発生しました!", e);
			throw oracleAddUserException;
		}

	}

//	 @Test
	public void testC() throws SQLException {
		try {
			createProcedureByJob();
			createJob();
			executeJob();

			System.out.println("\n\n\n");

			createLobTable();
			insertBlob();
			selectBlob();

			System.out.println("\n\n\n");
			
			loadJava();
			createJavaFunction();
			execJavaFunction();
			
			System.out.println("\n\n\n");
			
		} catch (Exception e) {
			OracleAddUserException oracleAddUserException =
				new OracleAddUserException("testAでエラーが発生しました!", e);
			throw oracleAddUserException;
		}

	}

	// @Test
	public void deleteA() throws SQLException {
		try {
			dropIndex();
			System.out.println("\n\n\n");
			dropTable();
			System.out.println("\n\n\n");
			dropView();
			System.out.println("\n\n\n");
			dropSequence();
			System.out.println("\n\n\n");
			
		} catch (Exception e) {
			OracleAddUserException oracleAddUserException =
				new OracleAddUserException("testAでエラーが発生しました!", e);
			throw oracleAddUserException;
		}
	}

	// @Test
	public void deleteB() throws SQLException {
		try {
			/*
			 * ユーザ作成(); 権限付与();
			 */

			dropProcedure();

			System.out.println("\n\n\n");

			dropFunction();

			System.out.println("\n\n\n");

			dropPackage();

			System.out.println("\n\n\n");

			dropType();
			
			System.out.println("\n\n\n");

		} catch (Exception e) {
			OracleAddUserException oracleAddUserException =
				new OracleAddUserException("testAでエラーが発生しました!", e);
			throw oracleAddUserException;
		}
	}

	// @Test
	public void deleteC() throws SQLException {
		try {
			dropProcedureByJob();
			System.out.println("\n\n\n");
			dropJob();
			System.out.println("\n\n\n");
			dropLobTable();
			System.out.println("\n\n\n");
			dropJavaFunction();
			System.out.println("\n\n\n");
			dropJava();
			System.out.println("\n\n\n");
			
		} catch (Exception e) {
			OracleAddUserException oracleAddUserException =
				new OracleAddUserException("testAでエラーが発生しました!", e);
			throw oracleAddUserException;
		}
	}

	// @Test
	public void createUser() throws SQLException {
		System.out.println("ユーザを作成します。");
		sql =
			"CREATE USER "
				+ targetUser
				+ " PROFILE DEFAULT "
				+ "IDENTIFIED BY "
				+ targetUserPass
				+ " DEFAULT TABLESPACE USERS "
				+ "TEMPORARY TABLESPACE TEMP "
				+ "ACCOUNT UNLOCK";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("ユーザ" + targetUser + "を作成しました");
	}

	// @Test
	public void grantTo() throws SQLException {
		System.out.println("権限を付与します。");
		sql = "GRANT DBA TO " + targetUser;
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("ユーザ" + targetUser + "にDBA権限を付与しました");
	}

	// @Test
	public void RevokeTo() throws SQLException {
		System.out.println("権限を剥奪します。");
		sql = "REVOKE DBA TO " + targetUser;
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("ユーザ" + targetUser + "のDBA権限を剥奪しました");
	}

	// @Test
	public void dropUser() throws SQLException {
		System.out.println("ユーザ削除します");
		sql = "DROP USER " + targetUser + " CASCADE";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("ユーザ" + targetUser + "を削除しました");
	}

	// @Test
	public void createTable() throws SQLException {
		System.out.println("テーブルを作成します");
		sql =
			"CREATE TABLE "
				+ targetUser
				+ "."
				+ "EMPLOYEETABLE ( "
				+ "EmployeeID INTEGER NOT NULL PRIMARY KEY, "
				+ "Name CHAR(20), "
				+ "GroupID INTEGER NOT NULL )";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("テーブルを作成しました");

	}

	// @Test
	public void createTable2() throws SQLException {
		System.out.println("テーブルを作成します2");
		sql =
			"CREATE TABLE "
				+ targetUser
				+ "."
				+ "GroupTable ( "
				+ "GroupID INTEGER NOT NULL PRIMARY KEY, "
				+ "GroupName CHAR(20))";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("テーブルを作成しました2");
	}

	// @Test
	public void insertData() throws SQLException {
		System.out.println("テーブルデータを挿入します");
		sql =
			"INSERT INTO "
				+ targetUser
				+ "."
				+ "EMPLOYEETABLE VALUES (42136, '小津安二郎', 3)";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		sql =
			"INSERT INTO "
				+ targetUser
				+ "."
				+ "EMPLOYEETABLE VALUES (77777, 'デビッドフィンチャー', 2)";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		sql = "INSERT INTO " + targetUser + "." + "GROUPTABLE VALUES (2, '監督')";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("テーブルデータを挿入しました");
	}

	// @Test
	public void selectData() throws SQLException {
		System.out.println("テーブルデータを参照します");
		sql = "select * from " + targetUser + "." + "EMPLOYEETABLE";
		result = nowStatement.executeQuery(sql);
		while (result.next()) {
			String string = result.getString("name");
			System.out.println("selectデータ :→→→→→: " + string);
		}
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("テーブルデータを参照しました");
	}

	// @Test
	public void deleteData() throws SQLException {
		System.out.println("テーブルデータを削除します");
		sql =
			"DELETE FROM "
				+ targetUser
				+ "."
				+ "EMPLOYEETABLE WHERE NAME = '小津安二郎'";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("テーブルデータを削除しました");
	}

	// @Test
	public void alterTable() throws SQLException {
		System.out.println("テーブルをALTERします");
		sql =
			"ALTER TABLE "
				+ targetUser
				+ "."
				+ "EMPLOYEETABLE ADD (addcolumn VARCHAR2(20))";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("テーブルをALTERしました");
	}

	// @Test
	public void dropTable() throws SQLException {
		System.out.println("テーブルを削除します");
		sql = "DROP TABLE " + targetUser + "." + "EMPLOYEETABLE purge";
		nowStatement.execute(sql);
		sql = "DROP TABLE " + targetUser + "." + "grouptable purge";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("テーブルを削除しました");
	}

	// @Test
	public void createView() throws SQLException {
		System.out.println("ビューを作成します");
		sql =
			"CREATE OR REPLACE VIEW "
				+ targetUser
				+ "."
				+ "emp_view AS "
				+ "select "
				+ "e.name , "
				+ "g.groupname "
				+ "from "
				+ targetUser
				+ "."
				+ "EMPLOYEETABLE e , "
				+ targetUser
				+ "."
				+ "grouptable g "
				+ "where e.groupid = g.groupid "
				+ "with read only";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("ビューを作成しました");
	}

	// @Test
	public void selectView() throws SQLException {
		System.out.println("ビューを参照します");
		sql = "select * from " + targetUser + "." + "emp_view";
		result = nowStatement.executeQuery(sql);
		while (result.next()) {
			System.out.println(result.getString(1));
			System.out.println(result.getString(2));
		}
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("ビューを参照しました");
	}

	// @Test
	public void dropView() throws SQLException {
		System.out.println("ビューを削除します");
		sql = "DROP VIEW " + targetUser + "." + "emp_view";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("ビューを削除しました");
	}

	// @Test
	public void createSequence() throws SQLException {
		System.out.println("シーケンスを作成します");
		sql =
			"CREATE SEQUENCE "
				+ targetUser
				+ "."
				+ "exseq "
				+ "START WITH 7 "
				+ "INCREMENT BY 1 "
				+ "MAXVALUE 1000000"
				+ "MINVALUE 0"
				+ "NOCYCLE ";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("シーケンスを作成しました");
	}

	// @Test
	public void selectSequence() throws SQLException {
		System.out.println("シーケンスを参照します");
		sql = "SELECT " + targetUser + "." + "exseq.nextval FROM dual";
		result = nowStatement.executeQuery(sql);
		while (result.next()) {
			String str = result.getString(1);
			System.out.println("シーケンス参照 : → :" + str);
		}
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("シーケンスを参照しました");
	}

	// @Test
	public void alterSequence() throws SQLException {
		System.out.println("シーケンスを変更します");
		sql =
			"ALTER SEQUENCE "
				+ targetUser
				+ "."
				+ "exseq"
				+ " INCREMENT BY 100";
		System.out.println(sql);
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("シーケンスを変更しました");
	}

	// @Test
	public void dropSequence() throws SQLException {
		System.out.println("シーケンスを削除します");
		sql = "DROP SEQUENCE " + targetUser + "." + "exseq";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("シーケンスを削除しました");
	}

	// @Test
	public void createIndex() throws SQLException {
		System.out.println("インデックスを作成します");
		sql =
			"CREATE INDEX "
				+ targetUser
				+ "."
				+ "index_id "
				+ "ON "
				+ targetUser
				+ "."
				+ "EMPLOYEETABLE( groupid asc )";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("インデックスを作成しました");
	}

	// @Test
	public void alterIndex() throws SQLException {
		System.out.println("インデックスをALTERします");
		sql = "ALTER INDEX " + targetUser + "." + "index_id REBUILD ONLINE";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("インデックスをALTERしました");
	}

	// @Test
	public void dropIndex() throws SQLException {
		System.out.println("インデックスを削除します");
		sql = "DROP INDEX " + targetUser + "." + "index_id";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("インデックスを削除しました");
	}

	// @Test
	public void createProcedure() throws SQLException {
		System.out.println("プロシージャを作成します");
		sql =
			"\nCREATE OR REPLACE PROCEDURE "
				+ targetUser
				+ "."
				+ "out_put(input in NUMBER , result out NUMBER) "
				+ "\nIS "
				+ "\nBEGIN"
				+ "\n\tresult := (input + 1);"
				+ "\nEND;\n";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("プロシージャを作成しました");
	}

	// @Test
	public void execProcedure() throws SQLException {
		System.out.println("プロシージャを実行します");
		// sql = "begin " + targetUser + "." + "out_put(?,?); end;";
		sql = "{call " + targetUser + "." + "out_put(?,?)}";
		System.out.println("呼び出すストアドプログラム : " + sql);
		cs = conn.prepareCall(sql);
		cs.registerOutParameter(2, Types.NUMERIC);
		cs.setInt(1, 10);
		cs.executeUpdate();
		int str = cs.getInt(2);
		cs.close();
		System.out.println(str);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("プロシージャを実行しました");
	}

	// @Test
	public void dropProcedure() throws SQLException {
		System.out.println("プロシージャを削除します");
		sql = "DROP PROCEDURE " + targetUser + "." + "out_put";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("プロシージャを削除しました");
	}

	// @Test
	public void createFunction() throws SQLException {
		System.out.println("ファンクションを作成します");

		sql =
			"\nCREATE or REPLACE FUNCTION "
				+ targetUser
				+ "."
				+ "get_data_func(in_data in varchar2)"
				+ "\n return varchar2 "
				+ "\nIS"
				+ "\nBEGIN"
				+ "\n	return in_data;"
				+ "\nEND get_data_func;\n";

		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("ファンクションを作成しました");
	}

	// @Test
	public void execFunction() throws SQLException {
		System.out.println("ファンクションを実行します");
		// sql = "begin ? :=" + targetUser + "." + "get_data_func(?); end;";
		sql = "{? = call + " + targetUser + "." + "get_data_func(?)}";
		CallableStatement cs = conn.prepareCall(sql);
		cs.registerOutParameter(1, Types.VARCHAR);
		cs.setString(2, "Hello World!");
		cs.executeUpdate();
		String data = cs.getString(1);
		cs.close();
		System.out.println("Functionの戻り値 :→:" + data);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("ファンクションを実行しました");
	}

	// @Test
	public void dropFunction() throws SQLException {
		System.out.println("ファンクションを削除します");
		sql = "DROP FUNCTION " + targetUser + "." + "get_data_func";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("ファンクションを削除しました");
	}

	// @Test
	public void createType() throws SQLException {
		System.out.println("TYPEを作成します");
		sql =
			"\nCREATE OR REPLACE TYPE "
				+ targetUser
				+ "."
				+ "ARRAY_TYPE"
				+ "\nIS"
				+ "\nTABLE OF VARCHAR2(50);\n";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("TYPEを作成しました");
	}

	// @Test
	public void createPackage() throws SQLException {
		System.out.println("パッケージ仕様部を作成します");

		sql =
			"\nCREATE OR REPLACE PACKAGE "
				+ targetUser
				+ "."
				+ "test_pack"
				+ "\nIS"
				+ "\n	arrayType ARRAY_TYPE;"
				+ "\n	FUNCTION out_put RETURN ARRAY_TYPE;"
				+ "\nEND;\n";

		nowStatement.execute(sql);
		System.out.println("パッケージを仕様部を作成しました");
	}

	// @Test
	public void createPackageBody() throws SQLException {
		System.out.println("パッケージ本体を作成します");

		sql =
			"\nCREATE OR REPLACE PACKAGE BODY "
				+ targetUser
				+ "."
				+ "test_pack"
				+ "\nIS"
				+ "\n	FUNCTION out_put RETURN ARRAY_TYPE"
				+ "\n		is"
				+ "\n		BEGIN"
				+ "\n 			SELECT NAME BULK COLLECT INTO arrayType from EMPLOYEETABLE;"
				+ "\n			RETURN arrayType;"
				+ "\n		END;"
				+ "\nEND;\n";

		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("パッケージを本体を作成しました");
	}

	// @Test
	public void execPackage() throws SQLException {
		System.out.println("パッケージを実行します");
		sql = "begin ? := " + targetUser + "." + "test_pack.out_put(); end;";
		System.out.println("実行パッケージ内FUNCTION : " + sql);
		CallableStatement cs = conn.prepareCall(sql);
		cs.registerOutParameter(1, OracleTypes.ARRAY, "ODU"
			+ "."
			+ "ARRAY_TYPE");
		cs.executeUpdate();
		Array array = cs.getArray(1);
		String[] str = (String[]) array.getArray();
		cs.close();
		System.out.println("パッケージ実行結果 : → :" + array);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("パッケージを実行しました");
	}

	// @Test
	public void dropPackage() throws SQLException {
		System.out.println("パッケージを削除します");
		sql = "DROP PACKAGE " + targetUser + "." + "test_pack";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("パッケージを削除しました");
	}

	// @Test
	public void dropType() throws SQLException {
		System.out.println("TYPEを削除します");
		sql = "DROP TYPE " + targetUser + "." + "ARRAY_TYPE";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("TYPEを削除しました");
	}

	// @Test
	public void createProcedureByJob() throws SQLException {
		System.out.println("JOB用プロシージャを作成します");
		sql =
			"\nCREATE OR REPLACE PROCEDURE "
				+ targetUser
				+ "."
				+ "deleteAllEmp "
				+ "\nIS "
				+ "\nBEGIN"
				+ "\n\tdelete from EMPLOYEETABLE;"
				+ "\nEND;\n";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("JOB用プロシージャを作成しました");
	}

	// @Test
	public void createJob() throws SQLException {
		System.out.println("JOBを作成します");
		sql =
			"\nBEGIN"
				+ "\n\tDBMS_SCHEDULER.CREATE_JOB ("
				+ "\n\tjob_name	=>	'"
				+ targetUser
				+ ".myjob',"
				+ "\n\tjob_type	=>	'STORED_PROCEDURE',"
				+ "\n\tjob_action =>'DELETEALLEMP');"
				+ "\nEND;\n";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("JOBを作成しました");
	}

	// @Test
	public void executeJob() throws SQLException {
		System.out.println("JOBを実行します");
		sql = "select * from " + targetUser + "." + "EMPLOYEETABLE";
		result = nowStatement.executeQuery(sql);
		while (result.next()) {
			String string = result.getString("name");
			System.out.println("selectデータ :→→→→→: " + string);
		}
		sql =
			"\nBEGIN"
				+ "\nDBMS_SCHEDULER.RUN_JOB ('"
				+ targetUser
				+ ".myjob');"
				+ "\nEND;\n";
		nowStatement.execute(sql);
		sql = "select * from " + targetUser + "." + "EMPLOYEETABLE";
		result = nowStatement.executeQuery(sql);
		if (!result.next()) {
			System.out.println("データ消えてる");
		}
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("JOBを実行しました");
	}

	// @Test
	public void dropProcedureByJob() throws SQLException {
		System.out.println("JOB用プロシージャを削除します");
		sql = "DROP PROCEDURE " + targetUser + "." + "deleteAllEmp";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("JOB用プロシージャを削除しました");
	}

	// @Test
	public void dropJob() throws SQLException {
		System.out.println("JOBを削除します");
		sql =
			"\nBEGIN"
				+ "\nDBMS_SCHEDULER.DROP_JOB ('"
				+ targetUser
				+ ".myjob'); "
				+ "\nEND;\n";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("JOBを削除しました");
	}

//	 @Test
	public void createLobTable() throws SQLException {
		System.out.println("LOBテーブルを作成します");
		sql =
			"CREATE TABLE "
				+ targetUser
				+ "."
				+ "IMGTABLE ( "
				+ "ID VARCHAR(4) NOT NULL primary key,"
				+ "fileName VARCHAR(20) not null,"
				+ "IMG BLOB)";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("LOBテーブルを作成しました");

	}

	// @Test
	public void insertBlob() throws SQLException, Exception {
		System.out.println("BLOBをinsertします");
		nowStatement = conn.createStatement();

		File file = new File("Sunset.jpg");

		StringBuffer sb =
			new StringBuffer("INSERT INTO "
				+ targetUser
				+ ".imgtable (id,fileName,img)");

		sb.append("VALUES(?,?,?)");

		nowPstatement = conn.prepareStatement(sb.toString());

		nowPstatement.setString(1, "01");
		nowPstatement.setString(2, file.getName());
		nowPstatement.setBinaryStream(3, new FileInputStream(file), (int) file
			.length());

		int cnt = nowPstatement.executeUpdate();
		System.out.println("BLOBをinsertしました");
	}

	// @Test
	public void selectBlob() throws SQLException, Exception {
		System.out.println("BLOBを取得します");
		nowPstatement =
			conn.prepareStatement(""
				+ "select img from "
				+ targetUser
				+ ".imgtable Where id = ?");

		nowPstatement.setString(1, "01");

		result = nowPstatement.executeQuery();

		int iData = 0;
		InputStream inputStream = null;
		BufferedInputStream bf = null;

		while (result.next()) {
			Blob blob = (Blob) result.getBlob(1);
			inputStream = blob.getBinaryStream();
		}

		bf = new BufferedInputStream(inputStream);

		FileOutputStream out = new FileOutputStream("copySunset.jpg");

		while ((iData = bf.read()) != -1) {
			out.write(iData);
		}
		System.out.println("BLOBを取得しました");
	}

//	 @Test
	public void dropLobTable() throws SQLException {
		System.out.println("テーブルを削除します");
		sql = "DROP TABLE " + targetUser + "." + "IMGTABLE purge";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("テーブルを削除しました");
	}
	
//	@Test
	public void loadJava() throws Exception{
		System.out.println("Javaをoracleにロードします");
		String user = connectionUser + "/" + connectionPass + "@sudaorcl";
		ProcessBuilder pb = new ProcessBuilder("CMD.EXE", "/C", "loadjava", "-user", user , "-schema" , targetUser , "C:\\Oscar.class" , ">", "stdout.txt", "2>", "stderr.txt");
//		ProcessBuilder pb = new ProcessBuilder("CMD.EXE", "/C", "loadjava", "-user", "odu/hogeodu@sudaorcl" , "C:\\Oscar.class" , ">", "stdout.txt", "2>", "stderr.txt");
		
		Process process = pb.start();
		
		process.waitFor();
		
		System.out.println("Javaをoracleにロードしました");
	}
	
//	@Test
	public void createJavaFunction() throws SQLException {
		System.out.println("Javaファンクションを作成します");

		sql =
			"\nCREATE or REPLACE FUNCTION "
				+ targetUser
				+ "."
				+ "javaFunc"
				+ "\nRETURN varchar2 "
				+ "\nIS LANGUAGE java"
				+ "\nNAME 'jp.co.suda.oracle.Oscar.quote() return java.lang.String';";

		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("Javaファンクションを作成しました");
	}
	
//	@Test
	public void execJavaFunction() throws SQLException{
		System.out.println("Javaファンクションを実行します");
		sql = "{? = call + " + targetUser + "." + "javaFunc}";
		CallableStatement cs = conn.prepareCall(sql);
		cs.registerOutParameter(1, Types.VARCHAR);
		cs.executeUpdate();
		String data = cs.getString(1);
		cs.close();
		System.out.println("Functionの戻り値 :→:" + data);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("Javaファンクションを実行しました");
	}
	
//	 @Test
	public void dropJavaFunction() throws SQLException {
		System.out.println("Javaファンクションを削除します");
		sql = "DROP FUNCTION " + targetUser + "." + "javaFunc";
		nowStatement.execute(sql);
		System.out.println("sql的には : " + sql + "を実行したからね");
		System.out.println("Javaファンクションを削除しました");
	}
	
//	 @Test
	public void dropJava() throws SQLException, Exception {
		System.out.println("Javaをクラスを削除します");
		String conuser = connectionUser + "/" + connectionPass + "@sudaorcl";
		ProcessBuilder pb = new ProcessBuilder("CMD.EXE", "/C", "dropjava", "-user", conuser , "-schema" , targetUser , "C:\\Oscar.class" , ">", "stdDROPout.txt", "2>", "stdDROPerr.txt");
		Process process = pb.start();
		
		InputStream is = process.getInputStream();
	    BufferedReader br = new BufferedReader(new InputStreamReader(is));
	    String line;
	    while ((line = br.readLine()) != null) {
	    	System.out.println(line.toString());
	    }
		process.waitFor();
		System.out.println("Javaをクラスを削除しました");
		
		System.out.println("JavaLOBテーブルを削除します");
		sql = "DROP TABLE " + targetUser + "." + "CREATE$JAVA$LOB$TABLE purge";
		nowStatement.execute(sql);
		System.out.println("JavaLOBテーブルを削除します");
		
	}
	
	
	
	
	@After
	public void tearDownMethod() {
		System.out.println("==================================== "
			+ testno
			+ " つめのテストを終了します ====================================");
		testno = testno + 1;
	}

	/**
	 * 
	 * クローズ処理
	 * 
	 * @throws Exception
	 */
	@AfterClass
	public static void teardown() throws Exception {
		DatabaseMetaData metaData = conn.getMetaData();
		System.out.println("");
		System.out.println("");
		System.out
			.println("接続ユーザ" + metaData.getUserName() + "のコネクションをクローズします");
		if (result != null) {
			result.close();
		}
		if (result != null) {
			nowStatement.close();
		}
		if (conn != null) {
			// ここでoracleのセッションも破棄される
			conn.close();
		}
	}

}

パーフェクトJavaScript読書メモ 6章

パーフェクトJavaScript (PERFECT SERIES 4)

パーフェクトJavaScript (PERFECT SERIES 4)


基本的に自分にとって大切な部分を抜粋させてもらってるメモです。言い方などが一部自分語になっている部分はあります。あくまで自身のための要約ですので、間違って解釈している部分等あるかもしれません。もちろんそのまま引用させていただいている文章に間違いはないはずですし、大体そうなのですが、間違ってたら申し訳ないので、書き添えさせていただきました。すばらしい書籍ですので、JavaScriptを使う初心者すべての方におすすめです。

6-2 関数呼び出しの整理

関数自体に分類があるわけではなく、呼び方の違いの分類であることに注意。つまり、ある関数を取り上げてそれをメソッドと呼ぶのは厳密には正しくない。正しくはその関数をメソッド呼び出ししたかどうかである。

関数呼び出しの分類
  1. メソッド呼び出し レシーバオブジェクト経由での関数呼び出し(applyとcallの呼び出しも含む)
  2. コンストラクタ呼び出し new式での関数呼び出し
  3. 関数呼び出し 上記2つ以外の関数呼び出し

6-5 関数はオブジェクト

関数はオブジェクトの一種です。内部的にはFunctionオブジェクトを継承します。これは以下のようにconstructorプロパティで確認できます。

js> function f(){}
js> f.constructor
function Function() {[native code]}

以下の大局的に見ると、実体(名なしのオブジェクト)の生成とそれを参照する名前を結びつけるコードという共通点があります。

var obj = {};
var obj = new MyClass();
var obj = function(){};
function obj(){}

6-7 入れ子の関数宣言とクロージャ

6-7-2 クロージャの仕組み

入れ子の関数宣言
function f(){
	function g(){
		alert('g is called');
	}
	g();
}
f(); // g is called

おさらいですが、JavaScriptの変数はプロパティです。それはグローバルとローカルという2つのスコープのどちらかにわかれます。グローバルはグローバルオブジェクトのプロパティです。一方関数内で宣言された変数がローカル変数であり、このローカル変数(関数のパラメータ変数も同様)とはその関数が呼ばれた時に暗黙的に生成されるCallオブジェクトのプロパティなんです。一般に変数の生存期間は関数が呼ばれてからぬけるまでだが、ここでクロージャを考慮にいれると抜けた後もアクセス可能なローカル変数が存在できるのです。

トップレベルコードでの関数fの宣言は、関数オブジェクトの生成と変数fによる関数オブジェクトの参照を意味します。変数fはグローバルオブジェクトのプロパティです。
JavaScriptでは関数を呼ぶたびにCallオブジェクトが暗黙に生成されます。関数f呼び出し時のCallオブジェクトを便宜上Call-fオブジェクトと呼びます。Callオブジェクトは関数呼び出しが終わると消滅します。
関数f内の関数gの宣言は関数gに対応する関数オブジェクトを生成する。名前gはCall-fオブジェクトのプロパティです。Callオブジェクトは関数呼び出しごとに独立しているので、関数gを呼ぶと別のCallオブジェクトが暗黙に生成されます。このCallオブジェクトを便宜上Call-gオブジェクトと呼ぶ。
関数gを抜けるとCall-gオブジェクトは自動で消滅します。同様に関数fを抜けるとCall-fオブジェクトが消滅します。この時、gが参照する関数オブジェクトは、プロパティgがCall-fオブジェクトとともに消滅するので、参照元がなくなる結果、消滅します(ガベージコレクションのため)

入れ子の関数とスコープ
var n = 'global';
function f(){
	var n = 'fff';
	function g(){
		var n = 'ggg';
                alert('n is ' + n);
		alert('g is called');
	}
	g()
}
f();

変数nの3箇所の宣言文の宣言場所によってnの値がどのようにアラートされるのか。関数内での変数の解決はCallオブジェクトのプロパティ、グローバルオブジェクトのプロパティの順で探す。上の例の場合は、g()が呼ばれた時にCall-gオブジェクトが生成されると考えると、関数内の変数はその関数のCallオブジェクトのプロパティなんだから、まずg()内部の変数nを探し、なければ外側の関数のCallオブジェクト(この場合だとCall-fオブジェクト)、さらになければ、この場合、グローバルオブジェクトのプロパティであるところの一番外側のnを探し当てるということになる。これをスコープチェーンと呼ぶ。

入れ子の関数を返す
クロージャ
function f(){
	var n = 123;
	function g(){
		alert('n is ' + n);
		alert('g is called');
	}
	return g;
}
var g2 = f();
g2();

関数fを呼んだ時のCallオブジェクト(Call-fオブジェクト)のプロパティgが参照していた関数オブジェクトをg2が参照します。参照元がある限りガーベージコレクションの対象にならないので、名前g2が有効な限り、関数オブジェクトも生きている。この関数オブジェクトはCall-fオブジェクトへの参照を持ちます(スコープチェーンのために使う)結果、名前g2から参照されるこの関数オブジェクトが残る限り、Call-fオブジェクトも残る。これが関数fを抜けてもローカル変数nが生きている理由です。

6-7-4 名前空間の汚染を防ぐ

//関数リテラル(無名)をその場で呼び出す
	//関数リテラルの返り値は関数なので変数sumは関数
	var sum = (function() {
		//関数の外部からこの名前にアクセスできない
		//事実上プライベートな変数
		//通常、関数の呼び出しが終わればアクセス出来ない名前だが
		//返り値の無名関数のなかから使える
		var position = {
			x : 2,
			y : 3
		};

		//同じく関数の外部からアクセスできなプライベート関数
		//名前をsumにしても問題ないが、余計な混乱を避けるためここでは別名にしている
		function sum_internal(a, b) {
			return Number(a) + Number(b);
		}

		//上記2つの名前を強引に使うだけの恣意的な返り値
		return function(a, b) {
			alert('x = ' + position.x);
			return sum_internal(a, b);
		}
		
	})();
	
        //呼び出し
	alert(sum(3,4)); // 7
	alert(sum_internal(3,4)); //sum_internal is not defined
	alert(position.x); //position is not defined


抽象化すると以下の様な感じ

(function() { 関数本体 })();

関数スコープによる名前の閉じ込めと、クロージャで関数を抜けた後も生きている名前、という2つの特性を活用した情報隠蔽です。


関数リテラルでなく、以下のようにオブジェクトリテラルを返しても情報隠蔽の目的は達成できる。

	var obj = (function() {
		//関数の外部からこの名前にアクセスできない
		//事実上プライベートな変数
		var position = {
			x : 800,
			y : 777
		};

		//同じく関数の外部からアクセスできないプライベート関数
		function sum_internal(a, b) {
			return Number(a) + Number(b);
		}

		//上記2つの名前を強引に使うだけの恣意的な返り値
		return {
			sum : function(a, b) {
				return sum_internal(a, b);
			},
			x : position.x,
			y : position.y
		};
	})();

	//呼び出し
	alert(obj.sum(10, 10)); //20
	alert(obj.x); // 800
	alert(obj.y); // 777

6-7-5 クロージャとクラス

//クラス定義もどき
function MyClass(x,y){
	//フィールド相当
	this.x = x;
	this.y = y;
	//メソッド相当
	this.show = function(){
		alert(this.x + " " + this.y);
	}
}

var obj = new MyClass(3,2);
obj.show();
alert(obj.x); // 3 アクセス可能
alert(obj.y); // 2 アクセス可能

プロパティに外からアクセスできてしまう。それなので、こうしてあげよう

function myclass(x, y){
	return { show : function(){alert(x + " " + y);}}
}
var obj = myclass(3,7);
obj.show();
alert(obj.x); //undefined 情報隠蔽
alert(obj.y); //undefined 情報隠蔽


もう一つの例を見て、クロージャを使うクラスの形をつかもう

function counter_class(init){
	var cnt = init || 0;
	
	//必要であればここにプライベートな変数や関数を宣言
	
	return {
		//公開メソッド
		show: function(){alert(cnt);},
		up: function(){cnt++; return this;},
		down: function(){cnt--; return this;}
	};
}

var counter1 = counter_class();
counter1.show(); // 0と表示
counter1.up(); 
counter1.show(); // 1と表示

var counter2 = counter_class(10);
counter2.up().up().up().show(); // 13と表示 メソッドチェーン

6-8-2 JavaScriptとコールバック

クロージャとコールバック
var emitter = {
		// 複数のコールバック関数を登録できるように配列で管理
		callbacks:[],
		//コールバック関数登録メソッド
		register: function(fn){
			this.callbacks.push(fn);
		},
		//イベント発火処理
		onOpen:function(){
			for each ( var f in this.callbacks){
				f();
			}
		}
};

//クロージャをコールバック関数に登録
//ここで登録されるのはfunction(){alert(msg + 'is called');}という本文を持った関数オブジェクトですね
emitter.register((function(){ var msg = 'closure1'; return function(){alert(msg + 'is called');}})());
emitter.register((function(){ var msg = 'closure2'; return function(){alert(msg + 'is called');}})());

//イベント発火のエミュレーション(コールバック関数の呼び出し)
emitter.onOpen();

パーフェクトJavaScript読書メモ 5章

パーフェクトJavaScript (PERFECT SERIES 4)

パーフェクトJavaScript (PERFECT SERIES 4)

あまりにも素晴らしい本なので、自分で抜粋させていただき、頭の整理をさせて頂く。
これだけ書かれてる本はちょっとすごい。ちょっと私の頭では1回では難しい。でも本質の理解にはもってこいの書籍すぎてすばらしい。理解に近道はない。きっちりやっておくと、なにかと後々ためになりますよね。とりあえず5章で私にとっての重大ごとを。

5-3変数とプロパティ

変数はスコープの違いで、グローバル変数とローカル変数に分かれる。

グローバル変数

グローバル変数(及びグローバル関数名)はグローバルオブジェクト(実行時に最初から存在するオブジェクト)のプロパティです。クライアントサイドJavaScriptでは最初からグローバルオブジェクトを参照するグローバル変数windowが提供されています。

ローカル変数

関数内で宣言した変数。関数の引数のパラメータ変数もローカル変数の1種。ローカル変数(パラメータ変数)は関数が呼ばれた時に暗黙に生成されるオブジェクトのプロパティ。暗黙に生成されるオブジェうとをCallオブジェクトと呼ぶ。一般にローカル変数の生存期間は関数が呼ばれてから抜けるまで。

5-7オブジェクト生成

5-7-2コンストラクタとnew式

function MyClass(x,y){
	this.x = x;
	this.y = y;
}

var obj = new MyClass(3, 2);
alert(obj.x + " " + obj.y);
  • コンストラクタの形式的な説明
    1. コンストラクタ自体は普通の関数宣言と同じ形
    2. コンストラクタはnew式で呼び出す
    3. コンストラクタを呼び出すnew式の評価値は(新規に生成された)オブジェクト参照
    4. new式で呼ばれたコンストラクタ内のthis参照は(新規に生成する)オブジェクトを参照する


コンストラクタと通常の関数の違いは呼び出し方の違いのみ。


コンストラクタは暗黙に関数の最後にreturn thisがあるような動作をします。ではコンストラクタ内に本当のreturn文があると何が起きるのでしょうか。実はやや分かりにくい挙動になります。returnでオブジェクトを返すとそれがコンストラクタ呼び出し時のnew式の評価値になります。つまりnew式を使っても生成したオブジェクト以外のオブジェクトが返ります。一方、基本型の値をreturnで返すとコンストラクタ呼び出し時には無視され、暗黙にreturn thisがある挙動をします。この挙動は混乱の元なのでコンストラクタにreturn文を書かないことを進めます。


リスト5.9クラス定義もどき(改善の余地あり)

function MyClass2(x,y){
	//フィールド相当
	this.x = x;
	this.y = y;
	//メソッド相当
	this.show = function(){
		alert(this.x + " " + this.y);
	}
}
var obj = new MyClass2(3,2);
obj.show();
  • 上記MyClass2の2つの問題点
    1. すべてのインスタンスが同じメソッド定義の実態のコピーを持つので効率(メモリ効率と実行効率)が良くない。→ プロタイプ継承で解決
    2. プロパティのアクセス制御(private public)ができない → クロージャで解決

5-8プロパティのアクセス

オブジェクト参照に対して、ドット演算子もしくはブラケット演算子でプロパティにアクセスできます。

5-8-2ドット演算子とブラケット演算子の使い分け

慣習的には、記述が簡潔なドット演算子をデフォルトにし、ブラケット演算子でしか書けない場合にブラケット演算子を使うのが一般的。

ブラケット演算子でしか書けないパターン

●識別子に使えないプロパティ名を使う場合

js> obj = {'hoge-hoge':10};
({'hoge-hoge':10})
js> obj.hoge-hoge
NaN
js> obj['hoge-hoge']
10

●変数の値をプロパティ名に使う場合
例えば、配列オブジェクトのプロパティ名は数値です。数値をドット演算子に続けて書けないので必然的にブラケット演算子を使います。配列の要素アクセスにブラケット演算を使うプログラミング言語は多いので可読性も上がります。

●式の評価を結果をプロパティ名に使う場合

5-8-3プロパティの列挙

var obj = {x:3,y:4,z:5};
for ( var key in obj) {
	alert('key = ' + key);
	alert('val = ' + obj[key]);
}

5-9連想配列としてのオブジェクト

5-9-1連想配列について

delete演算子について

オブジェクトからプロパティを削除する。
deleteはMap用語で言うところのキーを削除するだけで、値に関してはメモリに残る。その値はガーベージコレクションで消えるかもしれないが、それはdeleteの直接の働きではない。

var map = {x:3,y:4};
alert(map.x);
var b = delete map.x; //delete map['x']でも可
alert(b); //削除に成功するとtrue
alert(map.x); //削除した要素を読むとundefinedが返る

5-9-2連想配列としてのオブジェクトの注意点

function MyClass(){}
MyClass.prototype.z = 5; //プロトタイプチェーン上にプロパティzをセット
var obj = new MyClass();
alert(obj.z);

//for in はプロトタイプ継承したプロパティも列挙する。
for ( var key in obj) {
	alert(key);
}

//プロトタイプ継承したプロパティはdeleteできない。
var b = delete obj.z;
alert(b); //trueは返るが、
alert(obj.z); //削除はできない。
//オブジェクトを連想配列として使う場合、オブジェクトリテラルで生成するのが一般的、
//実際にはObjectクラスからプロパティを継承しているので注意が必要。
var map = {};
var r = 'toString' in map;
alert(r);//true

// Objectクラスをプロトタイプ継承したプロパティは列挙されない。
// enumerable属性のため(標準オブジェクトの一部のプロパティはこの属性がfalseである)。
// enumerable属性がfalseのプロパティはfor in文で列挙されない。
for ( var key in map) {
	alert(key);
}

//連想配列の存在チェックにin演算子を使うとプロタイプ継承したプロパティが引っかかる可能性がある
//よってhasOwnPropertyメソッドを使うといい。自分のプロパティのみの存在チェック。
var map = {};
alert(map.hasOwnProperty('toString'));//false
map['toString']=1;
alert(map.hasOwnProperty('toString'));//true
delete map['toString'];
alert(map.hasOwnProperty('toString'));//false

5-13 メソッド

JavaScriptの言語仕様にメソッドは存在しない。オブジェクトのプロパティに関数をセットしたものを便宜上メソッドと呼ぶだけ。

5-14 this参照

JavaC++

メソッドに暗黙に渡る引数とみなすことができる

JavaScript

トップレベルでも関数内でも使える。いつでも使える読み込み専用の変数です。オブジェクトを参照する。そしてコードのコンテキストに応じて自動的に参照先オブジェクトが変わる特別なものである。

5-14-1 this参照の規則

トップレベルコードのthis参照はグローバルオブジェクトを参照
関数内のthis参照は関数の呼び出し方法で異なる
//5-14-1
	alert('5-14-1');
	window.x = 'suda';
	var obj = {
		x : 3,
		doit : function() {
			alert('method is called. ' + this.x);
		}
	};
	obj.doit();
	obj['doit']();
	alert(this.x);

	//5-14-2
	alert('5-14-2');
	var obj = {
		x : 3,
		doit : function() {
			alert('method is called. ' + this.x);
		}
	};
	var fn = obj.doit; //obj.doitが参照する関数オブジェクトをグローバル変数に代入
	fn(); //関数内のthis参照はグルーバルオブジェクトを参照する
	
	var x = 5;
	fn();
	
	var obj2 = {x:4,doit2:fn};
	obj2.doit2();

5-15 applyとcall

function f() {
		alert(this.x);
	}
	var obj = {
		x : 4
	};

	f.apply(obj);
	f.call(obj);

	var obj = {
		x : 3,
		doit : function() {
			alert('method is called. ' + this.x);
		}
	}
	
	var obj2 = {x:4};
	obj.doit();
	obj.doit.apply();
	obj.doit.apply(obj2);

関数オブジェクトに存在するapplyとcallメソッドはその関数を呼び出す。関数内のthis参照を考慮しない場合は単なる関数呼び出しと変わらないが、this参照が関数内に存在する場合はthisが参照するオブジェクトを第1引数に渡すことで指定できる。

applyとcallの違い
function f(a, b) {
		alert('this.x= ' + this.x + ', a = ' + a + ',b = ' + b);
	}
	
	f.apply({x:4}, [1,2]); //第2引数の配列要素が関数fの引数になる
	f.call({x:4}, 1,2); //第2引数以降の引数が関数fの引数になる

5-16プロトタイプ継承

プロトタイプチェーン

前提
  1. すべての関数(オブジェクト)はprototypeという名前のプロパティを持つ(prototypeプロパティの参照先オブジェクトをprototypeオブジェクトと呼ぶことにします)
  2. すべてのオブジェクトは、オブジェクト生成に使ったコンストラクタ(関数オブジェクト)のprototypeオブジェクトへの(隠し)リンクを持つ
オブジェクトのプロパティ読み込み時の探索順序
  1. オブジェクト自身のプロパティ
  2. 暗黙リンクの参照オブジェクト(=コンストラクタのprototypeオブジェクト)のプロパティ
  3. 2のオブジェクトの暗黙リンクの参照オブジェクトのプロパティ
  4. 3の動作を探索が終わるまで続ける(探索の終端はObject.prototypeオブジェクト)
オブジェクトのプロパティ書き込み
  1. オブジェクト自身のプロパティ
プロトタイプチェーンによるプロパティの読み込み
function MyClass() {
		this.x = 'x in MyClass';
	}
	var obj = new MyClass(); //MyClassコンストラクタでオブジェクト生成
	alert(obj.x);			//オブジェクトobjのプロパティxにアクセス
	alert(obj.z);			//オブジェクトobjにプロパティzはない
	
	//関数オブジェクトは暗黙にprototypeプロパティを持つ
	MyClass.prototype.z = 'z in MyClass.prototype'; //コンストラクタのprototypeオブジェクトにプロパティzを追加
	alert(obj.z); //obj.zはコンストラクタのprototypeオブジェクトのプロパティにアクセス
	
	//prototypeに設定したので、以後生成するMyClassオブジェクトには、
	//共通してzプロパティが継承される
	var obj2 = new MyClass();
	alert('obj2 ' + obj2.z);
	
	var obj3 = new MyClass();
	alert('obj3 ' + obj3.z);
プロパティの書き込みと削除はプロトタイプチェーンを辿らない
        function MyClass(){this.x = 'x in MyClass';}
	MyClass.prototype.y = 'y in MyClass.prototype';
	
	var obj = new MyClass();
	alert(obj.y); 	// プロトタイプチェーンでプロパティyの読み取り
	
	obj.y = 'override'; // オブジェクトobjに直接プロパティyを追加
	alert(obj.y);		// 直接プロパティを読む
	
	var obj2 = new MyClass();
	alert(obj2.y);   // 別オブジェクトから見えるプロパティyは変わっていない 
	


	delete obj.y; //プロパティyを削除
	alert(obj.y);
	delete obj.y; //deleteの演算の評価値はtrueだが、
	alert(obj.y); //プロトタイプチェーン先のプロパティはdeleteできない

プロトタイプオブジェクト

function MyClass(){}
var obj = new MyClass();

MyClass.prototypeとobj.__proto__は同じオブジェクトを参照します。これがobjのプロトタイプオブジェクトです。

プロトタイプオブジェクトの取得方法
//プロトタイプオブジェクトの取得方法3例
function MyClass(){}
MyClass.prototype = {x:1050};
var Proto = MyClass.prototype;
alert('ProtoB ' + Proto.x);
var obj = new MyClass(); //オブジェクトobjのプロトタイプオブジェクトはオブジェクトProto

//インスタンスオブジェクトから取得(ECMAScript第5版の正攻法)
var Proto = Object.getPrototypeOf(obj);
alert('Proto1 ' + Proto.x);
//インスタンスオブジェクトから取得(独自拡張の__proto__利用)
var Proto = obj.__proto__;
alert('Proto2 ' + Proto.x);
//インスタンスオブジェクトからコンストラクタを経由した取得(常に使える保証はない)
var Proto = obj.constructor.prototype;
alert('Proto3 ' + Proto.x);

5-17オブジェクトと型

クラスベース言語

オブジェクトの型というのは雛形となるクラスや実装インターフェースになる。

JavaScript

この観点でのオブジェクトの型は存在しない(クラスやインターフェースはないから)。だが、組み込み基本型以外はすべてObject型であり、それらを生成して、そこに対してプログラマが恣意的にオブジェクトの共通性をprototype継承などを使って作ってゆくことにより、プロトタイプベースのオブジェクト指向での実装が可能になるし、そうするべきである。

5-17-4 型判定(ダックタイピング)

オブジェクトの振る舞いを直接調べて型を判定する手法を俗にダックタイピングと呼ぶ。ダックタイピングに使える手法の一つとしてin演算がある。プロトタイプチェーンで継承したプロパティも判別できる。以下ではobjの直接のプロパティだけでなく継承しているtoStringプロパティもtrueと判定される。

var obj = {};
obj.doit = function(){alert('doitMethod!');}
alert('doit' in obj); //オブジェクトobjがdoitプロパティを持つので結果はtrue
alert('toString' in obj); //toStringプロパティをObjectから継承しているので結果はtrue

5-17-5 プロパティの列挙(プロトタイプ継承を考慮)

ECMAScript第5版のObjectクラスのkeysメソッドとgetOwnPropertyNamesメソッドは引数に指定したオブジェクトの直接のプロパティ名の配列を返します。

var obj = {x:1,y:2};
alert(Object.keys(obj));
alert(Object.getOwnPropertyNames(obj)); //enumerable属性のデフォルト値は真なのでkeysと同じ結果

var arr = [3,4];
alert(Object.keys(arr));
alert(Object.getOwnPropertyNames(arr)); //lengthプロパティのenumerable属性は偽

//Object.prototypeオブジェクト
alert(Object.keys(Object.prototype)); //enumerableなプロパティは存在しない

alert(Object.getOwnPropertyNames(Object.prototype));

5-20 Objectクラス

Objectという名前は厳密にはグローバルオブジェクトのプロパティ名である。そのプロパティが参照しているのはFunctionオブジェクトである。なぜならObject()のように呼び出して機能するということはFunctionであるということでしょう?

5-21 グローバルオブジェクト

オブジェクトは本質的に名なしです。ObjectオブジェクトもStringオブジェクトもObject,Stringという名前(グローバルオブジェクトのプロパティ名)としてアクセス可能なだけ。グローバルオブジェクトの場合は仕様上決まった名前がない。クライアントサイドJavaScriptではwindowという変数名でアクセス可能。このwindowも実はグローバルオブジェクトのプロパティ名として存在している(循環参照)
ただしあくまでもECMAScriptのコア言語規格ではグローバルオブジェクトを参照する決まった名前は存在しません。

//トップレベルコードで下記コードを実行するとグローバルオブジェクトをどこでもglobalで参照可能
var global = this;

少しモヤモヤが解消されたのでmemoる

spidermonkeyを使ってコンソールで以下のJavaScriptを実行

js> var obj = new Object();
js> var fn = new Function();
js> print(typeof obj);
object
js> print(typeof fn);
function
js> print(typeof Object);
function
js> print(typeof String);
function
js> print(typeof Date);
function
js> print(typeof Array);
function
js> print(typeof Boolean);
function
js> print(typeof Number);
function
js> print(typeof window.Number);
typein:11: ReferenceError: window is not defined

最終行のwindowという変数はグローバルオブジェクトを参照するクライアントサイドJavaScriptでデフォルトで組み込まれている(グローバル)変数。なので、spidermonkeyから使用しようとしても組み込まれてませんのでエラー。ここで重要なことはグローバルオブジェクト(トップレベルで定義した変数とかはすべてこのオブジェクトのプロパティになる)自体はどちらにも存在するということで、windowというグローバルオブジェクトを参照する変数がここでは存在しないだけであるということ。グローバルオブジェクトとかきちんと理解しないと何も始まらない。


グローバルオブジェクトに関連して、上記コードでObjectやString等々のtypeofの結果が「function」であるのが解せなかったのですが、どうやらこれらは変数名であり、なんの変数名であるかというと「グローバルオブジェクト」の変数名であるということらしい。となれば、組み込み型と言われるこれらの文字列は、「コンストラクタとして呼ばれることが想定された関数オブジェクトを参照するグローバルオブジェクトのプロパティ」ということになり、すっきりした。


JavaScriptのコンストラクタって関数定義と基本的に定義の仕方は変わらない。newをつけて関数呼び出すとその関数はコンストラクタとして機能するという感じなので。それとJavaScriptの関数はオブジェクト。

JavaScriptイベント処理についてメモ


クックブックにあった例を少し改良し、要約的にメモっとく。忘れないように。

<script type="text/javascript">

	listenEvent(window, "load", function(){
		listenEvent(document.getElementById("hoge"), "click", processDivClick);
		listenEvent(document.getElementById("fuga"), "click", processButtonClick);
	});
	
	function processDivClick() {
		alert("divclick!");
	}
	function processButtonClick() {
		alert("buttonClick!");
	}

	function listenEvent(eventTarget, eventType, eventHandler) {
		//DOMLevel2のイベント処理(chrome,safari,opera,firefox)
		if (eventTarget.addEventListener) {
			//ここのfalseとtrueの違いについて
			//falseにしておくことで、内側→外側の順でバブルアップで処理する。(この場合button→div)
			//trueにしておくことで、外側→内側の順でカスケードダウン処理する。(この場合div→button)
			eventTarget.addEventListener(eventType, eventHandler, false);
			//eventTarget.addEventListener(eventType, eventHandler, true);

		//IE9より前対応  上のIE9ではDOMLevel2のイベント処理をサポートしてるらしい。IE9を動かせる環境がうちにはありません!環境ある人はデバックしてみてください。上のifを通るのだと思いますよ!
		} else if (eventTarget.attachEvent) {
			eventTyepe = "on" + eventType;
			eventTarget.attachEvent(eventType, eventHandler);

		//IE5以前対応 いわゆる「window.onload = 」的なDOMLevel0のイベントハンドラ設定
		} else {
			eventTarget["on" + eventType] = eventHandler;
		}
	}
</script>

↓HTML

<body>
	<div id="hoge">
		<input id="fuga" type="button" value="osu" />
	</div>
</body>

ここではwindow.onload = funcNameといった形で、イベントハンドラを設定していません。というのも、なんらかのJavaScriptライブラリをアプリケーションで使用おり、この方法でイベントハンドラを設定している場合、ライブラリの設定を上書きしてしまう可能性があるためです。よってなるべく、DOMLevel2のaddEventListenerを使いましょうということになるのですね。


window.onload = funcNameを使用する場合の代替案として、以下のような例が出ています。

function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			if (oldonload) {
				oldonload();
			}
			func();
		}
	}
}

これならば、もし使用するライブラリでwindow.onloadに関数が設定されていた場合でも『「元の関数を呼び出し、ついで引数で受け取る関数を呼ぶ」という関数』を設定できるわけですね!


あと忘れがちなのが、DOMLevel2のaddEventListener()の二番目の引数は「on」付かないからね。「onload」でなく「load」「onclick」でなく「click」という文字列ですからね!よろしくお願いします。


それにしても「いんたーねっとえくすぷろーらー」うっとうしいなー。
もうつかわないでください。お願いいたします。

自分のMBAのnode.js環境の整理メモ


使う前にいろいろ整理する。

覚えてませんが自分で導入したnvmが入ってるみたいなので、これ使って最新の安定版をインストールしてみる。

nvm install v6.0.19


そんで、/Users/teru/.nvm配下

terubookAir% pwd
/Users/teru/.nvm
terubookAir% ls -la
total 48
drwxr-xr-x  11 teru  staff   374  6 14 18:52 .
drwxr-xr-x+ 73 teru  staff  2482  6 15 22:18 ..
drwxr-xr-x  13 teru  staff   442  2  4 22:35 .git
-rw-r--r--   1 teru  staff    18  2  4 22:35 .gitignore
-rw-r--r--   1 teru  staff    13  2  4 22:35 .npmignore
-rw-r--r--   1 teru  staff  1594  2  4 22:35 README.markdown
drwxr-xr-x   2 teru  staff    68  2  4 22:50 alias
-rwxr-xr-x   1 teru  staff  9176  2  4 22:35 nvm.sh
drwxr-xr-x   6 teru  staff   204  6 14 09:16 src
drwxr-xr-x   6 teru  staff   204  2  4 22:45 v0.6.10
drwxr-xr-x   6 teru  staff   204  6 14 09:20 v0.6.19
terubookAir% 


そんで、コマンド叩いてみる。

terubookAir% node -v
v0.6.19
terubookAir% 

新しいのが使われてる。


ちなみにnpmもv0.6.19に同梱されてる最新が使われてる。
↓v0.6.10ディレクトリ配下ではnpmのバージョン1.1.0-3です。

terubookAir% pwd
/Users/teru/.nvm/v0.6.10/bin
terubookAir% ls -la
total 13912
drwxr-xr-x  6 teru  staff      204  2 18 21:06 .
drwxr-xr-x  6 teru  staff      204  2  4 22:45 ..
lrwxr-xr-x  1 teru  staff       39  2 18 21:06 express -> ../lib/node_modules/express/bin/express
-rwxr-xr-x  1 teru  staff  7109448  2  4 22:45 node
-rwxr-xr-x  1 teru  staff      355  2  3 09:56 node-waf
lrwxr-xr-x  1 teru  staff       38  2  4 23:42 npm -> ../lib/node_modules/npm/bin/npm-cli.js
terubookAir% ./npm -v
1.1.0-3


↓v0.6.19ディレクトリ配下ではnpmのバージョン1.1.24です。

terubookAir% pwd
/Users/teru/.nvm/v0.6.19/bin
terubookAir% ls -la
total 13728
drwxr-xr-x  6 teru  staff      204  6 14 20:45 .
drwxr-xr-x  6 teru  staff      204  6 14 09:20 ..
lrwxr-xr-x  1 teru  staff       39  6 14 20:45 express -> ../lib/node_modules/express/bin/express
-rwxr-xr-x  1 teru  staff  7013360  6 14 09:20 node
-rwxr-xr-x  1 teru  staff      355  6  6 09:46 node-waf
lrwxr-xr-x  1 teru  staff       38  6 14 09:20 npm -> ../lib/node_modules/npm/bin/npm-cli.js
terubookAir% ./npm -v
1.1.24


npmはもともとはnode本体とは別のツールだったようですが、最近のバージョンでは標準でnodeとともにインストールされるそうです。このnpmを使っていろいろなライブラリをインストールできる。なにがインストールされているかは以下のコマンドで確認できる。

terubookAir% npm list -g
/Users/teru/.nvm/v0.6.19/lib
├─┬ express@2.5.9 
│ ├─┬ connect@1.8.7 
│ │ └── formidable@1.0.11 
│ ├── mime@1.2.4 
│ ├── mkdirp@0.3.0 
│ └── qs@0.4.2 
└─┬ npm@1.1.24 
  ├── abbrev@1.0.3 
  ├── archy@0.0.2 
  ├── block-stream@0.0.5 
  ├── chownr@0.0.1 
  ├── fstream@0.1.18 
  ├─┬ fstream-npm@0.1.0 
  │ └── fstream-ignore@0.0.5 
  ├── graceful-fs@1.1.8 
  ├── inherits@1.0.0 
  ├── ini@1.0.2 
  ├── lru-cache@1.0.5 
  ├── minimatch@0.2.2 
  ├── mkdirp@0.3.2 
  ├─┬ node-gyp@0.4.5 
  │ ├── ansi@0.0.4 
  │ └── glob@3.1.9 
  ├── node-uuid@1.3.3 
  ├── nopt@1.0.10 
  ├── proto-list@1.0.0 
  ├── read@0.0.2 
  ├── request@2.9.153 
  ├── rimraf@2.0.1 
  ├── semver@1.0.14 
  ├── slide@1.1.3 
  ├── tar@0.1.13 
  ├── uid-number@0.0.3 
  └── which@1.0.5 

express2.5.9とnpm1.1.24がインストールされているようです。expressはv0.6.19を入れた後にnpmでグローバルインストールしたのです。「-g」はグローバルインストールされているものを表示すんですね。


インストール時

npm install [-g] パッケージ名

に-gをつけることでグローバルインストールされます。-g付けないとコマンドを実行したカレントディレクトリにインストールするようです。基本的に-gつけておくことにする。npm listも「-g」付けない場合はカレントのインストール状況を表示するようです。

terubookAir% pwd
/Users/teru
terubookAir% npm list
/Users/teru
└── (empty)

どうせ色々忘れるから、メモった。