내장 네이티브 생성자는 각자의 .prototype
을 가진다.
prototype 객체에는 해당 객체의 하위 타입별로 고유한 로직이 담겨 있다.
String.prototype.indexOf()
String.prototype.charAt()
String.prototype.substr()
String.prototype.substring()
String.prototype.slice()
String.prototype.toUpperCase()
String.prototype.toLowerCase()
String.prototype.trim()
.
.
.
각 생성자 프로토타입마다 자신의 타입에 적합한 기능이 구현되어 있다.
var a = " abc "
a.indexOf( "c" ); // 3
a.toUpperCase(); // " ABC "
a.trim(); // "abc"
평범하지 않은 프로토타입도 있다.
typeof Function.prototype; // "function"
Function.prototype(); // 빈 함수다!
RegExp.prototype.toString(); // "/(?:)/ - 빈 regex
"abc".match( RegExp.prototype ); // [""] - 책과 달리 이건 에러가 난다..
네이티브 프로토타입을 변경할 수도 있지만 결코 권장하지 않는다.
Array.isArray( Array.prototype ); // true
Array.prototype.push(1, 2, 3); // 3
Array.prototype; // [1, 2, 3]
// 이런 식으로 놔두면 이상하게 작동할 수 있다.
// 다음 코드는 'Array.prototype'을 비워버린다.
Array.prototype.length = 0;
Function.prototype은 함수, RegExp.prototype은 정규 표현식, Array.prototype은 배열이다. (이게 재밌고 쿨한가..?)
Function.prototype; // ƒ () { [native code] }
RegExp.prototype.toString(); // /(?:)/
Array.prototype; // [constructor: ƒ, concat: ƒ, copyWithin: ƒ, fill: ƒ, find: ƒ, …]
function isThisCool( vals, fn, rx ) {
vals = vals || Array.prototype;
fn = fn || Function.prototype;
rx = rx || RegExp.prototype;
return rx.test(
vals.map( fn ).join("")
);
}
isThisCool(); // true
isThisCool(
["a", "b", "c"],
function(v){ return v.toUpperCase(); },
/D/
); // false
es6부터는
'vals = vals || 디폴트 값'
식의 구문 트릭은 더 이상 필요 없다. function (a = 42, b = 20) {} 이런식으로 default값을 정할 수 있다.
예제처럼 디폴트 값으로 Array.prototype을 사용하는 일은 없도록 해야한다. vals는 읽기 전용이지만 vals 변수 자체를 수정하면 Array.prototype 자체도 수정되어 버린다.