본문으로 건너뛰기

"javascript" 태그로 연결된 112개 게시물개의 게시물이 있습니다.

모든 태그 보기

HTML 태그 모두 제거

· 약 1분

스마트 에디터 같은 에디터를 쓸 대 내용을 텍스트로만 받아야할 경우가 있다.

var data = data.replace(/[<][^>]*[>]/g, "");

설명

< > 안의 태그들을 모두 빈값으로 치환한다.

JSON.parse unexpected type Error

· 약 2분

database 에 이미 json 으로 저장된 데이터를 가져와 JSON.parse 메소드로 JSON 데이터를 파싱하는 중에 값이 string 인데도 오류가 나는 경우가 있다.

로그를 확인해보면

{"data":"[{"name":"gracefullight"},{"name","daniel"}]"}

[] 배열 기호 앞뒤로 따움표가 들어가 있다. 이중 object 가 있다면 선언문 앞뒤로 따움표가 들어가 파싱 오류가 난다.

jQuery.ajax 의 dataType 을 json 으로 설정해 데이터를 받는데, 이미 json 형태의 string 이 넘어와 두번 치환이 된 것 같다.

다시 json 을 인식할 수 있게 치환해보자

소스

var jsonReplace = function (j) {
if (j) {
j = j
.replace(/\"\[/g, "[")
.replace(/\]\"/g, "]")
.replace(/\"\{/g, "{")
.replace(/\}\"/g, "}");
}
return j;
};

설명

해당 함수로 오류가 나는 json string 을 치환 후에 다시 JSON.parse 를 실행하면 된다.

여담

정규식을 활용해 replace 중첩을 피하게 짤 수 있을 것 같은데...

hasOwnProperty vs prototype.hasOwnProperty

· 약 2분

for-in 구문을 쓸 때 상속된 프로퍼티나 this 구문을 방지하기 위하여 보통 hasOwnProperty 로 체크한다.

for (prop in obj) {
if (obj.hasOwnProperty(prop)) {
// code...
}
}

문제점

위와 같은 방식은 아래와 같이 hasOwnProperty 가 재정의 된 객체에서 오류를 발생할 수 있다.

소스

var obj = {
hasOwnProperty: function () {
return false;
},
data1: 1,
};

for (prop in obj) {
// obj.hasOwnproperty(prop) 의 결과는 항상 false
if (obj.hasOwnproperty(prop)) {
// 이 구문은 실행되지 않는다.
}
}

prototype.hasOwnProperty

따라서 prototype 을 사용해 코딩해야한다.

소스

for (prop in obj) {
// 첫번째 방법
if ({}.hasOwnProperty.call(obj, prop)) {
}

// 두번째 방법
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
}
}

설명

첫번째 방법은 익명 Object 를 생성한 후 obj 와 prop 을 밀어넣는 방식이고 두번째 방법은 기본 Object 의 hasOwnProperty 를 가져와 obj 와 prop 을 밀어넣는 방식이다.

두번째 방법이 새(익명) Object 를 생성하지 않기에 이 방법을 사용하면 된다.

더 자세하게 알고 싶다면 mdn을 참조한다.

Throttle, Debounce Pattern

· 약 3분

javascript throttle 패턴과 debounce 패턴에 대해 알아보자.

매 ms 마다 한 번만 호출된다. mousemove, scroll 같은 이벤트로 호출되는 함수는 이벤트 발생시 무한정 호출되어 성능 저하를 가지고 오는데, 이를 방지할 수 있다.

모바일에서 스크롤링 더보기에 사용할 수 있다.

소스

var throttleFunction = (function () {
"use strict";

var timeWindow = 500; // 여기에 시간(ms)을 지정한다
var lastExecution = new Date(new Date().getTime() - timeWindow);
// ES6 이하일 경우 ...args에 호출할 parameter 만큼 준다 function(arg1, arg2...)
var throttleFunction = function (...args) {
// 여기에 로직을 구현한다
};

return function () {
if (lastExecution.getTime() + timeWindow <= new Date().getTime()) {
lastExecution = new Date();
return throttleFunction.apply(this, arguments);
}
};
})();

// 사용법
throttleFunction(param1, param2);

Debounce

마지막 호출로부터 ms 후에 함수를 한번 호출한다. 지연된 호출을 할 수 있게 해주는데, 호출이 반복되는 동안은 실행을 방지하고, 호출이 멈춘 뒤 지정한 ms 후에 함수를 실행해 성능 저하를 막을 수 있다.

검색 자동완성 기능에 적합하다.

소스

var debounceFunction = (function () {
"use strict";

var timeWindow = 500; // 여기에 시간(ms)을 지정한다
var timeout;
// ES6 이하일 경우 ...args에 호출할 parameter 만큼 준다 function(arg1, arg2...)
var debounceFunction = function (...args) {
// 여기에 로직을 구현한다
};

return function () {
var context = this;
var args = arguments;

clearTimeout(timeout);
timeout = setTimeout(function () {
debounceFunction.apply(context, args);
}, timeWindow);
};
})();

// 사용법
debounceFunction(param1, param2);

여담

즐겨 사용하는 sublime text package 인 javascript patterns에서 참조했다.

lodash를 사용한다면 debounce, throttle로 더 쉽게 사용할 수 있다.

UMD Patterns

· 약 3분

UMD (Universal Module Definition) Pattern 이란 AMD (requireJS), CommonJS (node), 일반 browser 환경에서 통합해서 쓸 수 있는 javascript module pattern 이다.

jQuery, moment, D3 등의 라이브러리에서도 해당 패턴을 사용한다.

새로 만들 예제의 모듈명은 module1 이고 jQuery 에 종속적이라고 가정한다.

(function (global, factory) {
if (typeof define === "function" && define.amd) {
// AMD 환경
define(["exports", "jquery"], factory);
} else if (
typeof exports === "object" &&
typeof exports.nodeName !== "string"
) {
// CommonJS 환경
factory(exports, require("jquery"));
} else {
// 일반 브라우저
factory((global.module1 = global.module1 || {}), global.$);
}
})(this, function (exports, $) {
// module1의 private 기능 구현

// exports에 public function을 붙혀주면 된다.
exports.action = function () {};
});

종속되는 모듈을 추가하려면, AMD 는 배열안에, commonJS 와 일반은 파라미터로 추가한 뒤 12 번째 줄의 콜백함수 안에 원하는 변수로 받으면 된다.

예제 - 기본형

(function (global, factory) {
if (typeof define === "function" && define.amd) {
define(["exports"], factory);
} else if (
typeof exports === "object" &&
typeof exports.nodeName !== "string"
) {
factory(exports);
} else {
factory((global.module1 = global.module1 || {}));
}
})(this, function (exports) {
exports.action = function () {};
});

즉시실행 함수에 window 객체와 함수를 파라미터로 보내서 전역 객체를 생성하는 방식이다.

예제 - 3 항연산자 사용

(function (global, factory) {
typeof exports === "object" && typeof module !== "undefined"
? factory(exports)
: typeof define === "function" && define.amd
? define(["exports"], factory)
: factory((global.module1 = global.module1 || {}));
})(this, function (exports) {
exports.action = function () {};
});

설명

window 객체 안에 모듈이 선언되므로, module1.action(); 으로 바로 호출해 사용하면 된다.

더 자세한 설명을 보고싶다면 umd를 참조하면 된다.

jsonp function

· 약 2분

jsonp (json with padding)은 다른 서버의 데이터를 내 브라우저에서 호출하기 위해 사용한다. client 에서 callback 함수명과 전송할 값을 같이 보내어 server 에서 callback 함수 안에 data 를 담아 반환하는 방식이다.

전송할 값을 보낼 때, script 태그를 사용한다.

function jsonp(url, callback) {
var callbackName = "jsonp_" + Math.round(100000 * Math.random());
window[callbackName] = function (data) {
delete window[callbackName];
document.body.removeChild(script);
callback(data);
};

var script = document.createElement("script");
script.src =
url + (url.indexOf("?") >= 0 ? "&" : "?") + "callback=" + callbackName;
document.body.appendChild(script);
}

stackoverflow 에서 가져온 소스인데 현재 출처를 찾을 수 없다.

설명

임의의 함수명으로 callback 함수를 생성한 뒤 script 태그를 생성해 server 와 통신한다.

예제

jsonp("http://aaa.com?data=" + data, function (result) {
console.log(result);
});

여담

jQuery 가 있다면 jQuery ajax의 dataType 을 jsonp 로 설정해주면 되고, 요새는 CORS 를 적용해 그냥 호출하는 방식으로 가는 추세다.

Object freeze, seal, preventExtensions - 객체 수정 제어

· 약 2분

es5 부터 객체의 수정을 제어할 수 있다. ie9 부터 지원하고, ie8 은 es5-sham을 추가하면 된다.

객체를 불변으로 만든다.

예제

var frozenObject = {
value1: 1,
value2: 2,
};

Object.freeze(frozenObject);
console.log(Object.isFrozen(frozenObject)); // true

// 삭제 불가
delete frozenObject.value1;
console.log(frozenObject.value1); // 1

// 변경 불가
frozenObject.value2 = 3;
console.log(frozenObject.value2); // 2

// 객체 추가 불가
frozenObject.value3 = 3;
console.log(frozenObject.value3); // undefined

seal method

확장, 축소는 불가능하지만 writable 쓰기 가능하다.

예제

var sealedObject = {
value1: 1,
value2: 2,
};

Object.seal(sealedObject);
console.log(Object.isSealed(sealedObject)); // true

// 삭제 불가
delete sealedObject.value1;
console.log(sealedObject.value1); // 1

// 변경 가능
sealedObject.value2 = 3;
console.log(sealedObject.value2); // 3

// 객체 추가 불가
sealedObject.value3 = 3;
console.log(sealedObject.value3); // undefined

preventExtensions method

확장만 불가능하다.

예제

var preventExtensionObject = {
value1: 1,
value2: 2,
};

Object.preventExtensions(preventExtensionObject);
console.log(Object.isExtensible(preventExtensionObject)); // false

// 삭제 가능
delete preventExtensionObject.value1;
console.log(preventExtensionObject.value1); // undefined

// 변경 가능
preventExtensionObject.value2 = 3;
console.log(preventExtensionObject.value2); // 3

// 객체 추가 불가
preventExtensionObject.value3 = 3;
console.log(preventExtensionObject.value3); // undefined

설명

불변하게 하려면 얼리고, 수정이 가능하게 하려면 봉인하고 추가만 불가능하게 하려면 확장방지하자

client 에서 객체 변조를 못하게 전역변수를 얼려버리자

여담

freeze 는 중첩된 object 에 적용이 안 되는데, 이 때 deepFreeze 함수를 사용해 재귀적으로 객체를 얼려버리면 된다.

deepFreeze method

mdn을 참조했다.

소스

function deepFreeze(obj) {
if (!Object.isFrozen(obj)) {
Object.freeze(obj);
}

for (var key in obj) {
if (
{}.hasOwnProperty.call(obj, key) ||
!(
typeof obj[key] === "function" ||
(typeof obj[key] === "object" && !!obj[key])
)
) {
continue;
}

deepFreeze(obj[key]);
}
}

Javascript 기본값 연산자 (축약된 삼항연산자)

· 약 1분

한번 쓰면 헤어나올 수 없는 기본값 연산자에 대해 알아보자.

소스

// JavaScript syntax to set a default value
var text = someString || "default text";
var text2 = someString || someString2 || "default text2";

설명

someString 이 있으면 someString 을 반환, 아니면 default text 를 반환한다. 계속 붙혀나가면서 쓸 수 있다.

php7 에서는 해당 기능이 추가되었다. || 대신에 ?? 를 사용하면 된다.

lodash 에선 defaultTo를 사용하면 된다.

링크 클릭시 return false가 페이지에 그대로 출력될 때

· 약 1분

링크를 클릭했는데, 페이지에 return false;가 찍혀나오는 경우가 있다.

<script>
function test() {
if (true) {
return false;
}
}
</script>

<!-- 페이지에 return false;가 출력됨 -->
<a href="javascript:test();">테스트</a>

<!-- 대체 -->
<a href="javascript://" onClick="test();">테스트</a>

설명

a href 속성 안에 javascript 를 사용시 발생한다. javascript 호출문인 onClick 을 이용하자.

페이징시 Row의 순번(인덱스) 구하기

· 약 1분

전체 레코드 수와 현재 페이지 번호, 페이지에 표시되는 레코드의 수를 안다면 쉽게 구할 수 있다.

var totalCount;
var currentPageNum;
var shownRowNum;

for (var i = 0, len = data.length; i < len; i++) {
var index = Number(totalCount) - (i + (currentPageNum - 1) * shownRowNum);
}

여담

매번 공식을 알아내는게 귀찮아서 포스팅