
JavaScript: 연산자 operator
참고한 글
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators
- http://www.insightbook.co.kr/book/programming-insight/자바스크립트-완벽-가이드
산술 연산
+ - * / % ++ --
덧셈 연산자는 피연산자 중 하나가 문자열일 때 나머지 피연산자도 문자열로 변환하려고 시도한다. 그래서 'nan' + 1
의 결과는 ‘nan1’이 된다.
증가/증감++ --
연산자는 피연산자를 가능할 경우 숫자 타입으로 변경한다. 가령 x++
에서 x가 문자열 "1"
이면 x는 숫자 1로 바뀌며 이후 1씩 증가된다. x가 숫자로 바꿀 수 없는 문자열일 경우 NaN을 반환한다.
할당 연산
= += -= *= /= %=
&= ^= |= <<= >>= >>>=
비교 연산
== === != !== > < >= <=
===
는 일치연산자 혹은 엄격한 동등 연산자라고 한다. ==
는 동등(equal)을 판단하며 ===
는 일치(identical)하는지 판단한다. 둘은 같음을 정의하는 기준이 다르다. 가령 ===
는 값이 같아도(형변환을 통해 같다고 판단되는 값. 가령 1과 ‘1’은 동등하다.) 타입이 다를 경우 둘이 서로 다른것으로 판단한다.
동등 연산==
의 판단 기준:
- 두 값의 타입이 같은 경우, 두 값이 일치하면 둘은 동등하다.
- 두 값의 타입이 다른 경우에도 여전히 동등할 여지가 있으므로 타입 변환이 사용된다.
- 두 값 중 하나가 null이고 다른 하나가 undefined라면 두 값은 동등하다.
- 두 값 중 하나가 문자열이고 다른 하나가 숫자면 문자열을 숫자로 변환한다.
- 두 값 중 하나가 true이면 이를 1로 변환, false일 땐 0으로 변환 후 비교한다.
- 한 값이 객체고 다른 하나가 숫자 또는 문자열이면 객체를 원시 타입으로 변환 후 비교한다. 객체의 원시 타입 변환에는 해당 객체의
toString()
메서드나valueOf()
메서드가 사용된다.
일치 연산===
의 판단 기준:
- 두 값의 타입이 서로 다르면 두 값은 일치하지 않는다.
- 두 값이 모두 null이거나 undefined면, 두 값은 일치한다.
- 두 값이 모두 불리언 값 true이거나 false일 경우에 두 값은 일치한다.
- 적어도 하나의 값이 NaN이면 두 값은 일치하지 않는다. NaN 값은 자기 자신을 포함해 다른 어떠한 값과도 일치하지 않는다. 임의의 값 x가 NaN인지 검사하기 위해서는
x !== x
와 같이 사용한다. 앞의 표현식이 참을 만족 할 때만 x의 값이 NaN이 된다. - 두 값이 모두 숫자고 같은 값을 갖는다면, 두 값은 일치한다. 만약 하나의 값이 0이고 다른 하나의 값이 -0일지라도, 두 값은 일치한다.
- 두 값이 모두 문자열이고, 같은 위치에 정확히 같은 16비트 문자열 값을 갖고 있다면, 두 값은 일치한다. 만약 문자열의 길이나 내용이 다를 경우, 두 값은 일치하지 않는다. 두 문자열이 같은 의미를 갖고, 육안상 같은 문자열을 갖더라도 16비트 값의 순서가 다르게 인코딩되어 있을 수도 있다.
- 자바스크립트에서는 유니코드 문자열에 대해서 정규화 과정을 수행하지 않는다. 또한
===
나==
연산자를 사용해 유니코드 문자열의 동등 비교를 할 수 없다. 이와 같은 문자열을 비교하려면String.localeCompare()
를 사용한다. - 두 값이 모두 같은 객체나 배열 또는 함수를 참조하고 있으면, 두 값은 일치한다. 두 값이 서로 다른 객체를 참조할 경우에 설사 두 객체의 프로퍼티가 일치하더라도 두 값은 일치하지 않는다.
논리 연산
&& || !
var a = 0, b = 1;
a == 0 && b == 1; // true
true && b == 0; // false
a != b || b != b; // true
false || true; // true
false || (true && false); // false
논리 연산자 &&
, ||
는 피연산자가 관계 표현식 또는 boolean 타입이거나 괄호로 감싼 논리 표현식일 땐 일반적인 AND와 OR연산을 수행한다.
만약 피연산자가 boolean이 아닐 때 해당 피연산자는 boolean 타입으로 변환된다. 이후 규칙에 따라 값을 반환하는데, 반환되는 값은 boolean이 아니라 boolean으로 변환되기 전인 원래의 값이 반환된다. 가령 다음을 보면:
undefined && 1; // undefined
undefined가 false로 변환되고 연산식을 평가한 후 다시 원래의 값인 undefined가 반환된다.
1 && 2; // 2
3 && 1; // 1
0 && undefined; // 0
undefined && 0; // undefined
123 && null; // null
null && 123; // null
&&
는 다음 규칙을 따른다:
- 피연산자가 모두 true일 땐 우변 피연산자의 값을 반환
- 피연산자가 모두 false일 땐 좌변 피연산자의 값을 반환
- 둘 중 하나가 false일 땐 false로 평가되는 값을 반환
[] || {}; // Array [ ]
"123" || window; // "123"
null || undefined; // undefined
undefined || null; // null
0 || 1; // 1
1 || 0; // 1
||
는 다음 규칙을 따른다:
- 피연산자가 모두 true일 땐 좌변 피연산자의 값을 반환
- 피연산자가 모두 false일 땐 우변 피연산자의 값을 반환
- 둘 중 하나가 false일 땐 true로 평가되는 값을 반환
다른 연산자도 마찬가지지만 논리 연산자 또한 피연산자를 비교하기 전에 각 피연산자를 평가(evaluate)하는 과정을 거친다. 표현식이나 호출식을 먼저 실행한 후 비교한다고 생각하면 된다. 그리고 상황에 따라 우변의 피연산자는 평가될 수도 있고 평가되지 않을 수도 있다는 것을 주의해야 한다. 다음 예를 보면:
alert(1) || alert(2);
OR 연산은 좌변이 false일 때 우변도 평가한다. (window.alert의 리턴값은 undefined) 따라서 경고창은 두 번 나타난다.
alert(1) && alert(2);
AND 연산은 좌변이 false일 때 우변을 평가하지 않는다. 따라서 경고창은 한 번 나타난다.
true || alert(2);
OR 연산은 좌변이 true일 때 우변을 평가하지 않는다. 이 경우 경고창이 나타나지 않는다.
true && alert(2);
AND 연산은 좌변이 true일 때 우변을 평가한다. 경고창이 나타난다.
다음은 논리 연산자로 삼항 연산을 흉내낸 것이다:
var a = 1;
var result = (a == 1) && 'equal' || 'not equal';
console.log(result); // "equal"
OR 연산자의 좌변과 우변이 모두 true로 평가되는 값일 때만 제대로 작동하는 한계가 있지만…
비트 연산
~
: 비트단위 NOT&
: 비트단위 AND|
: 비트단위 OR^
: 비트단위 XOR<<
: 왼쪽으로 이동>>
: 부호 비트를 확장하면서 오른쪽으로 이동>>>
: 부호 비트 확장 없이 오른쪽으로 이동
삼항 연산자
조건 연산자 또는 선택 연산자. TRUE 혹은 FALSE에 해당하는 값을 반환한다.
조건 ? TRUE : FALSE
var a = 1;
var result = (a == 1) ? "일" : "일 아님";
console.log(result); // "일"
instanceof
객체의 프로토타입 체인에 생성자의 프로토타입이 존재하는지 테스트한다. 좌변의 피연산자로 객체를 받고 우변의 피연산자로 생성자를 받는다. 이 연산자로 객체가 특정 타입의 인스턴스인지 판단할 수 있다. 우변은 반드시 함수 이름이어야 하는데, 만약 함수가 아니면 TypeError가 발생할 것이다.
object instanceof constructor
function fn() {
// blah blah blah
}
fn instanceof Function; // true
alert instanceof Function; // true
"" instanceof String; // false, 문자열 자체는 원시 타입이기 때문
new String() instanceof String; // true, String 래퍼 객체는 String의 인스턴스
[] instanceof Array; // true, [].__proto__ === Array.prototype
[] instanceof Object; // true, 모든 객체는 Object의 인스턴스
typeof
연산자 다음에오는 변수, 함수, 객체 또는 표현식의 타입을 반환한다.
typeof expression
typeof "John" // "string"
typeof 3.14 // "number"
typeof NaN // "number"
typeof false // "boolean"
typeof [ 1, 2, 3, 4 ] // "object"
typeof { name: 'John', age: 34 } // "object"
typeof new Date() // "object"
typeof function() {} // "function"
typeof myCar // "undefined" (if myCar is not declared)
typeof null // "object"
in
객체나 배열에 특정 프로퍼티가 존재하는지 확인한다.
expression in Object
// Arrays
var cars = [ "Saab", "Volvo", "BMW" ];
"Saab" in cars // false, 'Saab'은 프로퍼티의 이름이 아니라 값이므로 false
0 in cars // true
1 in cars // true
4 in cars // false, cars의 길이는 3이므로 배열의 4번째 인덱스는 없다.
"length" in cars // true, Array 래퍼 객체에 length란 프로퍼티가 존재함.
// Objects
var person = { firstName: "John", lastName: "Doe", age: 50 };
"firstName" in person // true
"age" in person // true
// Predefined objects
"PI" in Math // true
"NaN" in Number // true
"length" in String // true
또한 in은 for-in 반복문에서 사용된다.
for (variable in object) { ... }
- object: 반복할 객체. 객체의 프로퍼티 만큼 반복된다.
- variable: 매번 반복될 때마다 프로퍼티의 key를 할당한다. 만약 반복되는 객체가 배열일 경우 인덱스를 할당할 것이다.
var foo = { a: 1, b: 2};
var propNames = [];
for (var ele in foo) {
propNames.push(ele);
}
console.log(propNames); // [ "a", "b" ]
var foo2 = [ 'aaa', 'bbb', 'ccc' ];
var idxs = [];
for (var ele in foo2) {
idxs.push(ele);
}
console.log(idxs); // [ "0", "1", "2" ]
delete
프로퍼티를 삭제한다. 삭제에 성공했을 때 true를, 실패했을 때 false를 반환한다.
delete Object.property
var fn = { word: "hi" };
console.log(fn.word); // "hi"
delete fn.word; // true
console.log(fn.word); // undefined
var문으로 정의된 변수(전역 객체의 프로퍼티라 하더라도), 함수 선언문(또는 함수 구문)으로 정의된 함수, 함수 매개변수로 선언한 함수는 삭제할 수 없다.
var a = 1;
delete a; // false
function fn() { }
delete fn; // false
function callee(callback) {
console.debug(delete callback); // false
}
callee(function() {});
void
void expression
void 연산자는 피연산자를 실행하고 undefined를 반환한다. 피연산자를 실행해야 하지만 결과를 노출하고 싶지 않을때 사용한다.
<a href="javascript:void window.open()">open</a>
void는 같은 이름의 함수가 존재하는데:
void(0); // undefined
void(); // SyntaxError: expected expression, got ')'
연산자와 마찬가지로 항상 undefined를 반환하는 함수다. 전달인자는 어느 값이어도 상관 없지만 할당하지 않으면 에러가 발생한다. 이동할 주소가 없는 앵커 태그가 필요할 때 종종 사용된다.
<a href="javascript:void(0)">test</a>