월별 글 목록: 2015년 6월월
replace()
string.replace(searchValue, replaceValue)
var result ="mother_in_low".replace("_", "-"); result // "mother-in_low"
“mother-in_low” 처럼 실망스런 결과가 나온다.
searchValue 가 정규표현식이고 g 플래그가 설정된 경우라면 일치하는 모든 부분이 교체 됩니다.
var result ="mother_in_low".replace(/_/g, "-"); result // "mother-in-low"
this, call(), apply()
객체에 메소드를 부여하는 방법중 하나는 다음 코드처럼 함수 값을 객체에 첨가하는것이다
var rabbit = {}; // rabbit객체 생성 //speak메소드 부여 rabbit.speak = function(line) { console.log("토끼가말합니다: '", line, "'"); } rabbit.speak("저는 살아 있어요."); // 토끼가말합니다 : ' 저는 살아 있어요. '
this
그런데 토끼 여러마리여서 서로 다른 말을 해야할때 객체안에 메소드인(rabbit.speak();) speak() 안에 this는 해당 객체를 가르킨다.
function speak(line) { console.log(this.adjective, "토끼가 말합니다:'",line,"'"); } var whiteRabbit = {adjective: "흰색", speak: speak}; var fatRabbit = {adjective: "살찐", speak: speak}; whiteRabbit.speak("하얀토끼가 좋으세요?"); // 흰색 토끼가 말합니다:' 하얀토끼가 좋으세요? ' fatRabbit.speak("당근먹고싶다"); //살찐 토끼가 말합니다:' 당근먹고싶다 '
call(), apply()
이번엔 반대로 call 과 apply을 이용해 함수에서 객체를 불러보자.
speak.call(fatRabbit,"꺼억~"); //살찐 토끼가 말합니다:' 꺼억~ ' speak.apply(fatRabbit,["냠냠"]); // 배열타입으로 인자를 넘김 //살찐 토끼가 말합니다:' 냠냠 '
주의할 점은 apply는 배열 ([]) 타입으로 인자를 넘겨야한다는 것이다. 기능은 같다.
function run(from, to) { console.log(this.adjective + "토끼가" , from + "에서" , to + "로 달려갑니다."); } var ary =["찬장","냉장고","집","학교"]; run.apply(fatRabbit, ary); //살찐 토끼가 찬장에서 냉장고로 달려갑니다. run.call(whiteRabbit, ary[2],ary[3]); //흰색 토끼가 집에서 학교로 달려갑니다.
재귀함수, arguments.callee
함수안에서 자신을 다시 부를 수 있다.
흔히 재귀함수라고 하는것인데.
factorial(팩토리얼) 알고리즘을 예로 들어 설명한다.
‘팩토리얼 5’의 결과값은 120이다.
5 x 4 x 3 x 2 x 1 = 120
수식은 자신’5’부터 ‘1’까지 1씩 줄여가며 곱하는 것이다
이제 이것을 함수 이름으로 선언하면
function factorial (x) { if (x <= 1) return 1; return x * factorial(x - 1); }
함수 리터럴로 선언하면
var factorial = function(x) { if (x <= 1) return 1; return x * factorial(x - 1); }
그런데 만약 함수리터럴에서 다른이름으로 할당한다면 어떻게 될까 ?
factorial(5); // 120 기존함수 var fact = factorial; // 새 변수에 기존함수 할당 factorial = null; // 기존 함수 제거 fact(5); // error!!
fact 함수안에서 자신이 아닌 factorial을 부르고 있기때문에 자신을 찾을 수가 없다.
함수의 이름을 사용하지 말고 arguments.callee 를 사용해 자신을 불러보자.
var factorial = function(x) { if (x <= 1) return 1; return x * arguments.callee(x - 1); // 자기자신을 부름 }
이렇게 되면 같은 과정을 거쳐 할당을 해도 작동을 한다.
factorial(5); // 120 기존함수 var fact = factorial; // 새 변수에 기존함수 할당 factorial = null; // 기존 함수 제거 fact(5); // 120 정상작동
for…in 문 사용시 주의할 점
getElementsByTagName 으로 특정Tag를 선택한후 for/in 문으로 인덱스를 뿌렸을때 이상한 것을 발견했다.
<h1>보라돌이</h1> <h1>뚜비</h1> <h1>나나</h1> <h1>뽀</h1>
var tagH1 = document.getElementsByTagName("h1"); for(var i in tagH1){ console.log(i); // 0,1,2,3,length,item,namedItem }
0,1,2,3 뿐만 아니라 length,item,namedItem 이란 요소가 따라왔다.
다시
document.getElementsByTagName("h1")[0] // <h1>보라돌이</h1> document.getElementsByTagName("h1")[1] // <h1>뚜비</h1> document.getElementsByTagName("h1")[2] // <h1>나나</h1> document.getElementsByTagName("h1")[3] // <h1>뽀</h1> document.getElementsByTagName("h1")[4] // undefined
배열로 접근한다고 잡히지도 않는다.
getElementsByTagName 는 배열이 아니라 nodelist이다.
더군다나 for in 문은 배열의 인덱스를 출력하는것이라기보다 오브젝트의 property를 뱉어낸다.
배열도 오브젝트이다. 인덱스를 뿌려줄수있으나 nodelist라던가 특정 object의 경우 프로퍼티까지 다 나온다.
반대로 배열에서
var a = [ , , 3];
의 경우 일반 for문을 돌리면
for(var i=0; i < a.length ; i++) console.log(a[i]); // undefined, undefined, 3
이렇게 나오지만 for/in문을 쓰면
for(var i in a) console.log(i); // 3
이렇게 존재하는 요소만 출력한다.
indexOf(), match()
indexOf()
일반적인 용도는 스트링에서 원하는 캐릭터의 인덱스값 추출이다.
var str = "산토끼 토끼야 어디를 가느냐 깡총깡총 뛰면서 어디를 가느냐"; str.indexOf("냐"); // 14 (인덱스는 0부터 시작하고 스페이스도 센다.)
분명 저 동요 마지막에도 “냐”가 있지만 처음 “냐”의 인덱스를 반환했다.
한 스트링에 여러개의 같은 캐릭터는 분명 존재한다. 이때는 어떤것을 추출하는지 모른다.
이럴대 시작 점을 지정해준다. 좀전에 14번째에 “냐”가 하나 있었으므로 그 다음으로 지정한다.
str.indexOf("냐",14); // 14 (x) str.indexOf("냐",15); // 31 (o)
저말은 두번째 “냐”는 첫번째 인덱스에 +1을 한 만큼 부터 찾을 수 있다.
str.indexOf("냐",str.indexOf("냐")+1); // 31
이 str에는 “냐”가 두개뿐인데 이 범위를 넘어서 호출하면 어떻게 될까?
str.indexOf("냐",32); // -1
-1을 반환한다.
이 조건을 이용해 해당 캐릭터가 몇개있는지 세어볼 수 있다.
var char = "냐"; var idx = -1; var sum = 0; do { idx = str.indexOf(char,idx+1); if(idx != -1) sum++; } while (idx != -1); console.log("\""+char+"\"가 "+sum+"개 있습니다."); // "냐"가 2개 있습니다.
참고) lastIndexOf() – 뒤에서부터 검색한다.
match(regexp)
물론 이와같이 특정 문자를 문자열에서 알아보는데는 match()함수를 쓰면 간단하다. (정규표현식을 사용한다)
str.match(/냐/gi); // ["냐"],["냐"] str.match(/냐/gi).length; // 2
flag
- g : 완전일치(발생할 모든 pattern에 대한 전역 검색)
- i : 대/소문자 무시
- gi : 대/소문자 무시하고 완전 일치
생략할 경우 기본값은 g
클로저(Closure), filter()
function makeAdder(amount) { return function (number) { return number + amount; }; } var addTwo = makeAdder(2); addTwo(3); // 5
클로저를 설명하는 예문이다.
저 예문에서 같은 결과를 갖는 호출은 이러하다
makeAdder(2)(3); // 5
이것을 어떻게 설명해야할까. 이러한 것을 ‘상향 펀아그 문제(upward Funarg problem)’ 라고 한다고 책은 설명한다.
클로저 개념의 로컬변수를 참조하고 있는 함수 내의 함수이다.
일반적인 프로그램에서 함수가 리턴하면 그안에있는 local 변수는 소멸되나 클로저함수로부터 리턴된 익명함수의 경우 그 로컬변수가 유지된다 는 것이다.
function createFunction() { var local = 100; return function () {return local; }; }
createFunction()(); // 100
filter()
필터를 사용해보자.
먼저 1~10까지의 배열을 만들고
var arr = [1,2,3,4,5,6,7,8,9,10];
그중에 특정요소를 필터링해보자. 예) 3의 배수
arr.filter(function (n) { return n % 3 == 0 }) // [3,6,9]
n에 arr의 값들이 대입되어 3의 배수만 리턴된다.
이제 이것을 응용해 ‘2의 배수‘, ‘3의 배수’를 만드는 클로저를 만들어보자.
var arr = [1,2,3,4,5,6,7,8,9,10]; // 배수필터를 만드는 제너레이터 var generateFilter = function(x){ return function(n) { return n % x == 0 }; } var filter2x = generateFilter(2); // 2의 배수 필터 var filter3x = generateFilter(3); // 3의 배수 필터 arr.filter(filter2x); // [2,4,6,8,10] arr.filter(filter3x); // [3,6,9]
마트 유정란 집에서 부화시키기
2015년 5월 16일 토요일 저녁(0~1일차)
TV에서 스타킹을 보는데 닭이 하나 나와서 재주를 부린다.
놀라운건 이 닭이 마트에서 파는 유정란을 부화한것이라고..

