2016년 12월 29일 목요일

RxJS - Purity(순수성)

Reactive extension JS (RxJS)


Purity(순수성)

RxJS는 순수함수로 이루어져있다는 뜻이다. 순수함수란 함수형 프로그래밍에서 쓰이는 단어이다. 사람들마다 그리고 언어들마다 순수함수에 대한 정의가 약간씩 다른 것 같긴 하지만.. 내가 아는 순수함수의 정의는 아래와 같다.

  • 같은 입력에 항상 같은 출력을 반환한다.
  • 사이드 이펙트가 없다.
  • 외부 상태와 무관하다.
순수함수는 해당 함수보다 상위의 스콥에서 정의된 함수를 참조하지 않는다. 오로지 인자로 인해 제어된다. 같은 값을 출력하기때문에 랜덤(Math.random)이나 날짜(new Date)등을 사용하지 않는다. 따라서 오류가 발생할 가능성이 적다. RxJS는 이 부분을 장점으로 내세우고 있다.

아래 예제를 보면...

const observable = Rx.Observable.from([1,2,3,4])
 .map(x => x*x)
 .scan((a,b) => a+b, 0);
observable.subscribe(x => console.log(x)); //1, 5, 14, 50

RxJS는 위처럼 체이닝으로 method들을 이어 나간다. 그리고 다음 method들의 함수 내부는 이전함수로 부터 return받은 인자로만 이루어 진다. 물론 global 영역에 변수를 지정하고 가져오는게 불가능 한건 아니지만, 되도록 순수하게 함수를 사용하는 것을 권장한다. 아무래도 순수함수가 가진 안정성과 속도의 장점을 가져가려는 것이 아닐까 생각한다.

Flow(흐름)

RxJS에는 관찰자를 통해 이벤트가 흐르는 방식을 제어하는 데 도움이되는 다양한 연산자(operator)가 있다. 위에서 등장한 map, scan 등이 그것이다. 하나 하나의 흐름을 operator들로 전달하는 방식으로 동작하는 것이다.

Values(값)

RxJS의 흐름이 진행되는 과정에서 인자로 값들을 넘긴다. RxJS는 operator들을 통해 이 값들을 원하는 값을 도출한다.

2016년 12월 23일 금요일

Reactive extension JS (RxJS) 시작!

Reactive extension JS (RxJS)

