April 06, 2017
전역변수의 문제점은 자바스크립트 어플리케이션이나 웹페이지 내 모든 코드 사이에서 공유가 된다. 모든 전역변수는 동일한 전역 네임스페이스 공간 안에 존재하게된다.
그래서 무조건 var 키워드를 변수 선언시 사용하는 것이 좋다.
function foo() {
var a = (b = 0)
}위처럼 코드를 작성하면, b는 전역변수가 된다. 평가 방식이 우측에서 좌측으로 이동한다.
var선언을 빼먹음으로써 부족용이 2가지 있다.
function funcexmaple() {
var a = 1,
b = 2,
sum = a + b,
myObject = {},
i,
j
}초기 값없이 선언된 변수들을 모두 undefined라는 값으로 초기화 된다.
자바스크립트는 변수를 비교할 떄 암묵적으로 타입캐스팅을 실행한다.
그런 이유로 false == 0 이나 """== 0과 같은 비교가 true를 반환한다.
암묵적 타입 캐스팅을 피하기 위해서는 항상 표현식의 값과 타입을 모두 확인하는 ===, !== 연산자를 사용해야 한다.
var seungdols = 0
if (seungdols === false) {
}
//anti-patterns
if (seungdols == false) {
}보안상에도 좋지 않고, 주로 사용하지 않으므로 아예 쓰지 말자. 쓰는 코드를 발견할 경우 즉시, 변경하도록 하자.
특히, setInterval(), setTimeout(), Function() 생성자에 문자열을 넘기는 것도 eval()과 유사한 기능을 하므로, 지양하자.
//안티패턴
setTimeout("seungdolsFunc()", 1000);
setTimeout("seungdolsFunc(1,2,3)", 1000);
//권장사항
setTimeout(seungdolsFunc, 1000);
setTimeout(funtion() {
seungdolsFunc(1,2,3);
}, 1000);parseInt()를 사용하면 문자열로부터 숫자 값을 얻을 수 있다. 이 함수의 두번째 매개변수로 기수를 받는데, 생략하는 경우에 많지만 그럼 안된다. 파싱할 문자열이 0으로 시작할 경우 문제가 생길 수 있다. 일관성 없고, 예측을 벗어나는 결과를 피하려면 항상 기수 매개변수를 지정해주어야 한다.
var strMonth = '06'
var month = parseInt(strMonth, 10)var dog = {}위는 빈 객체를 생성하는 객체 리터럴 표기법이다. 그러나, 참고해야 할 것은 자바스크립트에는 빈 객체라는 것은 없으며, 쉽게 말하는 의미이다. 간단한 객체 자체도, Object.prototype에서 상속받은 프로퍼티와 메서드를 가지고 있다.
var dog = { gender: 'M' } //권장 패턴
var cat = new Object() //안티패턴
cat.gender = 'W'리터럴 표기법을 사용시, 유효범위 판별 작업도 하지 않는다. 생성자 함수 사용시에는 지역 유효범위에 동일한 이름의 생성자가 있을 수 있어, Object()를 호출한 위치에서부터 전역 Object 생성자까지 인터프리터가 쭉 거슬러 올라가면서 유효범위를 검색해야 한다.
var Person = function(name) {
this.name = name
this.say = function() {
return 'I am ' + this.name
}
}
var adam = new Person('Adam')
adam.say()new 와 함께 생성자 함수를 호출하면, 함수 안에서 아래와 같은 일이 벌어진다.
코드의 내부적인 상황을 표현하면 이렇게 된다.
var Person = function(name) {
var this = {}
this.name = name
this.say = function() {
return 'I am ' + this.name
}
return this
}생성자의 반환값으로는 생성자 함수를 new와 함께 호출하면 항상, 객체가 반환 된다. 기본 값으로는 this호 참조되는 객체다.
함수내에 return문을 쓰지 않더라도 생성자는 암묵적으로 this를 반환한다.
생성자는 new와 함께 호출 될뿐이지, 다른 함수와 다를바가 없다. 그러나 new를 생략하면, 생성자 내부의 this 참조가 전역 객체인 window를 가리키므로 오류를 발생할 가능성을 높인다.
var arr = new Array('seungdols', 'seungho', 'speed') //안티 패턴
var arr = ['seungdols', 'seungho', 'speed']참고로 자바스크립트에서 배열은 object 타입이다.
더군다나, new Array로 생성할 경우 오류가 발생할 요지가 있는데, 이는 인자로 숫자를 줄 경우이다.
var arr = new Array(3)
console.log(arr.length)인자로 숫자를 주면 배열의 길이가 인자로 준 숫자 값으로 배열을 만드는데, 각 원소는 undefined로 생성 된다.
특히나, 부동 소수점으로 인자를 줄 경우 더욱 문제가 심해진다.
부동 소수점을 인자로 줄 경우에는 RangeError가 발생한다.
var re = '/\\/gm'
var reg = new RegExp('\\\\', 'gm') //안티 패턴자바스크립트에는 Error(), SyntaxError(), TypeError()등 여러 가지 에러 생성자가 내장 되어 있으며, throw문과 함께 사용된다.
이 생성자들을 통해 생성된 에러 겍체들은 다음과 같은 프로퍼티를 가진다.
name
message
try {
throw {
name: 'MyErrorType',
message: 'oops',
extra: 'This was rather embarrassing',
remedy: genericErrorHandler,
}
} catch (e) {
alert(e.message)
e.remedy()
}에러 생성자를 new 없이 일반 함수로 호출해도 new를 써서 생성자로 호출한 것과 동일하게 동작하여 에러 객체가 반환된다.
//기명 함수 표현식 (named function expression)
var add = function add(a, b) {
return a + b
}
//(무명)함수 표현식 or 익명 함수 (anonymous function)
var add = function(a, b) {
return a + b
}위 둘의 차이점은 별다른 것은 없고, 함수 객체의 name property가 빈문자열이 된다는 차이 밖에 없다.
//함수 선언문(function declaration)
function add(a, b) {
//
}함수 선언문은 전역 유효범위나 다른 함수의 본문 내부, 즉 ‘프로그램 코드’에서만 쓸 수 있다.
callMe(function() {
//unnamed function expression
})
callMe(function me() {
//named function expression
})
var seungdolsObject = {
say: function() {
//function expression
},
}위의 예 같은 경우에는 함수 선언문을 쓸 수 없다.
function foo() {
alert('global foo')
}
function bar() {
alert('global bar')
}
function hoistMe() {
console.log(typeof foo) //function
console.log(typeof bar) //undefined
foo() //local foo
bar() //TypeError
function foo() {
alert('local foo')
}
var bar = function() {
alert('local bar')
}
}
hoistMe()결국 선언된 위치와 상관 없이 끌어 올려지며 전역의 foo, bar를 덮어쓴다.
그런데, 지역변수 foo()는 나중에 정의되더라도 상단으로 호이스팅 되어 정상 작동하나, bar()의 정의는 호이스팅 되지 않고, 선언문만 호이스팅 된다.
때문에 bar()의 정의가 나오기 전까지는 undefined 상태이고, 따라서 함수로 사용할 수 없다. 또한 선언문 자체는 호이스팅 되어 유효범위 체인 내에서 전역 bar()도 보이지 않는 이유이다.
콜백 패턴은 이를테면, 함수의 특징 중 하나인 다른 함수의 인자로 전달 할 수 있다.를 활용한 방법이다.
function requestSpec(callback) {
//working
callback()
}위와 같은 코드를 콜백 패턴이라 말하는데, 요즘은 사실 콜백 헬 패턴이 될 가능성이 높아서 꺼리는 패턴이긴 하다.
콜백이 일회성의 익명함수나 전역 함수가 아니고, 객체의 메서드인 경우도 많은데, 이 때, 콜백 메서드가 자신이 속한 객체를 참조하기 위해 this를 사용하면, 예상치 않게 동작할 수 있다.
var seungdolsApp = {}
seungdolsApp.color = 'green'
seungdolsApp.paint = function(node) {
node.style.color = this.color
}
var findNodes = function(callback) {
if (typeof callback === 'function') {
callback(found)
}
}this.color가 정의 되지 않아 예상대로 동작 할 수 없다. 그리하여 동작 할 수 있도록 변경한다.
var findNodes = function (callback, callback_obj) {
if(typeof callback === "function") {
callback.call(callback_obj,found);
}
}
findNodes(seungdolsApp.paint, seungdolsApp); -> findNodes('paint', seungdolsApp);//이렇게 바꿀 수 있다.
var findNodes = function (callback, callback_obj) {
if (typeof callback === 'string') {
callback = callback_obj[callback];
}
if (typeof callback === "function") {
callback.call(callback_obj,found);
}
};함수는 객체이기 때문에 반환 값으로 사용될 수 있다. 즉, 함수의 실행 결과로 꼭 어떤 데이터 값이나, 배열을 반환할 필요는 없다는 뜻이다.
var setup = function() {
alert(1)
return function() {
alert(2)
}
}
var my = setup()
my()함수는 동적으로 정의 할 수 있고, 변수에 할당 할 수 있다. 새로운 함수를 만들어 이미 다른 함수를 가지고 있는 변수에 할당하면, 새로운 함수가 이전 함수를 덮어 쓰게 된다.
var scareMe = function() {
alert('Boo')
scareMe = function() {
alert('Double Boo')
}
}
scareMe()
scareMe()이 패턴은 lazy function definition이라고도 불리는데, 최초 사용 시점 전까지 함수를 완전 정의 하지 않고 있다가 호출된 이후에는 더 게으르게 동작하기 때문이다.
장점으로는 함수가 어떤 초기화 준비 작업을 단 한 번만 수행하는 경우 유용하다. 단점으로는 자기 자신을 재정의한 이후에는 이전에 사용한 함수에 추가 되었던 프로퍼티를 모두 찾을 수 없다.
var seungdols = function() {
console.log('Boo')
seungdols = function() {
console.log('Double Boo')
}
}
seungdols.property = 'property'
var seungdols_company = seungdols
var seungho = {
nick: seungdols,
}
seungdols_company()
seungdols_company()
console.log(seungdols_company.property)
seungho.nick()
seungho.nick()
console.log(seungho.nick.property)
seungdols()
seungdols() //undefined즉시 실행 함수 패턴은 함수가 선언되자마자 실행되도록 하는 문법이다.
;(function() {
console.log('watch out')
})()JSLint는 위 패턴을 선호하는데, 보통 아래와 같이 사용해도 무방하다.
;(function() {
console.log('watch out')
})();(function(name) {
console.log('My ' + name)
})('seungdols')매개변수도 전달을 할 수 있으나, 되도록 즉시 실행 함수에 많은 매개변수를 전달 하는 것은 좋지 않다.
장점으로는 전역 변수를 남기지 않고, 많은 양의 작업을 가능하도록 해준다. 선언 된 모든 변수는 스스로를 호출 하는 (self-invoking) 함수의 지역 변수가 되어 임시 변수가 전역 공간에 할당 되지 않는다.
즉시 객체 초기화 패턴이라 불리며, 즉시 실행 함수와 유사하다.
;({
maxHeight: 1330,
maxWidth: 780,
getWidth: function() {
return this.maxWidth
},
getHeight: function() {
return this.maxHeight
},
init: function() {
console.log(this.getWidth())
console.log(this.getHeight())
},
}.init())일회성 작업에 적합하고, init()이 완료되고 나면, 객체에 접근 할 수 없다. 만약 객체의 참조를 유지하고 싶다면, init() 마지막에 return this;를 추가 하면 된다.
장점으로는 단 한 번의 초기화 작업을 실행 하는 동안 전역 네임스페이스 영역을 보호 할 수 있다.
단점으로는 자바스크립트 압축 도구가 즉시 실행 함수 패턴에 비해 덜 효율적인 압축을 한다는 것이다.
함수는 객체여서 프로퍼티를 가질 수 있는데, 이를 이용하여 함수에 프로퍼티를 추가하여 결과를 캐시하면, 다음 호출 시점에 복잡한 연산을 반복하지 않아도 되는 이점을 얻을 수 있다. 이를 Memoization이라 부른다.
var myFunc = function(param) {
if (!myFunc.cache[param]) {
var result = {}
//working
myFunc.cache[param] = result
}
return myFunc.cache[param]
}
myFunc.cache = {}물론, 더 많은 매개변수나 복잡한 타입을 갖는다면, JSON 문자열로 직렬화하고, 이 문자열을 cache 객체에 키로 사용 할 수 있다.
단, 직렬화 하면 객체를 식별 할 수 없게 되는 단점이 존재한다.
설정 객체 패턴은 좀 더 깨끗하게 API를 제공하는 방법이다.
초기에는 어떤 함수가 단순 했다고 가정하자.
function addPerson(first, last) {}
function addPerson(first, median, date, last) {}이렇게 유지보수 하다보면, 매개변수가 늘어 날 수 있다. 이 때 사용하는 방법이 설정 객체 패턴이다.
var conf = {
first: 'seungdols',
median: 'seungseung',
last: 'jojoldu',
}
addPerson(conf)순수한 함수형 프로그래밍 언어에서 함수는 불려지거나 호출된다고 표현하는 것보다 적용 된다고 표현한다.
자바스크립트에서도 Function.prototype.apply()를 사용하면 함수를 적용할 수 있다.
var sayHi = function(who) {
return 'Hello' + (who ? ',' + who : '') + '!'
}
sayHi()
sayHi('world')
sayHi.apply(null, ['hello'])예제에서 확인이 가능하듯이 함수의 호출이나, 함수의 적용의 결과는 같다.
apply()는 2개의 매개변수를 받는데, 첫번째는 함수내 this와 바인딩할 객체이고, 두번째는 배열 또는 인자로 함수 내부에서 배열과 비슷한 형태의 arguments 객체로 사용한다.
var seungdols = {
sayHi: function(who) {
return 'Hello' + (who ? ',' + who : '') + '!'
},
}
seungdols.sayHi('world')
sayHi.apply(seungdols, ['company'])위 처럼 함수가 객체의 메서드일 때의 예시이다.
seungdols를 전달하게 되면, 해당 함수내의 this는 seungdols에 바인딩이 된다.
원래는 apply로 함수를 적용하는 방법이 더 직관적일 수도 있다는 생각이 든다…물론, 인자를 하나만 가지고도 해결 할 수 있다면, call() 메서드도 있다는 것을 기억하자!!
sayHi.apply(seungdols, ['company'])
sayHi.call(seungdols, 'company')위 처럼 call()을 이용하는 것이 더 편리할 수도 있다.
함수의 일부만 적용하는 것이 가능할까? 수학에서도 볼 법한 내용이지만, 실제로 가능하다.
var add = function(x, y) {
return x + y
}
add.apply(null, [5, 4])
var newadd = add.partialApply(null, [5])
newadd.apply(null, [4])위 처럼 partialApply() 메소드가 있다는 걸로 가정하고, 5 + 4를 부분적으로 적용 할 수 있는 함수를 머릿속으로 생각만 해보자. 이러한 방법을 써먹을 수 있을까? 자바스크립트에서는 자유도가 높기에 이러한 기능을 하는 함수를 구현 할 수 있다. 함수가 부분적인 적용을 이해하고 처리 할 수 있도록 만드는 과정을 커링이라고 한다.
다른 함수형 언어에서는 커링이 언어 자체에 내장 되어 모든 함수가 커링 된다. 자바스크립트는 약간의 기교를 추가하면 커링이 가능하게끔 할 수 있다.
function add(x, y) {
var oldx = x,
oldy = y
if (typeof oldy === 'undefinded') {
return function(newy) {
return oldx + newy
}
}
return x + y
}
typeof add(5)
add(3)(4)
var add2000 = add(2000)
add2000(10)위 코드를 조금만 살펴보면, add 함수에서 리턴하는 내부 함수에 클로저가 생성 된다. 부분 적용이 없이 값이 둘 다 전달 되면, 단순히 두 값을 더한다. 실제로 위 코드를 조금 더 간략하게 만들 수는 있다.
function add(x, y) {
if (typeof y === 'undefined') {
//부분 적용
return function(y) {
return x + y
}
}
return x + y //전체 인자 적용
}이러한 방식으로 커링을 만들어 볼 수 있다.
심화로 범용적으로 사용 할 수 있는 커링 함수를 만들어 본다면, 아래와 같다.
function schonfinkelize(fn) {
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1)
return function() {
var new_args = slice.call(arguments),
args = stored_args.concat(new_args)
return fn.apply(null, args)
}
}
function add(x, y) {
return x + y
}
var newadd = schonfinkelize(add, 5)
newadd(4)
schonfinkelize(add, 1)(3)
//2단계 커링
var addOneCurry = schonfinkelize(add, 3)
addOne(10, 20, 30, 40)
var addTwoCurry = schonfinkelize(addOneCurry, 2, 3, 4, 5)
addTwoCurry(45, 4)API패턴 : 함수에 더 좋고 깔끔한 인터페이스를 제공할 수 있게 돕는다.
초기화 패턴
성능 패턴
네임스페이스 패턴을 사용함으로써 전역 변수를 줄 일 수 있는 패턴으로 흔히 사용한다.
var SH = {}
SH.Parent = function() {}
SH.Child = function() {}
SH.seungdols = 1
SH.hello_module = {}
SH.hello_module.korean_hello = {}
SH.hello_module.korean_hello.data = { HI: '안녕하세요 ?', Hello: '안녕?' }
SH.hello_module.english_hello = {}전역 네임스페이스 객체의 이름은 보통 어플리케이션 이름이나 라이브러리의 이름, 도메인명, 회사 이름 중에서 선택하여 사용하곤 한다. 보통 전역 객체 이름은 모두 대문자로 쓰는 명명 규칙을 사용한다.
장점
단점
var SH = {} //이렇게 쓰면, 기존에 있는 이름과 충돌 가능성이 높다.
if (typeof SH === 'undefined') {
//개선안
var SH = {}
}
var SH = SH || {}기존 코드를 망가뜨리지 않고, 네임스페이스를 만드는 네임스페이스 함수를 구현 할 수 있다.
var SH = SH || {}
SH.namespace = function(ns_string) {
var parts = ns_string.split('.'),
parent = SH,
i
if (parts[0] === 'SH') {
parts = parts.slice(1)
}
for (i = 0; i < parts.length; i += 1) {
if (typeof parent[parts[i]] === 'undefined') {
parent[parts[i]] = {}
}
parent = parent[parts[i]]
}
return parent
}위 함수를 가지고 네임스페이스를 안전하게 만들 수 있다.
SH.namespace('SH.modules.hello')자바스크립트에는 private, protected, public 프로퍼티와 메서드를 나타내는 별도 문법적인 방법이 없으나, 클로저를 이용해 비공개 멤버를 구현 할 수 있다.
function private_member() {
var sh = 'seungdols'
this.getSH = function() {
//특권 메서드(privileged method)
return sh
}
}
var seungdols = new private_member()
console.log(seungdols.sh) //접근 안됨.
console.log(seungdols.getSH) //접근 됨.객체 리터럴로 만드는 방법
var myobj = (function() {
var name = 'seungdols'
return {
getName: function() {
return name
},
}
})()자바스크립트에서 클로저를 활용한 비공개 멤버를 쉽게 구현 할 수 있다.
비공개 멤버의 허점
생성자를 사용해 비공개 멤버를 만들 경우 생성자를 호출하여 새로운 객체를 만들기 때문에 비공개 멤버가 매번 재생성 된다는 단점이 있다. 이를 해결하려면, 공통 프로퍼티와 메서드를 생성자의 prorotype 프로퍼티에 추가해야 한다. 이렇게 하면, 감춰진 비공개 멤버들도 모든 인스턴스가 함께 쓸 수 있다. 이를 위해서는 , 생성자 함수 내부에 비공개 멤버를 만드는 패턴과 객체 리터럴로 비공개 멤버를 만드는 패턴을 함께 써야 한다.
function Seungdols() {
var name = 'seungdols'
this.getName = function() {
return name
}
}
Seungdols.prototype = (function() {
var browser = 'Chrome'
return {
getBrowser: function() {
return browser
},
}
})()
var sh = new Seungdols()
console.log(sh.getName())
console.log(sh.getBrowser())노출 패턴은 비공개 메서드를 구현하면서 동시에 공개 메서드로도 노출하는 것을 말한다.
var SH
;(function() {
var isEmpty = false
function isEmpty() {
//
}
function isNotEmpty() {
//
}
SH = {
isEmpty: isEmpty,
isNotEmpty: isNotEmpty,
}
})()마지막 부분에서 접근을 허용해도 괜찮은 부분에 대해 SH 객체에 추가해준다. 즉, SH를 통해서는 공개 메서드가 되나, 다른 부분에서는 비공개 멤버가 된다.
늘어나는 코드를 구조화하고, 정리하는데 도움되는 패턴이다. 이 패턴을 이용하면, 개별적인 코드를 느슨하게 결합시킬 수 있다. 모듈패턴은 여러개의 패턴을 조합한 것을 말한다.
SEUNGDOLS.namespace('SEUNGDOLS.utilites.ArrayUtils')
SEUNGDOLS.utilities.ArrayUtils = (function() {
//의존 관계
var obj = SEUNGDOLS.utilities.object,
lang = SEUNGDOLS.utilities.lang,
array_string = '[object Array]',
tos = Object.prototype.toString
//비공개 메서드
//...
//var 선언 끝
//일회성 초기화 실행
//...
//공개 API
return {
//1
//2
}
})()모듈 패턴은 점점 늘어가는 코드를 정리 할 때 널리 사용하며, 추천 되는 방법이다.
참고
모듈을 감싼 즉시 실행 함수에 인자를 전달하는 형태가 있는데, 보통 전역 변수에 대한 참조 또는 전역 변수 자체를 전달한다. 이렇게 전달을 하게 되면, 탐색작업이 좀 더 빨라진다.
SEUNGDOLS.utilities.module = (function(app, global) {
//
//
})(SEUNGDOLS, this)네임스페이스 패턴의 단점을 해결해주는 패턴이다. 더군다나 전역 네임스페이스를 보호해주는 역할을 한다. (아직 이해가 잘…)
function Sandbox() {
var args = Array.prototype.slice.call(arguments),
callback = args.pop(),
modules = args[0] && typeof args[0] === 'string' ? args : args[0],
i
//함수가 생성자로 생성되도록 보장
if (!(this instanceof Sandbox)) {
return new Sandbox(modules, callback)
}
//this에 필요한 프로퍼티들을 추가
this.a = 1
this.b = 2
// core this 객체에 모듈 추가
if (!modules || modules === '*' || modules[0] === '*') {
modules = []
for (i in Sandbox.modules) {
if (Sandbox.modules.hasOwnProperty(i)) {
modules.push(i)
}
}
}
//필요한 모듈들 초기화
for (i = 0; i < modules.length; i += 1) {
Sandbox.modules[modules[i]](this)
}
callback(this)
}
Sandbox.prototype = {
name: 'seungdols Application',
version: '1.0',
getName: function() {
return this.name
},
}
Sandbox('dom', 'hello', function() {
console.log('hello')
})스태틱 프로퍼티와 메서드란 인스턴스에 따라 달라지지 않는 프로퍼티와 메서드를 말한다. 자바스크립트 언어에서는 스태틱 멤버를 지칭하는 문법이 지원 되지 않는다. 하지만, 생성자에 프로퍼티를 추가하여 구현할 수 있다.
var Gadget = function() {}
Gadget.isShiny = function() {
return 'you bet'
}
Gadjet.prototype.setPrice = function(price) {
this.price = price
}위처럼 코드를 작성하면, 위험한 점이 존재하게 된다. Gadget.isShiny()를 호출 하면, 내부의 this는 Gadget 생성자를 가리키지만, 아래 코드에서는 위험하다.
var iphone = new Gadget()
iphone.setPrice(1000)
typeof Gadget.setPrice
typeof iphone.isShiny스태틱 메서드가 인스턴스를 통해 호출 했을 때도 동작한다면, 편리한 경우가 있을 수 있는데, 이 때는 프로토타입에 메서드를 추가 하는 것만으로도 가능하다. 그러나, 문제가 포함되어 있다.
스태틱 메서드 안에서 this를 사용할 떄 주의해야 한다. Gadget.isShiny()를 호출했을 떄는 isShiny()는 가젯 생성자를 가리키지만, iphone, isShiny()를 호출 했을 때는 this가 iphone을 가리키게 된다.
먼저 클로저 함수를 만들고, 비공개 멤버를 이 함수로 감싼 후, 이 함수를 즉시 실행한 결과로 새로운 함수를 반환하게 한다.
var Gadget = (function() {
var counter = 0
return function() {
console.log((counter += 1))
}
})()실제로 카운터 값을 인스턴스끼리 공유하는 것을 확인 할 수 있다.
객체에 연쇄적으로 메서드를 호출 할 수 있도록 하는 패턴이다.
양날의 검인듯 하지만, 알아 두면 좋을 듯한 패턴이다. 메서드에서 return 할 때에 this를 리턴하면 체이닝이 가능해진다.
더글라스 크락포드가 고안한 클래스 기반의 언어에 적응한 사람들이 메서드를 구현하는 방식을 고안했다. 허나 이 방법을 추천하지는 않는다.
생성자 본문 내에 인스턴스 프로퍼티를 추가 할 수 있다. 그러나 this에 인스턴스 메서드를 추가하게 되면, 인스턴스 마다 메서드가 재생성 되어 메모리를 잡아 먹어 비효율적이다.
if (typoef Function.prototpye.method !== "function") {
Function.prototype.method = function(name, implementation) {
this.prototype[name] = implementation;
return this;
};
}