어렸을때 학교앞에서 병아리를 많이 사서 닭으로 길렀던 기억이 나서..흥분
정말 되는지 테스트해보고도 싶고..
원래 부화기를 DIY해서 만들려면 전구 혹은 히터 그리고 박스나 온도조절기등 어느정도 준비를 해야하는데 마음이 급해서 마침 몇 주 전에 산 요구르트 제조기가 생각났다.
수은온도계와 롯데슈퍼에서 산 유정란 (사진을 못찍었다.)함께 사서 집에 있던 요구르트 제조기에서 부화를 시도하기로 작정
(당일날 찍은사진은 아니지지만)요구르트 제조기가 공간이 좁아서 한알만 시도해야하는 상황..
유정란 10개중 맘에드는 하나만 골랐다.(유정란은 5월 14자 포장된걸 잘 골라 샀다. 너무 오래된건 부화률이 떨어진다고 하여)
제조기는 일정온도를 유지하는 단순한 기계이다. 하지만 40도는 도달하는듯하다.
인터넷에 찾아본 바 부화 적정온도는 37.5 ~ 37.7도
요구르트 제조기 밑쪽이 좀 뜨거운듯 하여 아래 박스로 구조물을 조금 만든뒤 위로 띄워서
못쓰는 수면양말속에 달걀을 넣었다.
수은 온도계가 크기땜에 들어갈 곳이 없어서 ..ㅜ.ㅜ 그냥 방에 온도재는용도로 쓰고
온도를 제대로 재지 못해 난감해 하다 결국 온습도계를 인터넷으로 주문했다.
이 모델은 외부 온도를 같이 잴수 있는 센서와 선이 있는모델이다.
나와같은 상황에선 잘산거같다. 선만 부화기 요구르트 제조기안에 넣으면되니까..
너무 꽉 닫으면 환기가 안되기땜에 항상 살짝씩은 열어두었다.
참고로
요구르트 제조기는 1.5만원.
유정란 10개 4000원
온습도계 1만원 총 3만원이 들었다. (나머지 유정란은 먹었다~~ㅠㅠ)
5월 22일 금요일 (6~7일차)
일주일 정도 지난뒤 Candling(검란 : 불빛에 비춰서 알을 관찰하는것)을 해보았다.
와!! 달걀 껍질이 좀 고르지않고 어두워서인지 잘 보이진 않았는데…사진을찍고보니
선명하진 않지만 실핏줄(vessel)이 보인다.(스마트폰 Flash light로)
진행되고 있구나… 안도의 한숨~ ^__^;
온도는 정확히 맞추기가 힘들었다.
어쩔때 보면 38도를 넘기도 하고 39도가 되어있기도 해서 열어서 식혀주기도하고..
온도계 센서를 알 위쪽에대면 35도대고 아래쪽에 대면 38도가 넘고 그래서…
그냥 감으로 이정도면 되지않을까 의구심가득…진행한 면이 있다.
온도는 28도정도인가 최소 발육이 진행되는 온도만 넘으면 발육이 멈추지는 않는것같다.
하지만 고온에 오래 노출되는것도 위험한.. 그래서 높은온도를 더 무서워했다.
적정온도인 37.7보다 약간높으면 부화가 하루정도 빠르고 약간 적으면 부화가 하루이틀 느리다고 한다.
중간중간 인터넷 검색을 하면서 많은 자료를 보았다.
전란(알을 굴려서 온도나 혈액순환을 돕는거..)을 해주어야 하는데
기계가 없으니 수동으로 해야했다. 거의 매일 해주긴했다.
중간중간 검란을 더 해봤는데 심장이 뛰는건지 발을 움직이는건지 검은게 꿀렁 꿀렁 하는것이
자라고 있는듯 했다. 사실 부화가 첨이고 일반적인 부화방식이 아니라서..
이게 썩고있는건지 의심이 갈때가 한두번이 아니었다는..
6월 4일 목요일 (18~19일차)
Air Sac(사진에 보이는 공기층)이 크게 보인다.
18일이 되면 저 에어섹이 커지고 안이 검어진다고
보통 21일이 되면 나온다는데 6월 6일 토요일 전후로 나오지 않을까 기대를 하고있다.
6월 6일 토요일 (21~22일차)
5월 16일에 입란했지만 거의 10시넘은 밤에 한지라 사실상 오늘이 21일차라고 봐도 무방..하지만 아직 파각소식이 없다…머가 잘못된걸까? 온도가 낮아서일 가능성이 있다.. 그리고 전란을 18일째부터는 멈추라고 하는데 이건 기계를 써서 굴릴때 파각하는 애들이 있늘까봐 그런걸로 아는데…. 아닐지도… 어쨋든 난 몇번 좀 뒹굴뒹굴 해줬다..
오늘중에 나왔으면 좋으련만…23일째 나오는 애들도 있다고 하니 기다려봐야겠다..
현재시간 15:30분 – 병아리 소리가 들림 !!!!!!!
껍질 두두리는 소리 (볼륨업)..”똑 똑 똑 똑”…
“삐약 삐약” 소리
6월 7일 일요일 (22~23일차)
새벽2시 드디어 첫 파각 육안으로 확인!!
귀로는 몇시간동안 이어폰마이크를 껍질에 닿게해서 계속 듣고있었다. 녹음도하고..
너무 여리게 톡톡 쪼아서 그렇게 밖에 들리지 않았다.
구두발자국소리 처럼 일정한 비트.. 96비트 Moderato로
“콕-콕-콕-콕….”
거의 쉬질 않더란…어떻게 이럴 수 있는지 신기하다.
그래서 이게 심장박동인가?? 계속 의심했으나 중간중간 쉬는것을 봐서
부리로 쪼는 소리라고 생각…
2초에 3번정도? 계산해본결과
20초에 30번..1분엔 거의 90번
한시간엔 약 500번..10시간엔 5000번..
어제 오후 3시부터라고 쳐도 10시간은 족히 넘었다.
그러니 저게 적어도 오천번은 쪼은거란거다..
난 그것도 모르고 열었다 놨다 뒤집었다..ㅡ.,ㅜ
부화직전에 전란을 하지말란 이유를 이제 알거같다.
아주 작은 힘으로 수없이 한곳을 쪼아서 겨우겨우 파각을 하는것인데..말이다!
나오는 동안 털이 말라 껍질에붙지 않도록 습도조절을 잘해야겠다.
이제 자고 일어나면 ..짜잔?~
오전 10시
죽었다..
내가 너무 마지막에 스트레스를 준것같다.. 부리 위치가 아래쪽인거같은데
굳이 원인을 찾자면 마르지 않게한다고 습도를 너무 높인거같기도하고
알을 깨는데 기력을 다 소진한것같기도 하도..거의 다 깼는데..
결국 죽었다.
RIP..
isNaN(“123”) 은 왜 false를 리턴하는가?
isNaN()
NaN은 ‘Not a Number’란 표현이고 직역하면 ‘숫자가 아니다’가 된다.
isNaN(value)은 value가 ‘숫자가 아닌가? ‘라는 질문에
true 혹은 false를 리턴한다.
간단히 “apple”이란 문자열을 넣어보자. isNaN(“apple”) 하면 “apple”이 String 이기 때문에 NaN(숫자가 아님)이므로 true를 리턴한다.
그런데 123은 어떨까? 숫자니까 false가 나온다..
여기까진 상상한데로다.
하지만 “123”은 어떻게 될까?
isNaN("123") // false
음…..문자열인데 false 다. 타입을 확인해도
typeof "123" // "String"
“123”은 스트링이 맞다. 숫자가 아니니까 true를 리턴해야 하는게 아닌가?
isNaN("apple") // true isNaN("123") // false <= ? isNaN(123) // false isNaN("apple123") // true isNaN("123apple") // true
따옴표를 한 “123” 은 문자열 type이지만 (숫자로만 이루어져 있을 경우) isNaN(“123”)은 먼저 내부적으로 숫자 123으로 변경되기 때문에 false를 리턴한다.
prompt 로 입력받은 숫자
prompt로 숫자를 입력받아서 계산을 수행할 수 있을까?
원하는 정사각형의 가로나 세로 길이를 입력받아 면적을 제는 간단한 프로그램을 만들어보자
var theNumber = prompt("숫자를 입력하세요",""); // 입력 5 console.log(theNumber*theNumber); // 25
잉? 잘 되네..?? ㅋ
자 여기서 확인해 볼 필요가 있다.
theNumber*theNumber; 25 typeof theNumber; "string"
그렇다 String이다.
그럼 결과값으로 출력한 25는 어떤 type일까?
var total = theNumber*theNumber; typeof total; "number"
숫자..라네요.
결국 곱하기 연산을 하면서 두개의 문자를 숫자로 인식해주었다.
그럼 “5”*”5″ 는 어떻게 될까?
"5"*"5" 25
역시나 숫자로 계산된 25이다.
즉 String 5와 String 5를 곱셈 (*) 연산하면 Number 25가 된다.
책에서는 prompt입력값이 String이란것을 알려주기 위해 다음과 같은처리를 해주었지만
//(42p 예제) var theNumber = Number(prompt("숫자를 입력하세요","")); alert("입력한 숫자의 제곱은 " + (theNumber * theNumber) + "입니다.");
테스트 결과 수식에서 내부적으로 Number 형식으로 바뀌는 관계로 저자가 든 예가 무색하게 되었다.
어쨌든 저자가 말하려고 했던 의도는 prompt 입력한 숫자의 결과가 String 타입이란 것과 이 문자열 값을 Number(String)를통해 숫자로 강제 변환할 수 있다는 점인듯 하다.
아마도 저 예제를 바로잡으려면 theNumber+theNumber 로 해야했을것이다.
(그래야 Number()를 사용하지 않으면 원치않는 답인 “55” 가 나온다는것을 보여줄 수 있었을 것이다.)
최종결론:
prompt로 숫자(5) 입력받으면 // “5” : String 타입
"5" * "5"// 25: Number "5" * 5 // 25 : Number 5 * 5 // 25 : Number "5" + "5"// "55": String "5" + 5 // "55": String 5 + 5 // 10 : Number 5 * "five" // NaN 5 + "five" // "5five" : String
- 피연산자 중 하나가 NaN이면 결과도 NaN 입니다.
- 피연산자 중 하나가 숫자가 아니라면 이면에서 Number()를 적용하고 기타 규칙을 적용해 숫자로 변환합니다.
니콜라스 자카스 의 프론트엔드 개발자를 위한 자바스크립트 프로그래밍(76- 77p)