JavaScript基本

★Enterキーでの送信を禁止

<form method="POST" onsubmit="return false;">

...

<input name="button1" value="登録" onclick="this.form.submit();" />

...

</form>

★RepaintとReflow

・Repaint

外観が変化する。DOMに影響なし。例:outline,visibility,background color

・Reflow

DOMに影響あり。Repaintを起こす。性能低下の原因の一つ。

発生タイミング

・DOM要素を追加・変更・削除:Reflow + Repaint

・DOM要素の字体・色を変更:Repaint

・ブラウザをResize・scroll:Reflow

・offsetLeft、offsetTop、offsetHeight、offsetWidthを取得:Reflow

Reflowを避ける方法

1.要素をdocumentから削除し、修正後に元の位置に復元する

2.要素のdisplayをnoneに設定し、修正後に元の設定値に復元する

list.style.display = "none";

list.appendChild(document.createTextNode('xxx'));

list.appendChild(document.createElement('yyy'));

list.appendChild(document.createTextNode('zzz'));

list.style.display = "";

3.複数の要素を追加する場合にDocumentFragmentを利用

var fragment = document.createDocumentFragment();

fragment.appendChild(document.createTextNode('xxx'));

fragment.appendChild(document.createElement('yyy'));

fragment.appendChild(document.createTextNode('zzz'));

document.body.appendChild(fragment);

4.スタイルについて

・cssTextを利用

element.style.width = "80px";

element.style.height = "90px";

element.style.border = "solid 1px";

element.style.cssText = "width:80px;height:90px;border:solid 1px;";

或いは

.newStyle {

width:80px;

height:90px;

border:solid 1px;

}

element.className = "newStyle";

・属性をキャッシュ

var left = elem.offsetLeft;

・要素のpositionをabsolute/fixedに設定

・tableを使う際に、table-layoutをauto/fixedに設定

★thisについて

動的言語の場合:ランタイムで決まる

サンプル1

window.name = "from window";

var showName = function(){

return this.name;

};

alert(showName()); //from window

var obj1 = {};

obj1.name = "from obj1";

alert(showName.apply(obj1)); //from obj1

alert(showName.call(obj1)); //from obj1

var obj2 = {

"name" : "from obj2"

};

obj2.showName = showName;

alert(obj2.showName()); //from obj2

サンプル2

var obj = {

doSomething: function () {

console.log(this); // obj

(function () {

console.log(this); // window

}());

}

};

obj.doSomething();

this.title = "xxx"; // DOM

$(this).attr('title','xxx'); // jQuery

class Foo {

constructor(name) {

this.name = name;

//this.greet = this.greet.bind(this); // 対策2

}

greet() {

console.log('hello ', this.name);

}

someThingAsync() {

return Promise.resolve();

}

asyncGreet() {

this.someThingAsync().then(this.greet); // TypeError: this is undefined

//this.someThingAsync().then(this.greet.bind(this)); // 対策1

//this.someThingAsync().then(() =>{ // 対策3

// this.greet();

//});

}

}

new Foo('dog').asyncGreet();

★初期化

var a = new Object(); a.name = "aaa"; ×

var a = { name: "aaa" };

var b = new Boolean(true); ×

var b = true;

var c = new Array("aaa", "bbb"); ×

var c = ["aaa", "bbb"];

var d = new String("aaa"); ×

var d = "aaa";

var e = new Function("in", "alert(in);"); ×

var e = function(in) { alert(in); };

連想配列(オブジェクト)の初期化

var obj = { name: 'andy' };

var obj = { 'name': 'andy' };

var obj = {};

obj.name = 'andy';

var obj = {};

obj['name'] = 'andy';

var obj = new Object();

obj.name = 'andy';

//走査

