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

gotin blog

Whatever gotin wanna write

JavaScriptの基本的なことっぽいけど今日初めて気づいたことメモ

function Animal(){}
Animal.prototype = {
  bark:function(){return "wooo";}
};

function Human(){}
Human.prototype = new Animal;

var gotin = new Human();
console.log(gotin.bark()); // "wooo"

Human.prototype.bark = function(){
  return Animal.prototype.bark() + "ahhh";
};

console.log(gotin.bark()); // "woooahhh"

これをついうっかり↓こうすると動かない。

function Animal(){}
Animal.prototype = {
  bark:function(){return "wooo";}
};

function Human(){}
Human.prototype = Animal.prototype; // ←ここ。気持ちは分かる気がしません?

var gotin = new Human();
console.log(gotin.bark()); // "wooo"

Human.prototype.bark = function(){
  return Animal.prototype.bark() + "ahhh";
};

console.log(gotin.bark()); // too much recursion!

後者だとHuman.prototypeがAnimal.prototypeそのものをさしてるので、
Human.prototype.barkはAnimal.prototype.barkと同一のものをさすことになるわけで
ゆえに再起呼び出しになってしまうわけですね。
前者だとHuman.prototypeがnew Animalで作ったオブジェクトをさしてるので、
そいつにbarkプロパティを新たに定義することになるだけなので問題ナシなわけです。


それともうひとつ、配列の途中にインサートとかしたいのにそういう関数ないなぁ、なんて思ってたんですが、spliceでできるのでした。

var array = [1,2,3];
array.splice(1,0,"a"); 
console.log(array); // [1,"a",2,3]

//やりたければ
Array.prototype.insert = function(i){
  var args = [i,0];
  var tmp = Array.prototype.slice.apply(arguments);
  tmp.shift();
  Array.prototype.push.apply(args, tmp);
  this.splice.apply(this, args);
  return this;
};

console.log(array.insert(0, "b")); // ["b",1,"a",2,3]
console.log(array.insert(2, "c", "d", "e")); // ["b",1,"c","d","e","a",2,3]

常識レベルなんだと思うけど、今頃知ったのでメモ。

あと昨日あたりに気づいたことをもう一度書いておく。

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

for(var i=0,l=array.length;i<l;i++){
  var e = array[i];
  func[i] = function(){return e;};
}

console.log(func[0]()); // 3 あれ1じゃないの?

クロージャ使うぞーと思ってると↑こういう間違えをおかしやすい(僕は)。

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

for(var i=0,l=array.length;i<l;i++){
  var e = array[i];
  with({e:e}){
   func[i] = function(){return e;};
  }
}

console.log(func[0]()); // 1 お、やった☆

function内に定義されていない名前があるとその外側を見に行くんだけど、
上の場合だとfunc[0]()の実行時はeの値は3になっちゃってて、
下の場合だとwithの効用でeの値を1に束縛したままにできてて、見事1だと思って処理してくれる。

ってことはjavascriptの処理系はfunc[0]にひもづけてwithの()の値を保持したままにしている、ってことになるのかな。
with内で関数定義をする、ということを大量にやるとメモリをばかすか食ってしまうってことになる?

このへんの動作はもう一度勉強し直しておいた方がいいかも。