Skip to content

Latest commit

 

History

History
executable file
·
284 lines (240 loc) · 6.84 KB

9. function - etc .md

File metadata and controls

executable file
·
284 lines (240 loc) · 6.84 KB

9. function - etc.

9-1. name property of function

// 기명함수의 함수선언식
function a () { }
console.log(a.name) // a

// 아래 익명함수의 경우 name propery에 값이 할당되면 안되지만
// 브라우저들이 편의를 위해 자동으로 nmae 값 할당
// es6 부터 앞에있는 변수명을 name property에 할당하는 것으로 규칙 설정 
const b = function () { }
console.log(b.name)

// 기명함수가 표현식형태로 변수에 할당됬을 때는
const c = function cc () { }
console.log(c.name) // cc

// 화살표 함수도 변수를 name property에 할당한다
const d = () => {}
console.log(d.name) // d 

// 메소드도 마찬가지
const e = {
  om1: function () {},
  om2 () {},
  om3: () => {}
}
console.log(e.om1.name, e.om2.name, e.om3.name) //om1 om2 om3


// 이전 프로토 타입 방식에서는 지원 안됨
function G(){};
G.method1 = function(){};
G.prototype.method2 = function(){}
const g = new G();
console.log(G.method1.name, g.method2.name) // "", ""

// 클래스는? 스테틱 메소드, 프로토타입 메소드 둘다 동일하게 지원
class F {
  static method1 () {}
  method2 () {}
}
const f = new F()
console.log(F.method1.name, f.method2.name)//method1, method2
// 함수 생성자 활용해보기 
const f = function (a,b) {return a + b;}
// 마지막 인자로 블록문의 내용을 전달
const g = new Function('a', 'b', 'return a+b')

const g = new Function()
console.log(g.name)
// bind 의 경우 어떤 함수와 binding 되었는지 명시적으로 표시
function a () { }
const b = function () { }
const h = a.bind(b)
console.log(h.name) // bound a (b가 아니다)

// 잠깐 bind 활용 돌아보기 
function a (x,y,z) {console.log(this, x, y, z);}
const b = a.bind({}, 1,2) // 첫번째 this, 두번째부터 인자들
b(3) // 3번째 z 인자만 넘겨주고 실행하면 
// this, 1, 2, 3
//getter, setter 의 경우에도 nmae 프로퍼티가 명시적으로 나오게 됨
const person = {
  _name: '재남',
  get name () {
    return this._name
  },
  set name (v) {
    this._name = v
  }
}
const descriptor = Object.getOwnPropertyDescriptor(person, 'name')
console.log(descriptor.get.name) // get name
console.log(descriptor.set.name) // set name

9-2. new.target

  • 여기서 new는 객체가 아니다. new.target 자체가 하나의 값이다.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new.target

// 생성자 함수를 일반 함수처럼 사용하지 못하게 방어하는 코딩방법
function Person (name) {
  if (this instanceof Person) { // new 키워드와 함께라면 this가 새로 생성될 instance를 가르킴
    this.name = name
  } else { // 일반함수라면 this 는 window를 가르키고, 결국 에러발생
    throw new Error('new 연산자를 사용하세요.')
  }
}
// 정상
var p1 = new Person('재남')
console.log(p1)

// 에러
var p2 = Person('성훈')
console.log(p2)

// 에러
var p3 = Person.call({}, '곰')
console.log(p3)

// p1 은 Person의 instance 이기 때문에 정상작동
// 여기가 바로 우회수단이다!!
var p4 = Person.call(p1, '곰')
console.log(p4) //곰
console.log(p1) //곰 this가 p1을 가르켰고 name에 곰이 할당됬다.

// 어떻게 해결할까?
// 위의 new 연산자 사용을 강제하기 위한 방법을 보다 명시적으로 하기 위해 new.target 등장 

function Person (name) {
  console.dir(new.target)
  if (new.target !== undefined) {
    this.name = name
  } else {
    throw new Error('new 연산자를 사용하세요.')
  }
}

// 정상 작동
const p1 = new Person('재남') // new.target == Person || undefined
console.log(p1)

// 에러
const p2 = Person('성훈')
console.log(p2)

// 에러
const p3 = Person.call({}, '곰')
console.log(p3)

// 에러 드디어 우회를 막았다
const p4 = Person.call(p1, '곰')
console.log(p4)
 // arrow function 은 this, new.target, agrument 를 bind 하지 않는다. 
function Person (name) {
  const af = n => {
    this.name = n
    console.log(new.target)
  }
  af(name)
}
const p1 = new Person('재남') // arrow function의 new.target도 역시 Person 이 나옴
const p2 = Person('성훈')
// 이전의 우회방법
function Person (name) {
  this.name = name  
}
function Android (name) {
  Person.call(this, name)
}

// new.target === Android, 이기 때문에 오류 발생 x
const p1 = new Android('재남봇')
// 안전장치 걸기
function Person (name) {
  console.log(new.target)
  if (new.target === Person) { //undefined 보다 명시적으로 사용하기
    this.name = name
  } else {
    throw new Error('Person 생성자함수를 new로 호출해야 해요!')
  }
}
function Android (name) {
  Person.call(this, name)
}
const p2 = new Android('재남봇')
// class의 상속에서 더 의미를 가지는 new.target

// new A 로는 활용할 수 없도록 제한 걸기
// javascript에서는 추상클래스(<-> 구체클래스)가 없기 때문에 이런 로직이 필요함 

class A { // 추상 클래스처럼 흉내내기 
  constructor () {
    if (new.target === A) throw new Error("A는 추상클래스 입니다.")
    console.log(new.target)
  }
}

class B extends A {
  constructor () {
    super()
  }
}

const b = new B();
const a = new A();

9-3. 블록스코프 내에서의 함수 선언과 호이스팅 (브라우저 비교)

  • stric mode 가 아닌 경우 sloppy mode에서는 브라우저마다 다른 동작이 발생한다. 예상이 불가능하다.
  • strinc mode의 경우에는 함수선언문도 block scope 에 갇히게 된다.
  • es6 에서는 함수선언문을 쓰지말자
    • 기본적으로 arrow function을 쓰자
    • 객체 내부에서는: 메소드 축약형을 쓰자
    • prototype과 관련해서는 class를 쓰자
    • 그러면 나머지 generator 에서 function* 형태로만 볼 수 있다.
    • 오롯이 function만 있는 키워드가 등장할 일 자체가 없다.
// 함수 선언문은 let과 const 가 아니기 때문에 block에 갇히지 않고 hoisting 된다. 여전히 function scope인 것
if (true) {
  a() 
  function a () { console.log(true) }
}
a()
// true
// true
// 그럼 이것도 되야하는데 이건 에러가 난다. 왜 그럴까? 
// 이건 브라우저 별로 다르다. 크롬 -> 에러, firefox, safari -> 정상 작동, 
a()
if (true) {
  a()
  function a () { console.log(true) }
}
if (true) {
  a()
  function a () { console.log(true) }
  if (true) {
    a()
    function a () { console.log(false) }
  }
}
a()
'use strict'
if (true) {
  a()
  function a () { console.log(true) }
  if (true) {
    a()
    function a () { console.log(false) }
  }
}
a()
// use stric 키워드를 쓰면 함수 선언이 block socpe에 갇히게 된다.
'use strict'
if (true) {
  function a () { console.log(true) }
  a()
}
a()