2. JS์ ๋ค์ํ ๊ฐ ๋น๊ต์ ์์ ๋น๊ต, ๊น์ ๋น๊ต
๐ ๋ชฉํ
1.์์ํ์ ๊ณผ ์ฐธ์กฐํ์ ์ ๊ฐ๋ ์ ์ดํดํ๊ธฐ
2.๋ฆฌ์กํธ์์ ์ด๋ค์์ผ๋ก ๊ฐ๊ณผ ์ฐธ์กฐ๊ฐ ์ฐ์ด๋์ง ์ดํดํ๊ธฐ
3.๋ฐฐ์ด ๋ฉ์๋๋ฅผ ์ ์ฌ์ ์์ ์ ์ฌ์ฉํ๊ธฐ
๐ ์์ ๋น๊ต๋ก ์ดํด๋ณด๋ ๋ค์ํ ๊ฐ ๋น๊ต
๐ฃ ๋ฆฌ์กํธ์์์ ์์ ๋น๊ต
์์ ๋น๊ต๋ ๊ฐ์ฒด์ ์ฐธ์กฐ์ฃผ์๋ง ๋๊ฐ์์ง ๋น๊ตํ๋ค.
๋ฆฌ์กํธ์์ ์์ ๋น๊ต๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋ ์ํ๊ฐ ๋ณํ ๋ ํ์ด์ง๊ฐ ๋ ๋๋ง ๋๋ฉด ๋ค๋ฅธ ์ํ๊ฐ๋ค์ด ์ผ์นํ๋์ง ์ฒดํฌํ๋๋ฐ
๊น์ ๋น๊ต๋ฅผ ์ฌ์ฉํ๋ฉด ์์ชฝ์ depth๊น์ง ๋๊ฐ์์ง ๋๋ฌ๋ณด๊ณ ์ค๊ธฐ๋๋ฌธ์ ์ฐ์ฐ๋น์ฉ์ด ๋ ๋ง์ด๋ ๋ค.
๊ทธ๋์ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌํ๊ธฐ ์ํด์ ๋ฆฌ์กํธ์์ ๋ ๋๋งํ ๋ ์์ ๋น๊ต๋ฅผ ์ฌ์ฉํด์ state์ ์ฐธ์กฐ๊ฐ์ด ๋ค๋ฅด๋ฉด
๊ฐ์ด ๋ฐ๋์๊ตฌ๋! ์ธ์งํ๊ณ ์ฌ ๋ ๋๋ง ํ๊ฒ๋๋ค.
๊ทธ๋์ useState์ ๊ฐ์ ๋ณ๊ฒฝํ ๋ ๋ถ๋ณ์ฑ์ ์ง์ผ์ฃผ๊ธฐ ์ํด ...์ ์ฐ๊ฑฐ๋ a.concat(atherArr)๋ฅผ ์ฌ์ฉํ๋ค.
๐ฃ ๋ค์ํ ๊ฐ ๋น๊ต
export function shallowEquals(target1, target2) {
// ์์ ๋ฐ์ดํฐ ํ์
๋น๊ต
if (Object.is(target1, target2)) return true;
// ํ์
์ด ๋ค๋ฅผ ๊ฒฝ์ฐ
if (typeof target1 !== typeof target2) return false;
// ๊ฐ์ฒด๊ฐ ์๋ ๊ฒฝ์ฐ
if (typeof target1 !== 'object' || target1 === null || target2 === null) {
return false;
}
// ์ต๋ช
class ์กฐ๊ฑด ๋ฐ new ์์ฑ์ ๊ฐ์ฒด ์กฐ๊ฑด
if ((!target1.constructor.name || !target2.constructor.name) ||
(target1 instanceof Number || target2 instanceof Number) ||
(target1 instanceof String || target2 instanceof String)) {
return false;
}
// ๋ฐฐ์ด ๋น๊ต
if (Array.isArray(target1) && Array.isArray(target2)) {
if (target1.length !== target2.length) return false;
for (let i = 0; i < target1.length; i++) {
if (!Object.is(target1[i], target2[i])) return false;
}
return true;
}
// ๊ฐ์ฒด ํค ๋น๊ต
const target1Keys = Object.keys(target1);
const target2Keys = Object.keys(target2);
if (target1Keys.length !== target2Keys.length) return false;
for (let i = 0; i < target1Keys.length; i++) {
const currentKey = target1Keys[i];
if (!Object.hasOwnProperty.call(target2, currentKey) || !Object.is(target1[currentKey], target2[currentKey])) {
return false;
}
}
return true;
}
1. Object.is()
๋ ๊ฐ์ด ๊ฐ์์ง ๋น๊ตํ๋ค.
์์ํ์ ๊ฐ์ฒด ํ์ ๋ชจ๋ ๋น๊ตํ ์ ์๋ค.
=== ์ฐ์ฐ์๋ณด๋ค ๋ ์๊ฒฉํ๊ฒ ๋น๊ต๋ฅผ ์ํํ๋ค๋ ํน์ง์ด ์๋ค.
1. NaN์ NaN๊ณผ ๊ฐ๋ค๊ณ ๋ด
2. -0๊ณผ +0์ ๋ค๋ฅด๊ฒ ๋ณธ๋ค.
console.log(Object.is('foo', 'foo')); // true
console.log(Object.is(window, window)); // true
console.log(Object.is('foo', 'bar')); // false
console.log(Object.is([], [])); // false
console.log(Object.is(null, null)); // true
console.log(Object.is(0, -0)); // false
console.log(Object.is(-0, -0)); // true
console.log(Object.is(NaN, 0/0)); // true
console.log(NaN === NaN); // false
console.log(0 === -0); // true
2. Array.isArray
๋ฌด์กฐ๊ฑด ๋ฐฐ์ด์ธ์ง๋ง ๋น๊ตํ๋ค.
๋ฐฐ์ด์์ฑ์์ธ new Array()๋ก ๋ง๋ค์ด์ง ๋ฐฐ์ด๋ js์์๋ ๋ฐฐ์ด ๊ฐ์ฒด๋ก ์ทจ๊ธํ๊ธฐ ๋๋ฌธ์ true๋ฅผ ๋ฐํํ๋ค.
Array.isArray([]); // true
Array.isArray(document.querySelectorAll('div')); // false
3. Object.keys()
๊ฐ์ฒด์ ํค๋ค์ ๋ฌธ์์ด ๋ฐฐ์ด๋ก ๋ฐํํ๋ค.
๊ทธ๋ฆฌ๊ณ ์ด๊ฑฐ๋ถ๊ฐ๋ฅํ ์์ฑ์ ๋ฐํํ์ง ์๋๋ค. (enumerable: false)
๋ฐ๋๋ก Object.value()๋ ๊ฐ๋ค์ ๋ฐฐ์ด๋ก ๋ฐํํ๋ค.
const obj = { a: 1, b: 2, c: 3 };
const keys = Object.keys(obj);
console.log(keys); // ['a', 'b', 'c']
4. Object.hasOwnProperty.call(this, value)
๊ฐ์ฒด์ ํ๋กํ ํ์ ์ฒด์ธ์์ ์ง์ ์์๋ ์์ฑ์ ๋ฌด์ํ๊ณ , ํด๋น ๊ฐ์ฒด ์์ฒด์ ์์ฑ๋ง์ ํ์ธํ๋ค.
๊ฐ์ฒด์ ์์ฑ์ ์์ ํ๊ฒ ๊ฒ์ฌํ๊ธฐ ์ํด์ ์ฌ์ฉํ๋ค.
๋ค์ call์ ๋ถ์ด๋ฉด this๋ฅผ ์ํ๋ ๊ฒ์ผ๋ก ๊ฐ์ ํ ์ ์๋ค.
const parent = { a: 1 };
const child = Object.create(parent);
child.b = 2;
// child ๊ฐ์ฒด ์์ฒด์ ์์ฑ๋ค์ ์ถ๋ ฅํฉ๋๋ค.
console.log(Object.keys(child)); // ['b']
// parent ๊ฐ์ฒด์ ์์ฑ์ ํฌํจํ ๋ชจ๋ ์์ฑ๋ค์ ์ถ๋ ฅํฉ๋๋ค.
for (let key in child) {
console.log(key); // 'b', 'a'
}
// child ๊ฐ์ฒด์ ์์ฑ ์ค์์ ์ง์ ์ ์ผ๋ก child์ ์ํ ์์ฑ์ธ์ง๋ฅผ ํ์ธํฉ๋๋ค.
console.log(child.hasOwnProperty('b')); // true
console.log(child.hasOwnProperty('a')); // false
// Object.hasOwnProperty.call์ ์ฌ์ฉํ์ฌ child ๊ฐ์ฒด์ ์ง์ ์ ์ธ ์์ฑ์ธ์ง๋ฅผ ํ์ธํฉ๋๋ค.
console.log(Object.hasOwnProperty.call(child, 'b')); // true
console.log(Object.hasOwnProperty.call(child, 'a')); // false
console.log(Object.hasOwnProperty.call(parent, 'b')); // false
5. ์ต๋ช class ๋ง๋์ง ๋น๊ต
์๋์ class๋ ๋ณ์๋ช ์ ์์ง๋ง class ์ด๋ฆ์ ์๋ ์ต๋ช class๋ค.
์ต๋ช ํด๋์ค๋ ๋ง ๊ทธ๋๋ก ์ด๋ฆ์ด ์๊ธฐ๋๋ฌธ์ constructor.name ํ๋ฉด ๋น ๋ฌธ์์ด์ ๋ฐํํ๊ฒ ๋๋ค.
์ด๋ ๊ฒ ์ต๋ช ํด๋์ค์ธ์ง ์๋์ง ํ๋ณํ ์ ์๋ค.
const MyClass = class {
constructor() {
// constructor ๋ด์ฉ
}
};
6. ๊ฐ์ฒด๊ฐ ๋ง๋์ง ๋น๊ต
js๋ ์ ๋ช ํ๊ณ ๋ ํนํ ์ค๋ฅ๊ฐ ์๋ค.
null์ type๋ 'object'์ธ๊ฒ.
๊ทธ๋์ ๊ฐ์ฒด๊ฐ ๋ง๋์ง๋ฅผ ๋น๊ตํ ๋๋ null์ด ์๋์ง๋ ํ๋ฒ ๋ ์กฐ๊ฑด์ ๊ฑธ์ด์ค์ผ ํ๋ค.
if (typeof target1 !== 'object' || target1 === null || target2 === null) {
return false;
}
๐ ๊น์ ๋น๊ต์ ์ฌ๊ท
๊น์ ๋น๊ต๋ ๊ฐ์ฒด๋ฅผ ๋น๊ตํ ๋ ์์ชฝ์ depth์ ๊ฐ์ฒด์ ๊ฐ๊น์ง ์์ ๋๊ฐ์์ง ๋น๊ตํ๋ค.
์์ชฝ์ depth๊น์ง ๋น๊ตํ๊ธฐ ์ํด์ ์ฌ๊ท๋ฅผ ์ฌ์ฉํ๋ค.
export function deepEquals(target1, target2) {
// shallowEquals์ ์ ์ฌํ์ง๋ง, ์ฌ๊ท์ ์ผ๋ก ๋ด๋ถ ๊ฐ์ฒด๊น์ง ๋น๊ต
// ๋ ๊ฐ์ด ์ ํํ ๊ฐ์ ๊ฒฝ์ฐ true ๋ฐํ
if (target1 === target2) {
return true;
}
// target1๊ณผ target2๊ฐ ๋ชจ๋ ๋ฐฐ์ด์ด๊ณ , ๊ธธ์ด๊ฐ ๊ฐ์ ๊ฒฝ์ฐ ๊ฐ ์์๋ฅผ ๋น๊ต
if (Array.isArray(target1) && Array.isArray(target2) && target1.length === target2.length) {
return target1.every((v, k) => deepEquals(v, target2[k]));
}
// target1๊ณผ target2๊ฐ ๋ชจ๋ ๊ฐ์ฒด์ด๊ณ , ๊ฐ ์์ฑ๋ค์ ๋น๊ต
if (target1.constructor === Object && target2.constructor === Object) {
const key1 = Object.keys(target1); // target1์ ๋ชจ๋ ํค๋ฅผ ๋ฐฐ์ด๋ก ๋ฐํ
const key2 = Object.keys(target2); // target2์ ๋ชจ๋ ํค๋ฅผ ๋ฐฐ์ด๋ก ๋ฐํ
// ๊ฐ์ฒด ์์ฒด๊ฐ ๊ฐ๊ฑฐ๋ (๊ฐ์ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ๊ฑฐ๋)
// ์์ฑ์ ์๊ฐ ๊ฐ๊ณ ๋ชจ๋ ํค์ ๋ํด ์ฌ๊ท์ ์ผ๋ก deepEquals๋ฅผ ํธ์ถํ์ฌ ๊ฐ ๋น๊ต
return target1 === target2 || (key1.length === key2.length && key1.every(key => deepEquals(target1[key], target2[key])));
}
// ์ ์กฐ๊ฑด์ ๋ชจ๋ ํด๋นํ์ง ์์ผ๋ฉด ๋ ๊ฐ์ ๊ฐ์ง ์์
return false;
}
๐ new Number๊ณผ newString
expect(num1 == 1).toBe(true);
expect(typeof num1 === 'number').toBe(false);
expect(typeof num1 === 'object').toBe(true);
expect(num1 == '1').toBe(true);
expect(typeof num1 === 'string').toBe(false);
expect(typeof num1 === 'object').toBe(true);
num1์ด ๊ฐ์ ๊ฐ์๋ฐ ์๊ฒฉํ ๋น๊ต๋ฅผ ํ๋ฉด ์ซ์๋ ๋ฌธ์๊ฐ ์๋๋ผ๊ณ ํ๋ค.
๊ทธ๋ฐ๋ฐ type์ object์ด๋ค.
/** typeof๊ฐ object์ธ๊ฒ true๋๊น ๋ค์ด์ค๋ ๊ฐ์ new Number๋ก type์ object๋ก ๋ง๋ค๊ธฐ */
export function createNumber1(n) {
return new Number(n); // [Number: 1]
}
/** string์ฒ๋ผ ๋ถ๋๋ฐ, type์ด object. */
export function createNumber2(n) {
return new String(n); //[String: '1']
}
์์ ์กฐ๊ฑด๋ค์ ๋ชจ๋ ์ถฉ์กฑํ๋๊ฑด new ์์ฑ์๋ก ๋ง๋ Number ๊ฐ์ฒด๊ณผ String ๊ฐ์ฒด์ด๋ค.
๊ทธ๋์ ์์ํ์ ์ด ๋ง๋๊ณ ๋ฌผ์ด๋ณด๋ฉด false๊ฐ ๋์จ๋ค.
๐ valueOf, toJSON, toString
/** ๊ฐ์ฒด๊ฐ ์ซ์์ปจํ
์คํธ(๊ฐ์ฒด๊ฐ ์ซ์๋ก ๋ณํ๋์ด์ผ ํ๋ ์ํฉ)์์ ์ฌ์ฉ๋ ๋ ๊ฐ์ฒด์ valueOf ๋ฉ์๋๊ฐ ์ ์๋์ด ์์ผ๋ฉด
* 'valueOf'๋ฉ์๋๊ฐ ์๋์ผ๋ก ํธ์ถ๋์ด ๋ฉ์๋์ return ๊ฐ์ผ๋ก ์ฐ์ฐ.
* ์ซ์์ปจํ
์คํธ ๋ฐ์ : ์ํ ์ฐ์ฐ, ๋น๊ต ์ฐ์ฐ, ๋จํญ ์ฐ์
* JSON.stringify๋ก ๋ฌธ์์ด ๋ณํ์ ์๋ํ๋ฉด toJSON ๋ฉ์๋๊ฐ ์คํ๋๊ณ ,
* ๋ฌธ์์ด ์ปจํ
์คํธ์์๋ toString ๋ฉ์๋๊ฐ ์คํ๋๋ค.
**/
export function createNumber3(n) {
return {
value: n,
valueOf: function() {
return this.value;
},
toJSON: function() {
return `this is createNumber3 => ${this.value}`;
},
toString: function() {
return `${this.value}`;
}
};
}
๐ new Map()
๊ฐ์ ์ฐธ์กฐ๋ฅผ ๋ฐ๋ผ๋ด์ผ ํ๋ ์กฐ๊ฑด์ ์ํด new Map์ผ๋ก ๊ฐ์ฒด๋ฅผ ์บ์ฑํ๋ค.
๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ์บ์๋ฅผ ํ์ธํด์ ์ด์ ๊ณผ ๋์ผํ ๊ฐ์ฒด๊ฐ ์์๋ ๊ทธ ๊ฐ์ฒด๋ฅผ ๋ฐํํ๋ค.
๋์ผํ ๊ฐ์ฒด๊ฐ ์์๋๋ ์๋ก์ด ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ Map์ ์บ์ฑํ๋ค.
export class CustomNumber {
static cache = new Map();
constructor(n){
if (CustomNumber.cache.has(n)) {
return CustomNumber.cache.get(n);
}
this.value = n;
CustomNumber.cache.set(n, this);
}
valueOf() {
return this.value;
}
toJSON(){
return `${this.value}`;
}
toString(){
return `${this.value}`;
}
}
๐ Object.defineProperty
js์ ๊ฐ์ฒด์ ์์ฑ์ ์ ์ํ๊ฑฐ๋ ์์ ํ ๋ ์ฌ์ฉ๋๋ ๋ฉ์๋.
๋น ๊ฐ์ฒด๊ฐ ์๋์ง๋ฉด ์์ ๋ณต์ฌ๋ฅผ ํ ๋ ๋น ๊ฐ์ฒด์ ๊ฐ์์ผ ํ ๋ Object.defineProperty๋ก
์ง์ ์ ๊ทผํ ์๋ ์์ง๋ง ๊ฐ ์์ฑ์ ๋ฃจํ, ๋ฉ์๋์ ์ํด ์ด๊ฑฐ(๊ฐ์ฒด์ ์์ฑ์ ๋ฐ๋ณตํด์ ๋์ด)ํ ์ ์๊ฒ ๋ง๋ค์ด์ค๋ค.
const obj = createUnenumerableObject({ a: 1, b: 2 });
it('createUnenumerableObject > ', () => {
expect(obj.a).toEqual(1);
expect(obj.b).toEqual(2);
expect({ ...obj }).toEqual({});
})
๊ทธ๋ผ ์์ ๊ฐ์ฒด์ ์์ฑ๊ฐ์ ์ง์ ํ์ธํ ์ ์์ง๋ง
๊ฐ์ฒด๋ฅผ ์์๋ณต์ฌ๋ฅผ ํ๋ฉด enumerable์ false๋ก ํ๊ธฐ๋๋ฌธ์ ์ด๊ฑฐ๊ฐ๋ฅํ ์์ฑ์ด ์์ด ๋น ๊ฐ์ฒด๊ฐ ๋์จ๋ค.
export function createUnenumerableObject(target) {
const result = {};
Object.keys(target).forEach(key => {
Object.defineProperty(result, key, {
value: target[key],
enumerable: false,
writable: true,
configurable: true
});
});
return result;
}
7. Object.getOwnPropertyNames()
for ...in ๋ฃจํ๋ ์์ Object.keys()๋ ์ด๊ฑฐ ๊ฐ๋ฅํ ์์ฑ๋ง ๋ฐํํ์ง๋ง
Object.getOwnPropertyNames()๋ ์ด๊ฑฐ ๊ฐ๋ฅํ ์์ฑ๊ณผ ๋น์ด๊ฑฐ ๊ฐ๋ฅํ ์์ฑ ์ ๋ถ ์ด๋ฆ์ ๋ฐฐ์ด๋ก ๋ฐํํ๋ค.
const obj = Object.create({}, {
a: { value: 1, enumerable: true }, // ์ด๊ฑฐ ๊ฐ๋ฅ
b: { value: 2, enumerable: false } // ์ด๊ฑฐ ๋ถ๊ฐ๋ฅ
});
obj.c = 3; // ์ด๊ฑฐ ๊ฐ๋ฅ
console.log(Object.getOwnPropertyNames(obj)); // ["a", "b", "c"]
console.log(Object.keys(obj)); // ["a", "c"]
8. Object.getPrototypeOf()
๊ฐ์ฒด์ ํ๋กํ ํ์ ์ ๋ฐํํ๋ค.
๊ฐ์ฒด๊ฐ ์์๋ฐ๊ณ ์๋ ํ๋กํ ํ์ ์ฒด์ธ์ ํ์ธํ ์ ์๋ค.
Object.create()๋ฅผ ํตํด ์์ฑ๋ ๊ฐ์ฒด์ ํ๋กํ ํ์ ์ ํ์ธํ ๋ ์ ์ฉํ๋ค.
const obj = {};
const proto = Object.getPrototypeOf(obj);
console.log(proto === Object.prototype); // true
tmi...
์.. ์ฌ๊ธฐ์๋ถํฐ ์ฒ์๋ณด๋ ๋ฐ์ดํฐ ํ์ ์ ์ดํดํด์ผ ํ๊ณ ์๋ง์ ํ ์คํธ์ฝ๋๋ฅผ ํต๊ณผํด์ผ ํ๋ ๋ก์ง์ ์ง์ผํ๋๋ฐ
์ง์ง ๋จธ๋ฆฌ ์ฅ์ด๋ฏ์ด๋ ๊ตฌ๊ธ๋ง๊ณผ gpt๋ฅผ ์ฌ์ฉํ์ง ์์ผ๋ฉด ์ ๋ ์ดํดํ ์ ์์๋ค.
๊ตฌ๊ธ๋ง๊ณผ gpt๋ฅผ ๋๋ ค๋ด๋ ์ดํด์๋๋๊ฒ๋ ์๋ค๋๊ฑด ํจ์ ..ใ
์ด๋ฒ์ฃผ์ฐจ๋ ๋ด ์๊ฐ์ด ๋ค์ด๊ฐ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ํผ๋๋ฐฑ์ด ์์ฉ์ด ์์๋ค.. ๋ ์ด๋กํด์ ๐