JavaScript 3일차 생성자함수, 상속, 배열+배열 함수 + 엄격모드(알아서공부)
목차
상속
proto , prototype
배열
push , pop , indexof , lastindexof, includes , shift , unshift
slice , splice , reverse
배열 고차함수
sort, map , foreach , filter , concat , reduce , some , every
생성자함수 / 일반함수
//Object 생성자함수
const student = new Object(); // 빈 객체 생성
student.name = '이대엽'; // 프로퍼티 추가
student.age = 27;
console.log(student);
//결과
{ name: '이대엽', age: 27 }
// 생성자 함수 (리터럴 ?? ㅁㄹ)
const student1 = { // 프로퍼티 값을 하나하나...
name : '이이대엽',
age : 28,
getInfo : function () {
return `${this.name} 은 ${this.age} 살 입니다~`
}
}
const student2 = { // 프로퍼티 값을 하나하나... (리터럴 단점)
name : '22대엽',
age : 22,
getInfo : function () {
return `${this.name} 은 ${this.age} 살 입니다~`
}
}
‘리터럴’ 은 변수에 할당하는 고정 형태의 값입니다.
int a 우항에 놓이는 1 int a = 1; var empty_object 우항에 놓이는 {} **var** empty_object = {} //빈 객체 와 같이 표기한 문자가 있는 그대로 자신을 나타내는 값이죠.
이것이 진짜 생성자 함수
// 리턴을 명시하지 않아도된다. 기본으로 빈 객체가 반환 된다 (고민? 좀 해볼만할지도)
// new 를 사용해서 함수를 호출했을때 이야기이다 !!!!!!!!!!! (암묵적인 return이 있다. )
// 일반함수처럼 사용하면 눈에 보이는대로 return이 없다.
// ( 첫글자를 대문자로 작성해야함. 작성자가 스스로 지켜야하는 컨벤션)
function Sstudent(name, age) {
this.name = name;
this.age = age;
this.getInfo = function () {
return `${this.name} 은 ${this.age} 살 입니다~`
}
}
const sstudent = Sstudent('유재', 30);
// const sstudent = new Sstudent('유재', 30);
console.log(sstudent);
// 결과
undefined
// 해석
new Sstudent(~~ ) 가 아닌 일반함수처럼 Sstudent(~~) 를 호출 했기 때문에
return 된게 아무것도 없기 때문이다.
target - new 연산자 없이 호출되는것을 방지하기 위해 지원하는 함수
function Dog(name, age) {
// 일단 타겟이 뭐하는 넘인가?
// new 연산자 없이 호출되는것을 방지하기 위해 지원하는 함수 (new.target)
// 내부는 undefined 이다
console.log(new.target); // [Function: Dog]
// 생성자목적으로 만들경우
if(!new.target){
return new Dog(name, age);
}
this.name = name;
this.age = age;
}
const dog = Dog('ㅃㅃ', 3);
console.log(dog);
// 결과
[Function: Dog]
Dog { name: 'ㅃㅃ', age: 3 }
개발자의 실수를 방지하기 위해(?) 만들어진 함수라고 생각중 입니다
상속!!!!!!!!!!! (한 번도 써본적은 없음 )
const user = {
activate : true,
login : function(){
console.log('로그인 되었습니다.');
}
};
const student = {
passion : true
};
student.__proto__ = user;
console.log(student.activate);// 프로퍼티 activate를 student에서도 사용 가능
student.login();// 메소드 login도 student를 통해 호출 가능console.log(student.passion);
- 'student의 프로토타입은 user이다.' 혹은 'student는 user를 상속 받는다.' 라고 한다.
- 프로토타입에서 상속받은 프로퍼티를 상속 프로퍼티(inherited property)라고 한다.
내용이 너무 심오하다 …
그냥 아무 연관이 없는 객체 두 개를 만들고 뜬금없이 프로퍼티를 호출 하면 상속이 된다고하니 ..
아무 연관이 없는게 아니었다
__proto__ 라는 프로퍼티(key) 값에 user 라는 value 를 넣어서
student 는 user를 상속받는다 라는 선언이 되어있는것이었다.
' student.__proto__ = user; ' 바로 이 문장
const user = {
activate : true,
login : function(){
console.log('로그인 되었습니다.');
}
};
const student = {
passion : true
};
const greedyStudent = {
class : 11,
__proto__ : student // set, get 역할을 한다?? student 만 바라보게 하는건가 ??
};
console.log(greedyStudent.activate); // user에서 상속
console.log(greedyStudent.passion); // student에서 상속
//결과
undefined
true
student 객체 선언에 ' __proto__ : user ' 가 적혀 있었으면 undefined 안나왔음
const user = {
id : 'user',
login : function(){
console.log(`${this.id}님 로그인 되었습니다.`);
}
};
const student = {
__proto__ : user
};
student.id = 'user01';
student.login(); // user01님 로그인 되었습니다.
- 프로토타입은 프로퍼티를 읽을 때만 사용하며 프로퍼티를 추가, 수정, 삭제하는 연산은 객체에 직접 한다.
- 메소드 내의 this는 프로토 타입에 영향받지 않으며 메소드를 객체에서 호출했든 프로토타입에서 호출했든 상관없이 this는 언제나 .앞에 있는 객체이다.
( . 앞에 있는 객체 = [student] . << 여기 앞 말하는듯? login() )
- 메소드는 공유되지만 객체의 상태는 공유되지 않는다.
for...in문은 열거 가능한 non-Symbol 속성에 대해서만 반복합니다.
이것은 쉽게 객체의 속성을 확인(콘솔이나 다른 방법으로 출력)할 수 있기 때문에 실질적으로 디버깅을 위해 사용될 수 있습니다.
배열이 데이터의 저장에 있어서는 더 실용적이지만, 키-값 쌍이 선호되는 데이터의 경우(속성이 "key"의 역할을 함)
특정 값을 가진 키가 있는지 확인하려는 경우에 for...in을 사용할 수 있습니다
const user = {
testprop : 'test1',
activate : true,
login : function(){
console.log('로그인 되었습니다.');
}
};
const student = {
passion : true,
__proto__ : user
};
const greedyStudent = {
class : 11,
__proto__ : student // set, get 역할을 한다?? student 만 바라보게 하는건가 ??
};
// ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
for(let prop in greedyStudent) {
console.log(`ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ2`);
console.log(prop);
// key에 대응하는 프로퍼티가 상속 프로퍼티가 아니고 obj에 직접 구현되어있는 프로퍼티일 때만 true를 반환한다.
let isOwn = greedyStudent.hasOwnProperty(prop);
if(isOwn) {
console.log(`객체 자신의 프로퍼티 ${prop}`);
// greedyStudent.hasOwnProperty.
} else {
console.log(`상속 프로퍼티 ${prop}`);
}
}
//결과
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ2
class
객체 자신의 프로퍼티 class
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ2
passion
상속 프로퍼티 passion
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ2
testprop
상속 프로퍼티 testprop
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ2
activate
상속 프로퍼티 activate
ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ2
login
상속 프로퍼티 login
자신의 프로퍼티 순회 후 상속된 객체의 프로퍼티를 끝까지 순회 한다
키 값을 출력한다.
함수형 프로토타입(상속)
const user = {
activate : true,
login : function(){
console.log('로그인 되었습니다.');
}
};
// 생성자 함수
function Student(name) {
this.name = name;
}
// 여기서의 prototype은 일반적인 프로퍼티 (일반적인? 무엇이?.. 이해가 잘 안되었음)
// 프로토타입(상속) 을 정의
//const student = {
// name : 'name',
// __proto__ (= prototype) : user
//};
Student.prototype = user;
let student = new Student("홍길동");
console.log(student.activate);
//결과 ( user 의 activate 값 )
true
- new 연산자를 사용해 만든 객체는 생성자 함수의 프로토타입 정보를 사용해 [[Prototype]]을 설정한다.
- F.prototype은 new F를 호출할 때만 사용된다. new F를 호출할 때 만들어지는 새로운 객체의 [[Prototype]]을 할당한다.
function Student() {}
// 함수를 만들기만 해도 디폴트 프로퍼티인 prototype이 설정
// Student.prototype = { constructor: Student }
console.log(Student.prototype.constructor);
console.log(Student.prototype.constructor == Student);
let student = new Student(); // // {constructor: Student}을 상속받음
console.log(student.constructor == Student); // true ([[Prototype]]을 거쳐 접근함)
// 결과
[Function: Student]
true
true
- 개발자가 특별히 할당하지 않더라도 모든 (생성자?)함수는 기본적으로 "prototype" 프로퍼티를 갖는다.
- 디폴트 프로퍼티 "prototype"은 constructor 프로퍼티 하나만 있는 객체를 가리키는데, 여기서 constructor 프로퍼티는 함수 자신을 가리킨다.
이거는 이해하고 작성한건 아닙니다
느낌은 알겠음 하지만 논리적으로는 모르겠음
built in object prototype
const num = new Number(100);
// num은 Number.prototype을 상속받았는가?
console.log( num.__proto__ === Number.prototype ); // true
// num은 Object.prototype을 상속받았는가?
console.log( num.__proto__.__proto__ === Object.prototype ); // true
// 체인 맨 위엔 null이 있다.
console.log( num.__proto__.__proto__.__proto__ ); // null
// Number.prototype의 toString 사용
console.log(num); // [Number : 100]
console.log(num.toString()); // 100
- Function, String, Number을 비롯한 내장 객체들 역시 프로토타입에 메서드를 저장한다.
- 모든 내장 프로토타입의 상속 트리 꼭대기엔 Object.prototype이 있어야 한다고 규정한다.
- Object.prototype에도 메서드 toString이 있다
- 중복 메서드가 있을 때는 체인 상에서 가까운 곳에 있는 메서드가 사용된다.
배열 (자바스크립트의 배열)
// 1. 배열 리터럴을 통해 배열 생성
const arr = ['바나나', '복숭아', '키위'];
//전달된 인수값이 1개, 숫자 >> length 만큼 배열 생성
const arr3 = new Array(10);
console.log(arr3); // [ <10 empty items> ]
// 인수값이 2개 이상이거나 , 숫자가 아닌경우 인수를 요소로 갖는 배열 생성
const arr4 = new Array(1,2,3,4,5);
console.log(arr4); // [ 1, 2, 3, 4, 5 ]
// Array.of 메소드 = 전달 된 인수를 요소로 갖는 배열 생성
console.log(Array.of(10)); // [ 10 ]
let testArr = Array.of(1,2,3);
console.log(testArr); // [ 1, 2, 3 ]
const arr6 = [1,2,3,4,5];
arr6.push(6); // 마지막 인덱스로 값 추가
arr6.pop(); // 마지막 인덱스 제거 (원본 영향 o)
const sparse = [,2 , , 4]; // 구멍 숭숭 내도 만들어짐
console.log(sparse); //[ <1 empty item>, 2, <1 empty item>, 4 ]
console.log(sparse.length); // 4
console.log('프로퍼티 정보');
console.log(Object.getOwnPropertyDescriptors(sparse));
//결과
{
'1': { value: 2, writable: true, enumerable: true, configurable: true },
'3': { value: 4, writable: true, enumerable: true, configurable: true },
length: { value: 4, writable: true, enumerable: false, configurable: false }
}
'인덱스' : { 상세 정보 }
writable – true이면 값을 수정할 수 있다. 그렇지 않다면 읽기만 가능하다.
enumerable – true이면 반복문을 사용해 나열할 수 있다. 그렇지 않다면
반복문을 사용해 나열할 수 없다.
configurable – true이면 프로퍼티 삭제나 플래그 수정이 가능하다.
함수 메소드
indexof , lastindexof, includes
const foodList = ['물회', '삼계탕', '냉면', '수박', '물회'];
// indexOf : 요소가 위치한 인덱스 반환
console.log(`foodList.indexOf('물회') : ${foodList.indexOf('물회')}`);
// 0
console.log(`foodList.indexOf('물회', 1) : ${foodList.indexOf('물회', 3)}`);
// n번 인덱스 이후로 검색
console.log(`foodList.indexOf('삼겹살') : ${foodList.indexOf('삼겹살')}`);
// 없으면 -1 반환
// lastIndexOf : 요소가 위치한 마지막 인덱스 반환
console.log(`foodList.lastIndexOf('물회') : ${foodList.lastIndexOf('물회')}`);
// 4
console.log(`foodList.lastIndexOf('물회', 1) : ${foodList.lastIndexOf('물회', 1)}`);
// 0 n번 인덱스부터 0까지 거꾸로 찾는것같음
console.log(`foodList.lastIndexOf('삼겹살') : ${foodList.lastIndexOf('삼겹살')}`);
// 없으면 -1 반환
// includes 포함여부
console.log(`foodList.includes('물회') : ${foodList.includes('물회')}`);
// true
console.log(`foodList.includes('삼겹살') : ${foodList.includes('삼겹살')}`);
// false
unshift , shift
//Array.prototype.unshift : 배열의 맨앞 요소 추가
//Array.prototype.shift : 배열의 맨앞 요소 제거 후 반환
const chickenList = ['양념치킨', '후라이드', '반반'];
chickenList.unshift('간장치킨');
console.log(chickenList); // [ '간장치킨', '양념치킨', '후라이드', '반반' ]
chickenList.shift();
chickenList.shift();
chickenList.shift();
console.log(chickenList); //[ '반반' ]
concat
// Array.prototype.concat : 두 개 이상의 배열을 결합
const idol1 = ['아이브', '오마이걸'];
const idol2 = ['트와이스', '에스파'];
const idol3 = ['블랙핑크', '레드벨벳'];
// 배열명.concat(배열명1, 배열명2, ...)
const mix = idol1.concat(idol2);
const mix2 = idol3.concat(idol1, idol2);
console.log(`idol1 기준으로 idol2 배열을 concat : ${mix}`);
// idol1 기준으로 idol2 배열을 concat : 아이브,오마이걸,트와이스,에스파
console.log(`idol3 기준으로 idol1, idol2 배열을 concat : ${mix2}`);
// idol3 기준으로 idol1, idol2 배열을 concat :
// 블랙핑크,레드벨벳,아이브,오마이걸,트와이스,에스파
// 블핑 레드벨벳 트와이스는 ㅇㅈ
slice , splice , reverse
// Array.prototype.slice : 배열의 요소 선택 잘라내기
// Array.prototype.splice : 배열의 index 위치의 요소 제거 및 추가
const front = ['HTML', 'CSS', 'JavaScript', 'jQuery'];
//slice (시작인덱스, 종료인덱스) 1번에서 3번 앞에놈 까지 넥슬라이스
console.log(`front.slice(1,3) : ${front.slice(1,3)}`);
console.log(front);
// splice (index, 제거수, 추가값) 3번 뒤에 1놈 자르고 "내용추가"
console.log(`front.splice(3,1,"react") : ${front.splice(3,1,"react")}`);
console.log(front);
// Array.prototype.reverse : 배열의 순서 뒤집기
console.log(`${[1,2,3,4,5].reverse()}`);
고차메소드
sort 를 사용하는 방법 - MDN 문서
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
그냥 sort 함수는 유니코드 기준으로 비교하기 때문에 숫자 비교에는 부적합한 함수다.......
sort
let numbers = [];
for (let i = 0; i < 10; i++) {
numbers[i] = Math.floor(Math.random() * 100) + 1; // 1부터 100까지 소수점 다 버리기?
}
// 무작위 난수 생성 정렬 드가자 !!!
function compare(a,b) {
if(a > b) return 1;
if(a == b) return 0;
if(a < b) return -1;
}
// sort 함수의 인자로 반환값이 1, 0 , -1 인 정렬함수를 이용해야한다.
// MDN 에게 물어보세요
numbers.sort(compare);
console.log(`정렬 후 : ${numbers}`);
// function(a,b) return b - a; ( 양수값이면 a>b 음수값이면 a<b 라는 뜻)
numbers.sort((a,b) => b - a );
console.log(`내림차순 : ${numbers}`);
// function(a,b) return a - b; ( 양수값이면 a>b 음수값이면 a<b 라는 뜻)
numbers.sort((a,b) => a - b );
console.log(`오름차순 이해완료 : ${numbers}`);
foreach
numbers = [1,2,3,4,5];
numbers.forEach(function (item, index, array) {
// 배열의 요소에 각각 실행할 기능을 작성, 각 요소에 대해 콜백을 실행, 배열을 순회하기때문에 break 사용 불가
// 반환값 없음 , 배열 전용 함수이군요
console.log(`item : ${item}`);
console.log(`index : ${index}`);
console.log(`array : ${array}`);
})
결과
item : 1
index : 0
array : 1,2,3,4,5
item : 2
index : 1
array : 1,2,3,4,5
item : 3
index : 2
array : 1,2,3,4,5
item : 4
index : 3
array : 1,2,3,4,5
item : 5
index : 4
array : 1,2,3,4,5
map
// Array.prototype.map : 배열 요소 전체를 대상으로 콜백 함수 호출후
// 반환값들로 구성된 새로운 배열 반환
// 매개변수 return 값
const types = [true, 1, 'text'].map(item => typeof item);
console.log(`types : ${types}`);
// 매개변수 return 값
const lengths = ['apple', 'banana', 'cat', 'dog' , 'egg'].map(item => item.length);
console.log(`length : ${lengths}`);
// 결과
types : boolean,number,string
length : 5,6,3,3,3
filter
// Array.prototype.filter : 배열 요소 전체를 대상으로 콜백 함수 호출후
// 반환값이 true인 요소로만 구성된 새로운 배열 반환 // 원본에 영향 x
numbers = [1,2,3,4,5];
// 매개변수 return 값
const odds = numbers.filter(item => item % 2);
console.log(odds);
console.log(numbers); // 원본에 영향 x
// 결과
[ 1, 3, 5 ]
[ 1, 2, 3, 4, 5 ]
reduce ★★★★★★ 잠재력이 많은 함수인듯…
‘배열을 순회하며 ‘
각 요소에대해 이전의 콜백함수 실행 반환값을 전달하여 콜백함수를 실행하고 그 결과를 반환
(method) Array<number>.reduce(callbackfn:
(previousValue: number, currentValue: number, currentIndex: number, array: number[]) => number)
// Array.prototype.reduce :
// 배열을 순회하며 각 요소에대해 이전의 콜백함수 실행 반환값을
// 전달하여 콜백함수를 실행하고 그 결과를 반환
numbers = [1,2,3,4,5];
numbers.reduce(function (preValue, curValue, curIndex, array) {
console.log(`preValue : ${preValue}`); // 이전 콜백의 반환 값
console.log(`curValue : ${curValue}`); // 배열 요소의 값
console.log(`curIndex : ${curIndex}`); // 배열 요소의 인덱스
console.log(`array : ${array}`); // 메소드를 호출한 배열
}
// 이부분에 추가로 인자를 작성할 수 있다.
// 초기 값
);
reduce 합산
// 합산
numbers = [1,2,3,4,5];
const sum = numbers.reduce(function (preValue, curValue) {
console.log(`pre : ${preValue}, cur : ${curValue}`);
return preValue + curValue;
});
console.log(`sum : ${sum}`);
// 결과
pre : 1, cur : 2
pre : 3, cur : 3
pre : 6, cur : 4
pre : 10, cur : 5
sum : 15
reduce 최대값
//최대값
numbers = [1,2,3,4,5];
const max = numbers.reduce(function(preValue, curValue){
return preValue > curValue ? preValue:curValue;
})
console.log(max); // 5
some
배열 내 ‘일부’ 요소가 콜백 함수의 테스트를 통과하는지 확인하여 그 결과를 boolean 으로 반환
// Array.prototype.some :
// 화살표 함수 좀 안썼으면 좋겠다 !!!!!!!!!!!
let result = [1,5,2,3,4].some(item => item > 10);
console.log(`result : ${result}`); // result : false
let result1 = [1,5,2,3,4].some(item => item > 3);
console.log(`result1 : ${result1}`); // result1 : true
result = ['apple', 'banana', 'cat', 'dog'].some(item => item === 'egg')
console.log(`result : ${result}`); // result : false
▼ 약간 SQL문의 ANY , ALL 느낌 △
some every
every
배열 내 ‘모든’ 요소가 콜백 함수의 테스트를 통과하는지 확인하여 그 결과를 boolean으로 반환
// Array.prototype.every :
result = [1,5,2,3,4].every(item => item > 3);
console.log(`result : ${result}`); // result : false
result1 = [1,5,2,3,4].every(item => item > 0);
console.log(`result : ${result1}`); // result : true