var o = {
m: function() {
var self = this;
console.log(this === o); // true
f();
function f() {
console.log(this === o); // false
console.log(self === o);
}
}
}
o["m"]();
Output :
생성자 호출
new keyword -> 생성자 호출
인자가 없으면 두 문장은 완전히 같은 것.
var o = new Object();
var o = new Object;
생성자 함수는 보통 return 사용하지 않음. 함수의 마지막에서 객체를 반환, 혹은 return만 명시 되어있으면 거기서 객체 반환 기본 자료형 값(primitive value)을 반환하면 무시되고 새로생성된 객체가 호출 표현식 값.
간접 호출
call() -> 자신에게 주어진 전달인자를 호출할 함수의 전달인자로 사용 apply() -> 값 배열을 전달인자로 사용.
두 메서드 모두 호출 때 this 값을 명시적으로 지정 가능. -> 어떤 함수든지 특정 객체의 메서드로 호출할 수 있다는 의미
함수 전달인자와 매개변수
Javascript는 함수 매개변수타입, 전달인자 개수, 전달하는 인자의 타입 모두 검사하지 않음. 이를 프로그래머가 관리하는 방법들.
생략 가능한 매개변수
본래 정의된 것 보다 적으면 -> 나머지는 undefined 이렇게 두지 말고 생략된 매개변수에는 기본값을 주는 코드를 쓰자.
function getPropertyNames(o, /*optional*/ a) {
if(a == undefined) a = [];
//or a = a || []
// || -> 첫번째가 true나 true로 반환되는 값이면 그 값 return, 그렇지 않으면 뒤에 것 return
for(var property in o) {
a.push(property);
}
return a;
}
가변길이 전달인자 목록 : Arguments객체
본래 정의된 것 보다 많을 때.
function f(x, y, z) {
if(arguments.length != 3) {
throw new Error("인자개수가 3이 아닙니다.")
}
}
이렇게 해도 좋지만 javascript의 기본동작인
빠진 인자는 undefined
추가된 인자는 무시 로도 잘 동작하게 구현 가능.
argument 객체를 직접 수정시
function g(x) {
console.log(x);
arguments[0] = null;
console.log(x);
}
엄격모드가 아니면 값 변경, 엄격모드 시 값 변경되지 않음.
callee와 caller 속성
엄격모드에서는 사용 못함. callee -> 프로퍼티가 현재 실행되고 있는 함수를 참조, 이름없는 함수를 재귀적으로 호출하는데 유용 caller -> 비표준. 이 함수를 호출한 함수를 참조. 호출 스택에 접근할 수 있도록 해줌.
객체의 프로퍼티를 전달인자로 사용하기
easycopy({from : a, to : b, length : 4});
값으로서의 함수
function square(x) {return x * x};
var s = square;
square(4);
s(4);
var o = {square: function(x) {return x * x}};
var y = o.square(16);
var a = [function(x) {return x*x; }, 20];
a[0](a[1]);
자신만의 함수 프로퍼티 정의하기
C 에서의 static 지역변수 역할
uniqueInteger.counter = 0;
function uniqueInteger() {
return uniqueInteger.counter++;
}
함수 이름을 배열처럼 다룸
function factorial(n) {
if(isFinite(n) && n>0 && n == Math.round(n)) {
if(!(n in factorial)) {
factorial[n] = n * factorial(n - 1);
}
return factorial[n];
}
else return NaN;
}
factorial[1] = 1;
네임스페이스로서의 함수
javascript 는 단위 block 내에 유효한 변수를 정의하는 방법을 제공하지 않음. 간단한 임시 네임스페이스 처럼 작동하는 함수를 정의하는 기법 사용.
function mymodule() {
// 모듈의 지역변수로 사용해서 전역을 어지럽히지 않음
}
mymodule(); // 함수 실행 필수
// 하나의 프로퍼티 선언도 과하다면
(function() {
// 모듈 코드가 위치
}()) // 바로 호출하고 끝냄. function앞 뒤 괄호는 반드시 필요 -> 표현식임을 알림
클로저
함수 객체, 함수의 변수가 해석되는 유효범위(변수 바인딩의 집합) 을 아울러 클로저라고 함 모든 자바스크립트 함수는 클로저. -> 함수는 객체이고 함수 자신과 관련된 유효범위 체인을 가지고 있기 때문.
클로저는 자신을 정의한 바깥쪽 함수에 바인딩된 지역변수를 포착한다.
var scope = "global";
function checkscope() {
var scope = "local";
function f() {return scope;};
return f;
}
checkscope()() // local 출력
EX) Counter
내부변수는 private. 오직 count와 reset을 통해서만 제어가능
function counter() {
var n = 0;
return {
count: function() {return n++;},
reset: function() { n = 0; }
}
}
var c = counter(), d = counter();
console.log("c : ", c.count());
console.log("d : ",d.count());
c.reset()
console.log("c : ",c.count());
console.log("d : ",d.count());
Output:
Function 생성자
동적으로 자바스크립트 함수를 생성하고 실행 시간에 컴파일 되는 것을 가능하게 한다.
이걸로 생성하는 함수는 언제나 최상위 레벨 함수로, lexical scoping을 사용하지 않는다.
var f = new function("x", "y", "return x*y);
// 마지막 인자는 함수의 몸체 텍스트
var empty = [];
var primes = [2,3,5,7,11];
var misc = [ 1.1, true, "a" ];
// 임의의 표현식도 사용 가능
var base = 1024;
var table = [base, base+1, base+2, base+3];
var count = [1,,3]; // 가운데 값은 undefined
var undefs = [,,]; // 원소는 2개 (마지막원소에 , 가능)
Array 생성자
var a = new Array();
var aa = new Array(10); // length
var aaa = new Array(5,4,3,2,1, "testing, testing"); // 인자값이 배열의 원소
console.log(aaa)
배열에 속한 원소의 위치가 연속적이지 않은 배열 원소가 undefined가 아니라 아예 없는 것
arr = new Array(5); // 원소는 없지만 a.length의 값은 5
arr2 = [] // length값이 0인 빈 배열
arr3[1000] = 1; // 하나의 원소 할당, 길이는 1000
배열의 길이
배열의 length Property : 배열의 원소 개수, 배열의 가장 큰 인덱스+1
length 값 변경 :
a = [1,2,3,4,5];
a.length = 3; // 결과가 1,2,3이 된다.
a.length = 0; // 결과 []
a.length = 5; // new Array(5)와 같은 결과
length Property 읽기전용으로 만들기 :
a = [1,2,3];
Object.defineProperty(a, "length", {writeable: false});
a.length = 0; // 값 바꿔도 배열은 변하지 않음
배열 원소 추가 제거
a = [];
a[0] = "zero";
a.push("one");
a.push("two", "three");
console.log(a.length);
delete a[1];
console.log(1 in a); // false -> 지워졌다.
console.log(a.length);
Output :
배열 순회하기
var o = new Array(7,5,3,2);
var keys = Object.keys(o);
var values = [];
for(var i = 0; i < keys.length; i++) {
var key = keys[i];
values[i] = o[key];
}
console.log(o);
console.log(keys);
console.log(values);
for(var i = 0, len = keys.length; i < len; ++i) {
// 성능향상 위해 length를 한번만 불러오기
}
Output :
루프 돌릴 때 고려해야 할 점
원소가 null / undefined 일 때 어떻게 처리할 지
상속받은 Property 등의 고유 Property 가 아닌 값들을 어떻게 처리할 지
for in loop에서 원소 반환 순서
정해져있지 않음.
순서가 중요한 알고리즘에서는 for문을 통해 명시적으로 사용할 것을 권장
다차원 배열
var table = new Array(10);
for(var i = 0; i < table.length; ++i) {
table[i] = new Array(10);
}
for(var i = 0; i < table.length; ++i) {
for(var j = 0; j < table[i].length; ++j) {
table[i][j] = i*j;
}
}
console.log(table[5][7]);
Output :
배열 메서드
join()
* 배열의 모든 원소를 문자열로 변환, 변환한 문자를 이어붙인 결과를 return
* seperator를 지정하지않으면 , 가 기본 separator
* String.split() -> join의 반대. 문자열을 배열로
var a = [1, 2, 3];
console.log(a.join());
console.log(a.join(' '));
console.log(a.join(''));
Output :
reverse()
배열의 원소 순서를 반대로 뒤집어 반환.
배열안에서 직접 수행되어 배열 정렬순서 변환됨.
var b = [1,2,3];
b.reverse();
console.log(b);
Output :
sort()
정렬
undefined는 배열의 끝부분으로
정렬 조건도 바꿀 수 있음
var c = [1,2,3,4];
c.sort();
console.log(c);
c.sort(function(a,b) {
return b - a;
})
console.log(c);
Output :
concat()
concat의 전달인자를 추가한 배열 반환
var d = [1,2,3];
console.log(d.concat(4,5));
console.log(d.concat([4,5]));
console.log(d.concat([4,5], [6,7]));
console.log(d.concat([4, [5,6]]));
Output :
slice()
subarray 반환
-1은 마지막 원소
음수는 뒤에서부터 세는 것
var e = [1,2,3,4,5];
console.log(e.slice(0,3));
console.log(e.slice(3));
console.log(e.slice(1,-1));
console.log(e.slice(-3,-2));
var empty = {};
var point = {x:0, y:0};
var point2 = {x: point.x, y:point.y + 1}
var book = {
"main title" : "Javascript", // 공백도 가능
"for" : "all audiences"
}
console.log("empty : ", empty);
console.log("point : ", point);
console.log("point2 : ", point2);
2. new 키워드
var o = {};
var o2 = new Object();
// o 와 o2는 같다.
var a = new Array();
var d = new Date();
var r = new RegExp("js") // 패턴매칭을 위한 RegExp 객체
3. prototype
Javascript 의 모든 객체는 또 다른 Javascript의 객체와 연관되어 있음. 이 두 번째 객체 : Prototype 객체는 Prototype으로부터 Property를 상속받는다.
객체 리터럴로 생성된 모든 객체는 Prototype 객체가 같다.
Object.prototype으로 접근 가능
new Array()는 Array.prototype을 객체의 프로토 타입으로 사용하는 식
Object prototype : 프로토타입이 없음.
다른 객체들은 보통 prototype이 다 있음.
Array.prototype은 Object.prototype을 상속받음.
위와 같은 걸 Prototype chain이라고 한다 .
4. Object.create()
create()
첫 번째 인자 : 프로토타입 객체
두 번째 인자 : 새 객체의 프로퍼티 정보 생략가능
var o1 = Object.create({x:1, y:2});
console.log(o1);
var o2 = Object.create(null);
console.log(o2);
var o3 = Object.create(Object.prototype)
console.log(o3);
o1 :
o2 : -> 어떠한 객체도 상속받지 않는다.
o3 : -> Object객체는 상속받고 싶을 때
inherit 함수 구현
상속 받도록 구현하지 않고 객체 자체를 인자로 넣어 Property를 추가하려 한다면, 기존에 있는 수정되어서는 안되는 Property를 수정하게 되는 실수를 할 수 있다.
Prototype을 이용한 상속으로 원하는 Property를 추가하면서도 그 실수를 방지하기 위해 inherit function을 구현해 사용한다.
function inherit(p) {
if (p == null) throw TypeError();
if (Object.create) // ECMAScript 5 이상에 정의되어 있음
return Object.create(p);
// Object.create 가 정의되어있지 않으면
var t = typeof p;
if (t !== "object" && t !== "function") {
throw TypeError();
}
function f() {};
f.prototype = p;
return new f();
}