for (var property in obj) {

console.log(property + ":" + obj[property]);

if(obj.hasOwnProperty(property) {

...

}

}

配列の初期化

var array = ['aaa', 'bbb'];

var array = new Array('aaa', 'bbb');

var array = new Array(2); //長さ:2

var array = Array('aaa', 'bbb');

var array = [];

array[0] = 'aaa';

array[1] = 'bbb';

var array = [];

array['0'] = 'aaa'

array['1'] = 'bbb'

var array = { 0: 'aaa', 1: 'bbb', length: 2 };

array.__proto__ = Array.prototype;

//走査

for(var key in array){

console.log( key + ":" + array[key]);

}

★配列の操作

var arr1 = [1,2,3];

var arr2 = arr1;

arr1 =[];// arr2は[1, 2, 3]

arr1.length =0;// arr1とarr2は[]

Math.max.apply(Math, [1,2,3]); //3

Math.min.apply(Math, [1,2,3]); //1

var arr = [];

arr.push(0); // 配列の最後に追加

arr.push(1, 2); // 長さを返す

while (arr.length !== 0) {

// 配列の最後を取り出す

console.log(arr.pop()); // 2, 1, 0

}

Array.prototype.push.apply(arr1, arr2); // マージ

var arr = [];

arr.unshift(0); // 配列の最初に追加

arr.unshift(1, 2); // 長さを返す

while (arr.length !== 0) {

// 配列の最初を取り出す

console.log(arr.shift()); // 2, 1, 0

}

var arr = [1, 2, 3, 4, 5];

delete arr[1]; // [1, undefined, 3, 4, 5]

arr.splice(1, 1); // [1, 3, 4, 5]

// 挿入

var a = [1,2,3,7,8,9];

var b = [4,5,6];

var insertIndex = 3;

a.splice.apply(a, Array.concat(insertIndex, 0, b));

var arr = [1, 2, 3];

arr.reverse(); // [3, 2, 1],元arr:[3, 2, 1]

var arr = [1, 2, 3];

arr.concat(); // [1, 2, 3],元arr:[1, 2, 3] Cloneに相当

arr.concat(4, 5); // [1, 2, 3, 4, 5],元arr:[1, 2, 3]

arr.concat(4, [5, 6]); // [1, 2, 3, 4, 5, 6]

arr.concat(4, [5, 6], 7); // [1, 2, 3, 4, 5, 6, 7]

// クリア

書き方1

var array = [1, 2, 3, 4];

array.splice(0, array.length);

書き方2

var array = [1, 2, 3, 4];

array.length = 0;

※Javaの配列のlengthはReadOnly

書き方3(効率よく)

var array = [1, 2, 3, 4];

array = [];

// Clone

var array = [1, 2, 3, 4];

var clone = array.slice(0); // array.slice()

array = [4, 3, 2, 1];

或いは

var clone = [].slice.call(array);

※cloneが変わらない

[1, 2, 3].toString(); // '1, 2, 3'

[1, 2, [3, 4]].toString(); // '1, 2, 3, 4'

// map

function action(input) {

return input.replace(/o/g, 'e');

}

var words = ["foot", "goose", "moose"];

var result = words.map(action); //["feet", "geese", "meese"]

var numbers = [1, 4, 9];

var result = numbers.map(Math.sqrt); //[1, 2, 3]

var arr = [1,2,3,4,5];

//filter

var even = function(item){

if(typeof item !== "number"){

return false;

}

return !(item & 1);

};

var filter1 = arr.filter(even);

var filter2 = window.myFilter(arr, even);

//map

var add = function(item){

return item + 10;

};

var map1 = arr.map(add);

var map2 = window.myMap(arr, add);

//reduce

var plus = function(a, b){

return a + b;

};

var reduce1 = arr.reduce(plus, 0);

var reduce2 = window.myReduce(arr, plus, 10);

function myFilter(arr, callback){

var out = [];

for(var i = 0; i < arr.length; i++){

if(callback(arr[i])){

out.push(arr[i]);

}

}

return out;

}

function myMap(arr, callback){

var len = arr && arr.length || 0;

var out = new Array(len);

for(var i = 0; i < len; i++){

out[i] = callback(arr[i]);

}

return out;

}

function myReduce(arr, callback, num){

var i, out;

if(num){

out = num;

i = 0;

}else{

out = arr[0];

i = 1;

}

for(; i < arr.length; i++){

out = callback(arr[i], out);

}

return out;

}

〇Array.forEach()とjQueryの$().each()

var arr = [2, 4, 6, 8];

arr.forEach( function(i){alert(i);} );

$(arr).each( function(){alert(this);} );

或いは

$(arr).each( function(index, item){alert(item);} );

〇Array.filter()とjQueryの$.grep()

var arr = [2, 4, 6, 8];

var newArr = arr.filter(function(item){return item > 4;}); //6,8

var newArr = $.grep(arr, function(item, index){

return item > 4;

});

〇Array.map()とjQueryの$.map()

var arr = [2, 4, 6, 8];

var newArr = arr.map(function(item){return item + 1;}); //3,5,7,9

var newArr = $.map(arr, function(item, index){return item + 1;});

〇Array.every()とArray.some() 条件に満たす

var arr = [2, 4, 6, 8, 10];

var result = arr.every( function(item){return item > 1} ); //true

var result = arr.every( function(item){return item > 2} ); //false

var result = arr.some( function(item){return item > 9;} ); //true

var result = arr.some( function(item){return item > 10;} ); //false

〇Array.sort()

var arr = [6, 10, 2, 8, 4];

arr.sort(); ×

arr.sort( function(a, b){return a - b} ); ○

[

{ name: "Andy", age: 31 },

{ name: "Tom", age: 25 },

{ name: "John", age: 27 }

].sort(function(obj1, obj2) {

return obj1.age - obj2.age; // 昇順

});

★slice vs splice

Array.slice(begin[, end])

Array.splice(index, howMany, [element1][, ..., elementN])

var arr = [1, 2, 3];

arr.slice(0, 2); // [1, 2],元arr:[1, 2, 3]

arr.slice(-2, -1); // [2] 負の数:最後から数える

arr.slice(1); // [2, 3]

var color = ['red', 'blue', 'yellow', 'black'];

// 追加

result = color.splice(2, 0, "xxx");

console.log(color); // red,blue,xxx,yellow,black

console.log(result); // 空

// 削除

result = color.splice(3, 1);

console.log(color); // red,blue,xxx,black

console.log(result); // yellow

// 置換

result = color.splice(2, 1, "yyy");

console.log(color); // red,blue,yyy,black

console.log(result); // xxx

// 置換(複数)

result = color.splice(0, 2, "xxx", "yyy", "zzz");

console.log(color); // xxx,yyy,zzz,yyy,black

console.log(result); // red,blue

var arr = [1, 2, 3];

arr.splice(1); // [2, 3],元arr:[1]

var arr = [1, 2, 3];

arr.splice(1, 0, ['hello', 'world']); // [],元arr: [1, ['hello', 'world'], 2, 3]

var arr = Array.prototype.slice.call(document.querySelectorAll("div"));

var arr = Array.prototype.slice.call(arguments);

var arr = [].slice.call(arguments);

DOM属性

DOMメソッド(更新系)

DOMメソッド(参照系)

★文字列について

var str = 'aaa' + 'bbb' + 'ccc'; ×

var str = ['aaa', 'bbb', 'ccc'].join(); //aaa,bbb,ccc

var str = ['aaa', 'bbb', 'ccc'].join(''); //aaabbbccc

var list = '<ul><li>' + arr.join('</li><li>') + '</li></ul>';

var array = str.split(',');

var startTime = new Date();

var str = '';

for(var i = 0; i< 10; i++){

str += i + 'xxx';

}

alert(new Date() - startTime);

改善

var startTime = new Date();

var arr = [];

for(var i = 0; i< 10; i++){

arr.push(i, 'xxx'); 速い

//arr[arr.length] = i + 'xxx'; もっと速い

}

var str = arr.join('');

alert(new Date() - startTime);

また

var min = Math.min(a, b);

var min = a < b ? a : b; 速い

"bob".replace("b", "x"); // "xob"

"bob".replace(/b/g, "x"); // "xox"

"Bob".replace(/b/gi, "x"); // "xox" 大・小文字を無視

"bob".replace(new RegExp("b", "g"), "x"); // "xox"

※メソッドを呼ぶことより単純な計算の方が速い

ちなみに、文字列について

//var s = '0123'; × 無駄なオブジェクトが生成された

var s = new String('0123');

var len = s.length;

for( var i = 0; i < len; i++ ) {

s.charAt(i);

}

※文字列のメソッドとプロパティは文字列オブジェクトに定義されるため

★日付

var now = Date.now() || function(){

return + new Date();

};

new Date()

new Date(milliseconds)

new Date("2013/08/19")

new Date(year, month, day, hours, minutes, seconds, ms) ※monthは0から

new Date(Date.parse("8/2/2012")); // 〇 M/d/yyyy

new Date(Date.parse("2012-08-02")); // 〇 yyyy-MM-dd或いはyyyy/MM/dd

new Date(Date.parse("2012-8-2")); // ×

★変数の変換

alert(0xFF); 255 hex

alert(020); 16 octal

alert(1e3); 1000 Math.pow(10,3)と同じ

(1000).toExponential() 1e3

(3.1415).toFixed(3) 3.142 四捨五入

var a = 20;

var b = "10";

alert(a + b); //2010

alert(a + (+b)); //30

alert(a + +b); //30

alert(a ++b); //Compile error

var myVar = "3.14";

var str = "" + myVar; // to string

alert(typeof(str)); // string

var int = ~~myVar; // to integer

alert(typeof(int)); // number

var float = 1 * myVar; // to float

alert(typeof(float)); // number

var bool = myVar; // to boolean ""以外の文字列、0以外の数字の場合にtrue

alert(typeof(bool)); // boolean

var bool = Boolean(myVar); // to boolean

var array = [myVar]; // to array

alert(typeof(array)); // object

var date = new Date(myVar); // to Date

alert(typeof(date)); //object

var regExp = new RegExp(myVar); // to RegExp

alert(typeof(regExp)); //object

'10.5678'| 0 //10

-2.3456 | 0 // -2

var d = + new Date(); //Date⇒数値

(12).toString(16); // C int to hex

(12).toString(8); // 14 int to octal

parseInt(string, radix)

parseInt("FF",16) // 255 hex to int

parseInt("020",8) // 16 octal to int

parseInt("020", 10); // 20

parseInt("10"); //10

parseInt("19",10); //19 (10+9)

parseInt("11",2); //3 (2+1)

parseInt("17",8); //15 (8+7)

parseInt("1f",16); //31 (16+15)

typeof new Number(123); // object

typeof Number(123); // number

typeof 123; // number

typeof NaN; // number

"aaa" instanceof String //false

new String("aaa") instanceof String //true

["aaa", "bbb"] instanceof Array //true

new Array("aaa", "bbb") instanceof Array //true

typeof [] === 'object' // true

// 配列の判断

Array.isArray(var)

★グローバル変数

var g_var1 = 1;

g_var2 = 2; //属性と見られる

(function(){

g_var3 = 3; //属性と見られる

})();

delete g_var1; //NG

delete g_var2; //OK

delete g_var3; //OK

console.log( typeof g_var1 ); //number

console.log( typeof g_var2 ); //undefined

console.log( typeof g_var3 ); //undefined

※delete:属性はOK、変数はNG

★スコープ

JavaScriptではブロックスコープがない、関数スコープがある

for(var i=0; i<10; i++) {

console.log(i);

}

console.log(i); // 10

(function (){

for(var i=0; i<10; i++) {

console.log(i);

}

}());

console.log(i); // undefined

(function (){

console.log(x + 2); // Error(x is not defined)

x = 0; //global変数

}());

var x = 1;

(function (){

console.log(x + 2); // 2

x = 0;

}());

var x = 1;

(function (){

//書き方1

console.log(x + 2); //NaN

var x = 0;

//書き方2

var x;

console.log(x + 2); //NaN

x = 0;

}());

★画面遷移

window.location.href = "xxx.html?backurl=" + window.location.href;

window.history.back(-1);

window.navigate("xxx.html");

self.location = 'xxx.html';

top.location = 'xxx.html';

★NaN、null、undefined

var num = NaN;

num === NaN //false

isNaN(num) //true

var a;

a === null //false

a === undefined //true

チェック

if(a !== null && a !== undefined) {

...

}

[1,2,3] === [1,2,3] // false

{a: 1} === {a: 1} // false

{} === {} // false

★argumentsについて

argumentsは配列に似ているオブジェクトである

(function(a){

alert(arguments[0]); //1

a = 2;

alert(arguments[0]); //2

}(1));

//argumentsオブジェクト ⇒ 配列

console.log(arguments instanceof Array); // false

var argsArray = Array.prototype.slice.call(arguments);

console.log(argsArray instanceof Array); // true

function args(){

return [].slice.call(arguments);

}

var array = args(1, 2, 3);

//arguments変更

function add(){

//arguments.push('abc'); ×

Array.prototype.push.call(arguments, 'abc');

return arguments;

}

console.log( add()[0] ); //abc

★applyとcall

callは可変引数で、第2引数以降に並べる

applyは固定引数で、第2引数に配列を渡す

var obj = { name:'Andy' };

obj.func = function (arg1, arg2) { console.log(arg1 + arg2 + this.name); };

obj.func('aaa', 'bbb');

var obj = { name:'Andy' };

var func = function (arg1, arg2) { console.log(arg1 + arg2 + this.name); };

func.apply(obj, ['aaa', 'bbb']);

或いは

func.call(obj, 'aaa', 'bbb');

function log() {

console.log(this + '|' + arguments.length);

}

log('abc'); // [object Window]|1

log.call('abc', [1, 2, 3]); // abc|1

log.apply('abc', [1, 2, 3]); // abc|3

var func = function(name){

...

};

func.apply(null, ['Andy']);

var obj = {

func: function(name){

...

}

};

func.apply(obj, ['Andy']);

★new

JavaScriptのnew処理とJava・C#のnew処理は違う

var obj = new person();

下記と同様

var obj ={};

person.apply(obj);

obj.__proto__ = person.prototype;

★instanceメソッドとstaticメソッド

function class() { };

class.staticMethod = function() { ... };

class.prototype.instanceMethod = function() { ... };

//staticメソッドの呼び出し

class.staticMethod();

//instanceメソッドの呼び出し

var instance = new class();

instance.instanceMethod();

★evalとnew Function

var str = "var a = 1; console.log(a);";

eval(str); //1

str = "var b = 2; console.log(b);";

new Function(str)(); //2

str = "var c = 3; console.log(c);";

(function(){

eval(str);

})(); //3

console.log(typeof a); //number

console.log(typeof b); //undefined

console.log(typeof c); //undefined

(function(){

var local = 1;

eval("console.log(typeof local); local = 2;"); //number

console.log(local); //2

})();

(function(){

var local = 1;

new Function("console.log(typeof local); local = 2;")(); //undefined

console.log(local); //1

})();

★javascript:void(expression)

void:expressionを計算し、戻り値を返さず

<a href="javascript:void(0)"></a>

<a href="javascript:void(document.form.submit())">送信</a>

★jQuery vs. Native JavaScript

Selectors

Event

$('.el').on('event',

function() {

...

});

[].forEach.call(document.querySelectorAll('.el'),

function (el) {

el.addEventListener('event', function() {

...

}, false);

});

DOM

★functionについて

定義方法1 function func(){...} 解析時、コードの最初に移動させる

定義方法2 var func = function(){...}

function method(){

console.log(aaa); //function

console.log(bbb); //undefinded

function aaa(){

...

}

var bbb = function(){

...

};

}

functionもオブジェクトである

書き方1

function add() {

console.log(++add.count);

}

add.count = 0;

add(); //1

add(); //2

書き方2

function add() {

if(!arguments.callee.count){

arguments.callee.count = 0;

}

console.log(++arguments.callee.count);

}

add(); //1

add(); //2

※arguments.calleeはfunctionのこと、つまりadd()

new漏れを防ぐ

function Person(name) {

if (!(this instanceof arguments.callee)) {

return new arguments.callee(name);

}

this.name = name;

}

var p1 = new Person('Andy');

var p2 = Person('Andy');

console.log(p1.name);

console.log(p2.name);

new vs func

function Person(name, age){

this.name = name;

this.age = age;

//if(this.constructor === arguments.callee){

//if(this instanceof arguments.callee){

if(this instanceof Person){

console.log('new');

}else{

console.log('func');

}

}

var p = new Person('Andy', 30); // new

Person(); // func

Curry化

function add(x, y){

if(typeof y === 'undefined'){

return function(y){

return x + y;

};

}

return x + y;

}

console.log( add(1) ); //function

console.log( add(1, 2) ); //3

console.log( add(1)(2) ); //3

自動実行

//書き方1

(function(){

...

}());

(function(){

...

})();

(function(data){

...

}('dummy'));

//書き方2

({

name:'Andy',

getName: function(){

return this.name;

},

init: function(){

console.log( this.getName() );

}

}).init();

CSS

var el = document.querySelector(".content");

$(el).addClass("someClass");

$(el).removeClass("someClass");

$(el).toggleClass("someClass");

if($(el).hasClass("someClass"))

$(el).css({

background: "#FF0000",

"box-shadow": "1px 1px 5px 5px red",

width: "100px",

height: "100px",

display: "block"

});

var el = document.querySelector(".content");

el.classList.add("someClass");

el.classList.remove("someClass");

el.classList.toggle("someClass");

if(el.classList.contains("someClass"))

el.style.background = "#FF0000";

el.style.width = "100px";

el.style.height = "100px";

el.style.display = "block";

el.style.boxShadow = "1px 1px 5px 5px red";

Ajax

$.get('url', function (data) {

...

});

$.post('url', {data: data}, function (data) {

...

});

var xhr = new XMLHttpRequest();

xhr.open('GET', url);

xhr.onreadystatechange = function (data) {

...

}

xhr.send();

var xhr = new XMLHttpRequest()

xhr.open('POST', url);

xhr.onreadystatechange = function (data) {

...

}

xhr.send({data: data});

★クラスの対象作成

function Car(color, doors){

this._color = color;

this._doors = doors;

this.drivers = new Array("Mike","John");

}

Car.prototype.showColor = function() {

alert(this._color);

};

var car1 = new Car("red", 5);

var car2 = new Car("blue", 3);

car1.drivers.push("Andy");

alert(car1.drivers); //"Mike","John","Andy"

alert(car2.drivers); //"Mike","John"

★メソッドの呼び方(10種)

console.log(1);

(_ => console.log(2))();

eval('console.log(3);');

console.log.call(null, 4);

console.log.apply(null, [5]);

new Function('console.log(6)')();

Reflect.apply(console.log, null, [7])

Reflect.construct(function(){console.log(8)}, []);

Function.prototype.apply.call(console.log, null, [9]);

Function.prototype.call.call(console.log, null, 10);

new (require('vm').Script)('console.log(11)').runInThisContext();

★bind用法

thisの問題を解決

var andy = new Person('Andy');

setTimeout(function() {

andy.sayHello(); // ×

}, 3000)

setTimeout(andy.sayHello.bind(andy), 3000);

関数の引数を束縛

var mul = function(a, b) {...}

mul(2, 3);

// 一つ目の関数を束縛

var mul2 = mul.bind(null, 2);

mul2(4);

// 二つ目の関数も束縛

var mul2x5 = mul2.bind(null, 5);

mul2x5();