RxJS에 대해 학습한 내용을 정리해서 포스팅 해보고자 한다.
여기 글을 RxJS공식 사이트(http://reactivex.io/rxjs)를 근간으로 하고 있다.

RxJS 공식사이트에서는 RxJS를 한문장으로 정의하고 있다..

Think of RxJS as Lodash for events.

이벤트의 로다시 같다는 것이다.. 로다시가 무엇인가. 함수형 프로그래밍을 위한 라이브러리가 아닌가...? 대신 로다시가 절차지향적 방식이라면 RxJS는 이벤트 기반의 비동시 방식이라는 차이가 있는 것으로 보인다.

RxJS는 다음과 같은 키워드로 정의되고 있다.
  • Observable: 미래의 값(value)나 이벤트의 호출 가능한 수집의 개념을 나타냄.
  • Observer: Observable에 의해 전달 된 값을 처리하는 콜백 콜렉션.
  • Subscription: Observable의 실행을 나타냄. 주로 실행 취소에 유용함.
  • Operators: map, filter, concat, flatMap 등과 같은 method를 사용하여 컬렉션을 다루는 함수 프로그래밍 스타일을 가능하게하는 순수(pure) 함수.
  • Subject: EventEmitter와 동일하며 여러 Observers에 값 또는 이벤트를 멀티 캐스팅함.
  • Schedulers: 동시 처리를 제어하는 중앙 집중식 디스패처로서 계산이 언제 발생하는지 조정할 수 있다. setTimeout or requestAnimationFrame or others.

RxJS가 힘든 이유는 2가지 인것 같다. 
  • 이벤트 기반의 비동기 처리 프로그래밍 방식이 개념적으로 익숙하지 않다.
  • 익혀야할 용어나 method들이 많다. 
앞으로 하나씩 하나씩 익혀보자.

초반 개념을 잡는데 네이버 김훈민 님의 강의가 많은 도움이 됐다. 아래는 관련 블로그나 강의 영상의 링크다. 내용이 많이 겹치지만 일부 다른 부분들도 있어서 되도록 알고있는 모든 링크를 첨부한다.

블로그: http://huns.me/development/2051
나프타 컨퍼런스 영상: https://www.youtube.com/watch?v=3FKlYO4okts
웹 프론트엔드 개발자의 얕고 넓은 Rx 이야기: http://www.slideshare.net/jeokrang/rx-70197043

2016년 12월 16일 금요일

React Life Cycle

React Life Cycle..

자꾸 잊어버려서 기록해 둔다...



컴포넌트를 생성 할 때는 constructor -> componentWillMount -> render -> componentDidMount.

컴포넌트를 제거 할 때는 componentWillUnmount 메소드만 실행.

컴포넌트의 prop이 변경될 때엔 componentWillReceiveProps -> shouldComponentUpdate -> componentWillUpdate-> render -> componentDidUpdate.

컴포넌트의 state가 변경될 떄엔 props 를 받았을 때 와 비슷하지만 shouldComponentUpdate 부터 시작.

2016년 12월 15일 목요일

함수형프로그래밍

함수형 프로그래밍에 익숙해지기고 functional한 사고를 키우기위해 연습한 내용들을 기록한 포스트입니다.

두개의 배열을 하나의 배열로 합쳐보자.

  1. 각 배열의 요소는 객체이다.
  2. 각 배열의 객체의 "id" 프로퍼티가 일치하는 객체끼리 합친다.
  3. 남자이고 나이가 30이상이면 target을 true로, 아니면 false로 

Trial 1. underscore의 map, extend, find 함수 활용

const arr1 = [
  {name: 'owen', gender: 'male', age: 36, id: 11},
  {name: 'bbo', gender: 'female', age: 34, id: 12},
  {name: 'woo', gender: 'male', age: 20, id: 13}
];

const arr2 = [
  {id: 10, phone: '010-1111-1111'},
  {id: 11, phone: '010-2222-2222'},
  {id: 12, phone: '010-3333-3333'},
  {id: 13, phone: '010-4444-4444'}
];

const arr3 = _.map(arr1, function(item){
  return _.extend(item, _.find(arr2, function(i){
    return item.id === i.id;
  }), {target: item.age >= 30 && item.gender === 'male'})
});

console.log(arr3);
/*[
{'name':'owen','gender':'male','age':36,'id':11,'phone':'010-2222-2222','target':true},
{'name':'bbo','gender':'female','age':34,'id':12,'phone':'010-3333-3333','target':false},
{'name':'woo','gender':'male','age':20,'id':13,'phone':'010-4444-4444','target':false}
]*/

[Check]

  • 위에서 find는 findWhere로 대체할 수 있다. 퍼포먼스 차이는 크게 없어 보인다.

2016년 9월 1일 목요일

ECMA5 javascript method : map

오늘은 ECMA5 javascript 메소드 중에 하나인 map에 대해서 포스팅 하고자 한다.

map메소드는 Array객체의 프로토타입 프로퍼티에 존재하는 메소드다. (즉 모든 배열에서 사용 가능하다.) 이 메소드는 배열의 각 요소들에 대해서 인자로 넘기는 함수를 실행시키고, 해당 배열을 리턴으로 반환한다.

array.map(function(currentValue,index,arr), thisValue)

위에서 볼 수 있듯이 콜백함수에 첫번째 값으로 요소의 값을, 두번째로 인덱스, 세번째로 배열 자체를 넘긴다. 아래는 제곱근을 구하는 예제이다.

var numbers = [4, 9, 16, 25];
var sq = numbers.map(function(val, idx){
  return Math.sqrt(val);
});
console.log(sq);//[2, 3, 4, 5]

map은 원래의 배열에 영향을 미치지는 않는다. 따라서 다시 numbers를 콘솔로 찍으면 원래 값([4, 9, 16, 25])을 반환한다.

ECMA3에서 map메소드는 없지만, 다음과 같이 스크립트를 활용해 만들 수 있다.

if(!Array.prototype.map){
  Array.prototype.map = function(a, f){
    var results = [];
    for (var i = 0, len = a.length; i < len; i++) {
      if(i in a) results[i] = f.call(null, a[i], i, a);
    }
    return results;
  };
}


2016년 8월 28일 일요일

ECMA5 javascript method : reduce

자바스크립트를 쓰다보면 ECMA5에서 표준화된 메소드들을 접하게 된다. 이를 사용하면 ECMA3보다 훨신 효율적인 소스를 제작 할 수 있음에도 불구하고, 아직 우리나라는 익스8버젼을 고려해야하기 때문에 포기하는 경우가 많았다.

하지만 가까운 미래에 우리나라도 ECMA5기반으로 만들어진 사이트 들이 늘어날 것이고, 또 node.js의 경우에는 서버단의 언어이고 V8엔진 기반으로 해석되기 때문에 익스에 대한 고민없이 ECMA5 또는 6기반으로 소스를 설계할 수 있다.

그래서 ECMA5기반의 메소드들을 익숙하게 사용할 수 있도록 익혀 보고자 한다.
그리고 첫번째로 reduce 메소드를 꼽았다.

reduce는 배열의 메소드다. 배열의 각 요소들을 순회하는데, 순회할 때 마다 리턴값을 만들어서 다음 순회에 넘겨준다. 다음은 w3c의 reduce 메소드에 대한 설명이다.
http://www.w3schools.com/jsref/jsref_reduce.asp

reduce 매소드의 기본형태는 아래와 같다.

array.reduce(function(리턴값,현재요소,현재요소의 index,배열),초기값)

여기서 리턴값이란 1번째 순회에서는 초기값을, 이후 순회에서는 그전 순회에서 받은 리턴값을 나타낸다. 아래는 reduce의 가장기본적인 예제이다.

var arr = [1, 3, 2, 5, 4];
var sum = arr.reduce(function(total, val){return total + val;}, 0);
console.log(sum);//15

위 예제에서는 리턴값에 현재요소를 더한값을 다음 순회로 리턴시킨다. 결국 모든 요소를 더한값을 반환한다.

다음은 배열안의 수 중 가장 큰 수를 추출하는 스크립트이다.

var arr = [1, 6, 4, 100, 5, 2];
var max = arr.reduce(function(a, b){return a > b ? a : b;});
console.log(max);//100

위 예제는 리턴된 값과 현재요소를 비교해서 큰 값을 리턴시킨다. 물론 배열에서 가장 큰 값을 구하는 방법은 apply함수를 이용하는 방법이 더 효율적이긴 하다.
> Math.max.apply(Math, arr);

이제 좀 더 복잡한 예제를 보자. 아래는 배열중에 연속된 수들이 있으면 해당 수들을 배열로 묶어서 반환시키는 함수이다.

var arr = [1, 6, 4, 100, 5, 2, 101, 103];
arr.sort(function(a, b) {return a - b}); //sort 메소드로 오름차순 정렬.
var cnt = 0,tArr = [],len;
var max = arr.reduce(function(a, b) {
    if (a + 1 === b) { //현재요소가 리턴값과 이어지는 정수면...
        if (!cnt) { //연속된 수의 첫 시작이면
            var tArr2 = [];
            tArr2.push(a, b);
            len = tArr.push(tArr2);
            cnt = 1;
        } else { //연속된 수가 계속 이어지고 있는 상태면..
            tArr[(len - 1)].push(b);
        }
    } else { //수가 이어지지 않으면..
        cnt = 0;
    }
    return b; //현재 요소를 반훤
});
console.log(tArr); //[[1, 2], [4, 5, 6], [100, 101]]

결론적으로 reduce는 어떤값을 리턴시키느냐에 따라 다양하게 확장해서 사용할 수 있다!

2016년 8월 22일 월요일

JSONP에 관하여...

jsonp라는 놈을 처음 접한건 instagram API에 대해서 스터디 하고 있었을 때였다. jquery의 ajax매소드($.ajax(인자))를 써서 api를 써보는데, datatype속성을 json으로 하면 브라우저가 크로스도메인 에러를 뿌린다.. 에러내용은 아래와 같다.

XMLHttpRequest cannot load http://받는주소. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://보낸주소' is therefore not allowed access.

즉, 도메인이 달라서 안된다는 것인데, 이것저것 찾아보다가 몇시간을 허비했다... 결국 찾은 해결책은 datatype속성을 jsonp로만 바꿔주면 되는 것이었다!

이는 교차출처(Cross-Origin) HTTP요청에 대한 정책때문이었다. ajax요청을 받는 서버의 헤더에 크로스도메인 요청을 승인(CORS)이 되어 있지 않으면 서로다른 도메인간에 ajax요청은 승인되지 않는다. 그리고 CORS가 되어 있더라도 ie8 같은 낮은버젼의 브라우저에서는 이를 지원하지 않는다. 그래서 나온 해결책이 jsonp다. 결국 jsonp는 우회해서 크로스도메인 요청을 할 수 있는 방식인 것이다.

jsonp가 생소할수 있지만, 사실 jsonp은 script태그를 생성하고 해당 url을 호출하는 방식이다. 우리가 아주 많이쓰고 있는 방식이다. 예를 들면 우리가 jquery js파일을 호출할때 아래와 같이 할 수 있다.

<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>

생각해보면 script태그로 호출하는 url주소는 도메인이 어디든지 영향을 받지 않는다. jsonp는 이 방법을 활용해서 해당 파일을 호출한다. 응답하는 파일의 내용에는 함수를 호출하는 자바스크립트 문장이 있으며, 인자로 json형태의 객체를 넘긴다. 예를 들면 다음과 같다.

callback([1, 2, {"name" : "owen"}])//여기서 함수명(callback)은 개발자가 정하기 나름이다.

그리고 이 함수에 대한 선언을 미리 해놓아서, jsonp으로 파일이 응답할때 해당 함수가 실행되도록 하는 것이다. 예를 들어.

function callback(res){console.log(res.name)}
//jsonp로 파일을 가져오면 위 'callback'함수가 실행된다.

Jquery의 ajax를 활용해서 jsonp를 사용하는건, 아래와 같이 쓴다.

$.ajax({
    dataType: "jsonp",
    url: "http://textsite.com/jsonp",
    type: "GET",
    data: {'s':s},
    success: function(data){
    }
});

아주쉽다. json을 jsonp로만 바꾸어주면 된다..
여기서 주의할 점은 위에서도 봤지만, 요청 받는 서버(http://textsite.com/jsonp)에서 자바스크립트 함수 호출하는 문장 형태로 값을 넘겨줄 준비가 되어 있어야 한다. 즉 아무 사이트나 json을 jsonp로 바꾼다고 값을 넘겨받을 수 있는건 아니라는 것이다. 다행히 요새 대부분의 sns, 포털사이트의 api들이 jsonp방식을 지원하고 있어서 큰 진행함에 있어서 큰 문제는 없다.

보다 정확히 jsonp를 이해하기 위해서 Jquery를 쓰지 말고 직접 만들어보자.

function getJSONP(url){
 if(url.indexOf("?") === -1) url +="?callback=cbFn"; //url에 파라미터가 있으면 '&' 없으면 '?'
 else url += "&callback=cbFn";
 var script = document.createElement('script');//스크립트 엘리먼트를 생성한다.
 window.cbFn = function(res){//호출될 함수를 미리 선언한다.
  try{
   console.log(res);
  }
  finally{
   delete window.cbFn;//임시로 추가한 함수므로 함수 실행이 끝나고 나서 지운다.
   script.parentNode.removeChild(script);//추가한 스크립트 테그도도 지운다.
  }
 }
 script.src = url;
 document.body.appendChild(script);//DOM에 script가 추가됨에 따라 파일 안의 함수(cnFn)가 호출된다.
}
getJSONP('jsonp.php');

그리고 호출되는 jsonp.php파일은 아래와 같이 작성하였다.

<?php echo $_GET['callback'];?>([
 [1,2,{"name" : "owen"}]
]);

결국 jsonp.php파일안의 cbFn([[1,2,{"name" : "owen"}]]) 를 통해 전역함수인 cbFn함수가 호출되면서 콘솔 함수(console.log(res);)가 실행되는 것이다~

2016년 8월 21일 일요일

Javascript의 valueOf, toString

Javascript의 Object객체의 내장 매쏘드 중,  자바스크립트 내부적으로는 많이 사용되지만, 사용자가 작성할때는 거의 사용되지 않는 것들이 있다. 그중에 대표적인 것이 toString, valueOf 이다.

내부적으로 toString이 사용되는 대표적인 예는 DOM프로퍼티인 innerHTML을 사용할 때이다.
var obj = {name : 'owen'};
document.getElementById('demo').innerHTML = obj;

이렇게 하면 자바스크립트는 demo아이디를 가진 엘리먼트에 "[object Object]"를 출력한다. 즉, 사용자는 사용하지 않았지만, 자바스크립트 내부적으로 toString 매쏘드를 사용해서 객체의 내용을 출력한 것이다.

valueOf가 가장 흔하게 사용되는 경우는 객체를 비교하는 연산자에서이다. ">, <, >=, <="등의 연산자가 객체간에 실행될때 자바스크립트 내부적으로는 valueOf 매쏘드를 호출한다.

이런 특성을 이용하면 흥미로운 예제를 만들 수 있다.
toString, valueOf은 결국 프로토타입으로부터 상속받은 매쏘드이기 때문에, 사용자가 같은 이름의 매쏘드를 선언함으로써 위 두 매쏘드를 원하는 형태로 바꿀수 있다는 것이다.

다음 예제를 보면... (자바스크립트의 프로토타입에 대해 잘 모르시는 분은 이해하기 어려울 수 있습니다.)

var students = [
  {name : 'owen', idx : 5},
  {name : 'jason', idx : 3},
  {name : 'justin', idx : 4}
];

var proto = {
  toString : function(){return this.name;},
  valueOf : function(){return this.idx}
};
var students2 = [];
for(var i = 0 ; i < students.length ; i++){
  var F = function(){};
  F.prototype = proto;
  students2[i] = new F();
  students2[i].name = students[i].name;
  students2[i].idx = students[i].idx;
}
console.log(students2[0] < students2[1]); //false
document.getElementById('demo').innerHTML = students2[0]; //owen 출력


  1. 이는 학교에서 학생들의 번호와 이름을 객체로 만드는 상황을 가정한 것이다. 첫번째로 학생들을 배열로 만들고 이름과 번호(idx)를 선언한다. 
  2. proto라는 객체를 만들어서 toString과 valueOf매쏘드를 새롭게 정의한다. 즉 toString은 학생의 이름을, valueOf는 학생의 번호를 가져오는 매쏘드가 된 것이다.
  3. for문을 실행시켜 새로운 배열을 생성하면서 각각의 요소에 toString과 valueOf를 프로토타입 상속을 통해 선언하고, 각이름과 idx값을 넣어준다.
  4. 이제 각요소의 idx프로퍼티나 name프로퍼티를 찾아가지 않아도 값비교나 이름 출력이 가능해 졌다.
이 예제는 크게 실용적으로 보이지는 않지만, 이런 자바스크립트 특성을 잘 활용하면 보다 효율적인 코드를 작성할 수 있을것 같다.^^

2016년 8월 18일 목요일

다른 퍼블리셔들의 사용패턴 설문조사

다른 퍼블리셔들은 어떻게 하는지 궁금한 것을이 있었다.
예를들어 에디터는 뭐를 쓸까? css 스타일은 한줄에 쓰나 나눠서 쓰나? 등등..

그러던 와중 css사용 패턴에 대한 설문조사가 있는 글을 발견했다.

https://www.sitepoint.com/results-ultimate-css-survey/

모수가 3,500명 정도 되고, 외국사람들을 대상으로 조사한 설문이다 보니 꽤 글로벌하게 의미있는 결과가 아닐까 싶다.

재미있었던것 몇가지가 있는데..


  1. css스타일을 멀티라인이 아닌, 1개 라인에 쓰는 사람이 훨신 많다는 것.
  2. css스타일링을 모바일 페이지 먼저 하는 사람이 많다는것
    (이건 외국이니까 가능한 것 같다. 우리는 미디어 쿼리 따위는 무시하는 ie8의 눈치를 봐야 한다.)
  3. 얼마전까지 썼던 aptana 에디터는 순위 안에도 없다는것
  4. 부트스트랩 css를 사용하는 사람이 43%로 제일 많다는것.
    (프레임워크 사용 안하는 사람은 20%...)
  5. CSS preprocessor(SASS, LESS등)을 사용하는 사람이 73%라는것.

설문조사가 영어로 되어 있어서 완전히 이해하기는 어렵다. 시간날때마다 천천히 봐야 겠다..

2016년 8월 15일 월요일

Javascript 클로저

올해 초까지만 해도 Javascript를 사용하면서 '클로저'라는 개념을 잘 모르고 있었다. javascript를 제대로 익히고 싶다는 마음으로 시작한 공부에서 가장 큰 이득은 클로저를 어느정도는 이해 할 수 있게 된 것이라고 생각한다. 그만큼 중요하다.

사전적으로 클로저는 외부함수(포함하고 있는)의 변수에 접근할 수 있는 내부 함수를 말한다. 클로저라는게 사실 유효 범위를 뜻하는 것이라 사실 우리가 알게 모르게 쓰고 있다. 자바스크립트를 어느정도 하는 사람은 아래 예제가 어렵지는 않을 것이다.

var num = 1;
function init(){
  var num = 2;
  return num;
}
console.log(init())//2;

자바스크립트가 변수를 찾아 나갈때는 유효범위의 우선 순위대로 찾아 나간다. init함수에서 num이라는 변수를 찾을 때, 가장 가까이 변수가 선언된 곳은 var num=2이므로 해당 값을 반환한다.

비슷 하지만 다음 예제를 보자.

var num = 1;
function init(){
  var num = 2;
  function getNum(){
    return num;
  }
  return getNum;
}
console.log(init()())//2;

첫번째 예제와 거의 흡사하지만, 리턴을 변수가 아닌 함수로 넘겼다. 따라서 init()() 라는 조금 특이한 형태로 호출했다. init라는 함수를 호출해서 리턴받은 함수를 다시 호출한 것이다. 이 부분이 제일 중요한데, 왜냐하면 내부 함수(getNum)를 해당 내부함수의 외부함수(init)가 아닌 전역 영역에서 호출했다는 것이다. 또 호출된 내부 함수(getNum)의 유효범위가, 전역 영역에서 호출되었으메도 불구하고, 외부함수(init) 안의 변수에 접근해서 값을 가져왔다는 것이다.

외부함수(init)가 호출되고 함수의 해석이 끝날때, 리턴된 값이 함수로 남아 있어서 해당 함수에 접근할 수 있다면, 외부함수의 변수들은 사라지지 않고 남아있다고 한다. 그리고 자바스크립트의 유효범위는 함수가 호출될 때가 아닌, 정의될 때를 기준으로 작동된다고 한다.

이 개념을 잘 이해하고 있으면 다양한 방법으로 사용이 가능하다. 간단한 예제로, 숫자를 1씩 더하는 함수를 만들어 보자. 우리가 보통 사용하는 방법은 아래와 같다.

var num = 0;
function inc(){
 num++;
 return num;
}
console.log(inc());//1
console.log(inc());//2
console.log(inc());//3

함수안에 변수를 선언하면 함수가 실행될때 마다 변수가 초기화 되므로 전역 영역에 변수를 정의한다. 하지만 전역 영역에 변수를 정의하고 사용하는 것은 퍼포먼스를 고려할때 좋은 방법이 아니다.
이를 클로저를 사용하면 다음과 같이 바꿀수 있다.

function inc(){
 var cnt = 0;
 return function(){
  cnt++;
  return cnt;
 };
};
var incFn = inc();

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

실제로 사용해보니, 개인적으로는 엘리먼트 요소를 외부 함수에 미리 정의해두고, 내부함수에 접근해서 외부함수의 엘리먼트를 호출하는 형태를 많이 쓰게 되었다. 함수가 호출될때마다 엘리먼트를 찾지 않아도 되니 퍼포먼스 측면에서 효율적이었다.

2016년 8월 12일 금요일

프레임에 이미지 꽉 채우기 Part2(Javascript)

** 이 글은  프레임에 이미지 꽉 채우기 Part1(CSS)에 이어진 글입니다.

이번에는 자바스크립트를 이용한 방식이다.

Javascript로 꽉 채우기.

우선 소스...


imgAlign이라는 함수를 만들었다.

함수가 길고 복잡하니 함수에 대한 설명은 하지 않고 사용법에 대해서만 기록한다.

우선 css스타일이 있어야 한다.

img.h100p {
    height: 100% !important;
    width: auto !important;
    position: relative
}
img.w100p {
    width: 100% !important;
    height: auto !important;
    position: relative;
}

자바스크립트로 width와 height값을 처리하지 않고 클래스를 add, remove 해서 위치를 맞춘다. 그게더 속도가 빠르다고 해서 이렇게 한건데.. 실상은 잘 모르겠다.

함수 실행할때 인자는 여러 방법으로 넘길 수 있다. 인자로는 이미지를 싸고있는 박스를 css selector방식으로 넘긴다.

imgAlign('.imgBx'); //jquery로 씌워서 해당 element를 찾음
imgAlign(['.imgBx', '.imgBx2']); //배열을 돌면서 jquery로 씌워서 해당 element를 찾음
imgAlign($('.imgBx')); //이미 jquery로 싸여 있으므로 바로 element를 찾음
imgAlign('.imgBx', {resize : ture}); //리사이즈 될때마다 위치를 재 계산함.



프레임에 이미지 꽉 채우기 Part1(CSS)

코딩을 하다 보면 특정 프레임 안에 이미지를 꽉 채워야 할 때가 종종 있다.
여기서 꽉체운다는 것은, 프레임의 가로/세로 보다 이미지의 가로/세로가 크다면 세로가 100%로가 되고, 작다면 가로가 100%가 되는것을 의미한다.

이 것과 관련된 글을 찾아보니 css-tricks에 잘 정리가 되어 있는것을 발견했다.

https://css-tricks.com/perfect-full-page-background-image/

위 페이지에서 여러가지 방법을 제시하고 있는데 그 중 유용한 2가지 방법에 대해서 포스팅 하려고 한다.

CSS로 꽉 채우기.

이 방법은 완벽하진 않다. 하지만, javascript를 쓰지않고 구현할 수 있다는 점에서 매력적이다.

우선 링크...
See the Pen 이미지 꽉 채우기(css) by owen (@wooner) on CodePen.


여기서의 핵심 스타일 소스는 아래와 같다.

.gallery_list_artwork .img> a {
    display: block;
    position: absolute;
    top: -50%;
    left: -50%;
    width: 200%;
    height: 200%;
}
.gallery_list_artwork .img img {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    min-width: 50%;
    min-height: 50%;
    margin: auto;
}

프레임 영역 안의 프레임(위 에서 a태그)를 absolute로 띄우고 크기를 프레임에 200%로 넗힌다음 top, left를 50%씩 줘서 가운데로 위치하게 했다.
그 다음 이미지의 최소 길이와 최소 높이를 50%씩 줘서 안쪽 프레임 넓이의 반절로 길이를 조절하고, top, bottom, left, right를 0을 주고,  margin을 auto를 줘서 가운대로 위치 시켰다. 이렇게 하면 가로든, 세로든 프레임에 딱 맞도록 이미지가 위치하게 된다.
이 방법의 한계는 이미지의 원본 크기가 프레임의 크기보다 2배 이상 클때는 역시 이미지가 프레임을 넘어가게 된다.

더 큰 이미지에 맞추려면 프레임의 안쪽 프레임의 넓이를 더 넓히면 된다. 예를 들어..

.gallery_list_artwork .img> a {
    display: block;
    position: absolute;
    top: -25%;
    left: -25%;
    width: 400%;
    height: 400%;
}
.gallery_list_artwork .img img {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    min-width: 25%;
    min-height: 25%;
    margin: auto;
}

하지만 이미지가 얼마나 크게 될지 예측할 수 없는 경우도 있고, 저렇게 영역을 400%씩 넗히는 것도 뭔가 찜찜하다...

다음은 자바스크립트로 맞추는 방법을 게시하겠다.

객체와 배열 구분하기.

자바스크립트를 작성하다 보면, 객체와 배열을 구분해야할 때가 있다.
근데 타입을 조사하는 함수인 typeof 를 실행해 보면 객체와 배열 모두 'object'를 반환한다.

console.log(typeof {});//"object"
console.log(typeof []);//"object"

이때 사용하는 방법은, 자바스크립트 객체의 매쏘드인 toString을 활용하는 것이다.
일단 소스는 아래와 같다.

위의 예제에서 typeof 대신 toString을 실행해보면 아래와 같이 나온다.

console.log(Object.prototype.toString.call({}))//;"[object Object]"
console.log(Object.prototype.toString.call([]));//"[object Array]"

위 예제에서 특이한 것은 toString매쏘드를 해당 객체(또는 배열)에 직접 실행 한 것이 아니라 Object객체의 프로토타입 프로퍼티로 실행을 시키고 call이라는 재귀 함수를 통해 toString을 해당 객체(또는 배열)의 매쏘드화 시켰다는 것이다.

일반적으로 우리가 사용하는 방법인 '[].toString()'과 이 방법의 차이는 무엇인가..?(이 방법으로 하면 배열을 콤마(,)로 구분된 문자열을 반환한다)

'[].toString()'의 toString은 배열('[]')의 프로토타입인 Array 객체로 부터 상속받아 사용하는 매쏘드이고,
'Object.prototype.toString.call([])'의 toString은 배열('[]')에 Object의 매쏘드인 toString()을 직접 정의시킨 매쏘드 인 것이다.

즉 Array객체의 toString을 사용하면 우리가 원하는 객체 타입을 반환하는 것이 아니라 배열을 문자열로 반환시켜 버리므로, Object객체의 toString을 사용하도록 강제로 설정했다고 볼 수 있다.

자 그럼 이제 객체의 class를 구분하는 함수를 만들어 보면..

function getClassType(obj){
  return Object.prototype.toString.call(obj).slice(8,-1);
}

console.log(getClassType([]));//"Array"
console.log(getClassType({}));//"Object"
console.log(getClassType(1));//"Number"
console.log(getClassType(new Date()));//"Date"

이처럼 반환된 문자열을 slice 매쏘드를 통해 잘라내어 class를 구할 수 있다.^^

자바스크립트 프로토 타입의 프로퍼티 할당

지난번 게시물에서 자바스크립트의 객체에서 특정 프로퍼티를 찾을 때, 프로토 타입 체인의 순서에 의해서 값을 찾아 나간다는 것을 배웠습니다.

그런데 이 프로토 타입 체인이 값을 "찾을 때" 뿐 아니라 값을 "할당 할 때"도 동일하게 작동 하는 것을 확인했습니다.

아래 소스를 보면..
var Test = function(){}
Test.prototype = {
    a : {
        aa : '1'
    }
}
var TestA = new Test();
var TestB = new Test();
TestB.a.aa= '2';
console.log(TestA.a.aa); //2
console.log(TestB.a.aa); //2


위에서 신기한 것은, TestB 객체에 직접 프로퍼티 값을 할당했는데도, Test 함수의 프로토 타입의 값이 바뀌었다는 것입니다. (이 내용이 잘 이해 안되시면 프로토 타입 체인에 대해서 찾아 보시기 바랍니다.^^)

이유는 처음에도 말한것 처럼 자바스크립트의 객체는 값을 할당할 때도 프로토 타입 체인을 따라가기 때문입니다.

TestB.a.aa= '2'; 을 실행했을때, TestB에는 a라는 프로퍼티가 없기 때문에 'aa'라는 프로퍼티를 생성 할 수가 없습니다. 보통은 자바스크립트가 error를 뿌리면서 실행이 중지되죠.
하지만 이 경우에는 자바스크립트는 프로토타입에 a라는 프로퍼티가 존재합니다. 따라서 프로토타입 체인 순서에 의해 Test객체의 prototype 프로퍼티에 있는 a.aa에 값을 할당하게 됩니다.
Test객체의 prototype 값이 바뀌었으므로 이를 상속받는 TestA객체도 영향을 받은 것이지요.

자바스크립트는 참 유연한 언어라는걸 또한번 느낄수 있었네요.

2016년 6월 16일 목요일

웹폰트에 대한 고찰

우선 웹 폰트 사용방법.

여기만큼 잘 정리한 웹페이지는 없는것 같다.
http://www.beautifulcss.com/archives/431

한국같이 조합형으로 만들어지는 글자의 웹폰트는 디자인의 다양성이나 용량측면에서 갈길이 멀다.

그래도 다양한 방법으로 웹폰트의 용량으로 용량 부담에 대한 대안들이 나오고 있으니 언젠가는 해결책이 나올것으로 생각된다.





div 박스 세로길이를 가로길이에 비례하게 만들기

코딩을 하다보면..(특히 반응형) 특정 박스의 세로 길이를 가로길이에 비례하게 줄이고 싶을 때가 있다.

이런 경우는 대부분 박스 안에 이미지가 들어있을 경우가 많다. 

 여러 방법을 찾아봤지만 지금까지 발견한 가장 좋은 방법은 padding의 %를 이용하는 것이다.

아래 링크를 살펴보자.. 

여기서의 핵심은 아래 css에 있다. 
.lst_type_owen > ul > li .img{
    position: relative;
    height:0;
    padding-bottom:65%;
} 

기본적으로 padding의 %는 자기 자신의 부모 엘리먼트의 가로 길이를 기준으로 계산한다. 
즉 height를 0으로 주고, 부모 엘리먼트의 가로길이의 65%만큼을 padding-bottom으로 밀어서 가로길이에 비례하게 박스 크기를 변경시켜 주는 것이다. 

물론 그안에 엘리먼트는 absolute로 띄워야 한다는게 좀 찜찜할 수 있지만... 박스의 세로길이를 가로길이에 고정했다는 것 자체가, 내부 엘리먼트의 세로길이 따위 신경 안쓰겠다는 것이기 때문에.. 접근성 측면에서도 문제는 없어보인다.

객체 및 프로토타입 스터디정리

우리가 객체를 생성하는 방법을 크게 2가지로 배웠습니다.

1. 리터럴 방식

var o  = {x:1,y:2}


2.객체 생성자를 통한 방식

var o  = new Object();
o.x  = 1;
o.y  = 2;

모든 함수는 prototype이라는 프로퍼티를 가지고 있습니다. (함수도 객체이기 때문에 프로퍼티를 갖는게 가능합니다.)
이 prototype프로퍼티의 역할은, 이 함수를 통해 생성되는 객체에게 prototype프로퍼티의 값을 상속해주는 역할을 합니다.

객체를 생성하면 우리가 만든 객체는 Object라는 최상위 함수 객체의 prototype이라는 프로퍼티를 상속받게 됩니다. 
즉 우리가 위에서 생성한 'o'라는 객체는, Object라는 함수 객체가 가지고 있는 prototype 프로티의 값들들 상속받는 것입니다. Object​의 prototype 프로퍼티를 확인해보기 위해서는 콘솔을 찍어보면 되겠죠?
console.log(Object.prototype);

그러면 toString, valueOf등의 매쏘드 들이 보일겁니다. 즉 우리는 Object의 prototype로 부터 값들을 상속받아서 o.toString()같이 매쏘드들을 사용할 수 있는 것입니다.

한단계 더 들어가 보겠습니다.

var d  = new Date();
console.log(d.toString());

위 소스에서 우리는 Date라는 함수를 통해 d라는 객체를 만들었습니다.
그런데 d객체에서도 toString이라는 함수를 쓸수 있습니다. 이상합니다. 분명 toString은 Object라는 객체의 prototype에 있는 매쏘드라고 했는데... 여긴 Object가 등장 안하잖아요!

천천히 살펴보면 그 이유를 알 수 있습니다.
먼저 d객체는 Date라는 함수로 부터 생성되었습니다. 이에 따라 Date의 prototype 프로퍼티가 가지고 있는 요소들(getHours등..)을 사용할 수 있습니다.
그리고 요 Date라는 함수또한 객체이기 때문에 생성될 당시 Object객체로 부터 값들을 상속받습니다.

즉 모든 객체는 최상위 객체인 Object로 부터 상속을 받습니다. 따라서 배열, 함수등에도 toString이라는 매쏘드를 사용할 수 있는 것입니다.

그리고 d는 Date를 상속받고, Date는 Object를 상속받고... 이러한 관계를 프로토타입 체인이라고 합니다. 모든 자바스크립트의 객체는 이러한 방식으로 매쏘드를 상속받아 사용하는 것입니다. 스터디때도 봤지만 대표적인것이 dom의 프로토타입 체인입니다.
예 : document.getElementsByTagName('body').toString()​  같은 매쏘드를 쓸 수 있죵. 

-------------------
직접 프로토타입을 활용한 상속을 해봅시다.

var A  = function(){this.x  = 1;}
var obj  = new A();
A.prototype.y  = 2;
A.prototype.plus  = function(){
    return this.x  + this.y
}
console.log(obj.plus());

위에서 obj는 함수 A를 통해 만든 객체 입니다. 따라서 A의 프로토타입에 있는 항목들을 상속받습니다.
A,함수에서의 this는 함수를 호출한 놈. 즉 위에서는 obj를 가리킵니다.

헌데 5번라인까지는 A의 prototype이 없기 때문에 상속받을 것이 없습니다. 그 이후 7,8번 열에서 프로토타입이 정의 됩니다. 따라서 12번 열에서 obj객체가 plus라는 매쏘드를 사용할 수 있는 것입니다.

프로토타입 체인을 정리해보면..
obj는 A의 프로토타입 프로퍼티로부터 상속받고
A는 Object(최상위 객체)로 부터 값을 상속받습니다.

그렇다면 위 소스에서

var obj2  = new A();
console.log(obj2.plus());

를 추가하면 어떻게 될까요?
한번 생각해 보세요~

다음주는 객체 지향 프로그래밍을 좀 더 실용적인 예를 통해 스터디 하겠습니다.