4장. 데이터 구조: 객체와 배열
숫자, 부울 , 문자열 은 데이터 구조 에서 내장 된 벽돌 입니다. 하지만 당신은 하나의 벽돌 에서 많은 수의 집을 만들수 없습니다. 객체는 그룹 값들과 함께 더 복잡한 데이터 구조를 만들수 있습니다.
우리가 구축한 프로그램은 지금까지 단순 데이터 유형에서만 동작하고 있다는 사실에 의해서 방해를 받았습니다.
이 장에서는 툴킷에 데이터 구조에 대한 기본적인 이해를 추가 할 것입니다.
이 장의 끝에서 당신은 몇가지 유용한 프로그램을 충분히 이해하고 사용 할 수 있습니다.
이 장에서는 다소 현실적인 프로그램을 통해 동작할 것입니다.
예제코드는 이전의 텍스트에서 function과 변수를 활용 할 것입니다.
- The Weresquirrel
8시에서 10시 사이에 자크는 덥수룩한 털과 함께 작은 모피 설치류로 변하고 있다는 것을 알았다. 한편 자크는 자신이 늑대인간으로 변하지는 않을 것을 다행이라 생각했다.
다람쥐로 변하게 되면 늑대인간으로 변하는 것보다 문제가 덜 발생하는 경향이 있다.
이웃들을 잡아먹는 사고 등에 대한 걱정 대신, 그는 이웃들의 고양이에게 먹히는걸 걱정했다
그는 오크나무에서 벌거벗은채로 깨어 그의방과 문을 걸어잠그고 바닥에 호두를 넣기 바빴다. 그가 오크나무를 만질때 마다 변신한다. 그래서 그는 나무를 터치하는 것을 멈추었지만 문제는 여전했다.
과학적으로 접근해서 자크는 매일 모든것에 로그를 남기는 것을 시작했다 그의 변화에 대해 이 데이터는 그가 변화하는 때를 좁혀 줄것이라고 희망한다. 그는 첫번째로 데이터 구조를 디자인 했다.
- Data Sets
디지털 데이터가 작동하려면 우리의 기계의 메모리에서 표현하는 방법을 알아야 한다. 예를들어 말하자면 2,3,5,7,그리고11의 numbers 집합을 표현하기를 원한다.
우리는 문자열을 창조적으로 얻은 후에 문자열은 어떠한 길이도 될수있습니다.
우리는 많은 문자열 데이터를 넣을 수 있고, 그리고 2,3,4,5,11이라는 우리의 표현을 사용할 수있습니다. 그러나 이것은 어색합니다. 당신은 어떻게든 숫자를 추출해야 할것이고 그것들에 접근하기 위해 다시 변환해야만 할것입니다.
운이 좋게도 자바스크립트는 특별하게 값들의 순서를 저장하기 위한 데이터 타입을 지원합니다. 배열 (array)라고 합니다. 이것은 대괄호 안에 리스트로서 쓰여지고 콤마( , )로 분리 됩니다.
var listOfNumbers = [2, 3, 5, 7, 11];
console.log(listOfNumbers[1]);
// . 3
console.log(listOfNumbers[1 - 1]);
// . 2
- Properties
우리는 이전 예제들에서 몇가지 myString.length,Math.max 같은 몇가지 의심스러운 표현들을 살펴 보았다.몇가지 value의 속성으로 접근하는 표현들이 있다. 첫번째로 우리는 myString 에서 lnegth속성으로 접근한다. 두 번째로는 Math객체 안에 max라 불리우는 속성으로 접근한다. (이것은 수학과 연관된 value와 function 과 관련이 있다. )
대게 모든 자바스크립트 속성들은 properties(속성)을 가진다. 예외는 null,과 undefined이다. 만약에 이러한 nonvalues에 접근하려 한다면, 에러를 얻는다.
null.length;
// . TypeError: Cannot read property 'length' of null
자바스크립트에서 속성들에 접근하기 위한 두가지 일반적인 방법 은 dot(마침표)와 대괄호([ ])이다. value.x 그리고 value[x]는 value에 접근한다. 그러나 필수적으로 같은 속성이라고 볼 순 없다. 차이점은 x를 사용하는 방법에 의해 해석된다. Dot(마침표)를 사용할때는 마침표 이후의 부분은 유효한 변수여야 한다. 직접적으로 이름을 사용한다.
대괄호를 사용하는 경우 괄호 사이의 표현은 속성이름을 얻기위해 사용된다.
다시말해 value.x는 속성의 값을 가져오는 반명, value[x]는 속성이름을 결과로 사용한다. 그래서 당신이 속성을 알기 원한다면 "length" 를 사용하라. 만약 너가 변수1의 값을 추출하기를 원한다면 value[1]을 사용하라. 그리고 속성은 어떤 문자열도 사용할 수있다. 너가 "o","Jogn Doe"에 접근한다면 너는 대괄호를 사용해야한다. Value[0],혹은 value["John Doe"]와 같이 .
- Method
흥미롭게도 toUpperCase에 대해 인수를 전달하지 않는 경우에도 이 함수는 어떻게든 문자열"Doh"를 호출 하여 접근합니다. 이것이 어떻게 동작하는지는 6장에서 설명합니다. 함수(function)를 포함하는 속성은 value를 포함하는 메소드라고 합니다.
마찬가지로 toUppercase도 문자열의 메소드입니다.
다음 예제는 배열 객체들이 가지는 몇가지 메소드의 예제입니다.
The push method can be used to add values to the end of an array. The
pop method does the opposite: it removes the value at the end of the array
and returns it. An array of strings can be flattened to a single string with the
join method. The argument given to join determines the text that is glued
between the array's elements.
push 메소드는 배열의 최종값을 추가 하기 위해 사용된다.
Pup메소드는 반대로 마지막 값을 제거하고 그것을 return한다.
배열의 문자들을 단일 문자열로 바꿔주는 메소드는 join메소드이다.
주어진 인자들은 배열 요소들 사이에 text를 이어 붙여 준다.
Objects
Back to the weresquirrel. A set of daily log entries can be represented as an
array. But the entries do not consist of just a number or a string—each entry
needs to store a list of activities and a Boolean value that indicates whether
Jacques turned into a squirrel. Ideally, we would like to group these values
together into a single value and then put these grouped values into an array
of log entries.
객체
객체는 Number ,문자 , 부울린 이러한 값들을 포함하는 것을 그룹화하는 것이다.
이러한 객체의 속성값은 임의로 추가하거나 제거할 수있다.
객체의 생성 방법은 중괄호를 사용하는 것이다.
var day1 = {
squirrel: false,
events: ["work", "touched tree", "pizza", "running",
"television"]
};
console.log(day1.squirrel);
// . false
console.log(day1.wolf);
// . undefined
day1.wolf = false;
console.log(day1.wolf);
// . false
Inside the braces, we can give a list of properties separated by commas.
Each property is written as a name, followed by a colon, followed by an expression
that provides a value for the property. Spaces and line breaks are
not significant. When an object spans multiple lines, indenting it like in
the previous example improves readability. Properties whose names are not
valid variable names or valid numbers have to be quoted.
중괄호 내부에서, 우리는 쉼표로 구분된 속성의 목록을 보여준다.
각 속성은 쉼표로 구분한다.
공백과 줄바꿈은 중요하다. 객체가 들여쓰기, 여러 줄에 걸쳐 사용된다. 이렇게 사용하면 가독성을 높일 수 있다.
var descriptions = {
work: "Went to work",
"touched tree": "Touched a tree"
};
This means that braces have two meanings in JavaScript. At the start of
a statement, they start a block of statements. In any other position, they describe
an object. Fortunately, it is almost never useful to start a statement
with a brace object, and in typical programs, there is no ambiguity between
Reading a property that doesn't exist will produce the value undefined,
which happens the first time we try to read the wolf property in the previous
example.
이 중괄호는 자바스크립트에서 두가지 의미를 가진다.
문장의 시작을 표시하는 동시에 다른의미에서는 객체를 묘사하는 의미를 가진다.
It is possible to assign a value to a property expression with the = operator.
This will replace the property's value if it already existed or create a new
property on the object if it didn't.
To briefly return to our tentacle model of variable bindings—property
bindings are similar. They grasp values, but other variables and properties
might be holding onto those same values. You may think of objects as octopuses
with any number of tentacles, each of which has a name inscribed
on it.
"="연산자 속성식에 값을 할당 할 수있다. 이것은 이미 존재하는 경우 속성값을 대체하거나 새로 만든다.
The delete operator cuts off a tentacle from such an octopus. It is a
unary operator that, when applied to a property access expression, will remove
the named property from the object. This is not a common thing to
do, but it is possible.
Delete 연산자는 객체의 속성을 제거한다.
일반적으로 사용되진 않지만 가능하다.
var anObject = {left: 1, right: 2};
console.log(anObject.left);
// . 1
delete anObject.left;
console.log(anObject.left);
// . undefined
console.log("left" in anObject);
// . false
console.log("right" in anObject);
// . true
The binary in operator, when applied to a string and an object, returns
a Boolean value that indicates whether that object has that property. The
difference between setting a property to undefined and actually deleting it is
that, in the first case, the object still has the property (it just doesn't have a
very interesting value), whereas in the second case the property is no longer
present and in will return false.
"in" 연산자는 그것의 속성이 존재하는지 boolean 값으로 리턴한다.
Arrays, then, are just a kind of object specialized for storing sequences
of things. If you evaluate typeof [1, 2], this produces "object". You can see
64 Chapter 4
them as long, flat octopuses with all their arms in a neat row, labeled with
numbers.
배열은 시퀀스를 저장하기 위한 특별한 개체 종류중 하나이다. 만약 typeof [1,2]를 실행해 본다면 "object"가 된다.
So we can represent Jacques's journal as an array of objects.
var journal = [
{events: ["work", "touched tree", "pizza",
"running", "television"],
squirrel: false},
{events: ["work", "ice cream", "cauliflower",
"lasagna", "touched tree", "brushed teeth"],
squirrel: false},
{events: ["weekend", "cycling", "break",
"peanuts", "beer"],
squirrel: true},
/* and so on... */
];
Mutability
가변성
We will get to actual programming real soon now. But first, there's one last
piece of theory to understand.
We've seen that object values can be modified. The types of values discussed
in earlier chapters, such as numbers, strings, and Booleans, are all
immutable—it is impossible to change an existing value of those types. You
can combine them and derive new values from them, but when you take a
specific string value, that value will always remain the same. The text inside
it cannot be changed. If you have reference to a string that contains "cat", it
is not possible for other code to change a character in that string to make it
spell "rat".
객체의 값은 수정될 수 있다. numbers,strings,Booleans는 이미 존재하는 타입의 값을 변경하는 것은 불가능 하다. 결합하여 새로운 값을 만드는 것은 가능하지만, 특정 문자열 값은 항상 동일하게 유지된다. 만약"cat"을 포함하는 문자열에 대한 다른 참조가 있으면 다른 ㅗ드를 만들기 위해 해당 문자열의 변경은 할 수없다.
With objects, on the other hand, the content of a value can be modified
by changing its properties.
When we have two numbers, 120 and 120, we can consider them precisely
the same number, whether or not they refer to the same physical bits.
But with objects, there is a difference between having two references to the
Data Structures:
same object and having two different objects that contain the same properties.
Consider the following code:
다른 한편으로는 객체의 내용은 수정이 될 수있 다 .
해당 속성을 변경하여 두 숫자 120과 120을 가질때 , 이 것들이 정확하게 같은 숫자인지 생각해볼 필요가 있다. 여기 차이점이 있다 두개의 참조를 가지는 데이터 구조가
하나는 같은 객체 또 하나는 두가지 다른객체를 가지지만 같은 속성을 가지고 있다.
var object1 = {value: 10};
var object2 = object1;
var object3 = {value: 10};
console.log(object1 == object2);
// . true
console.log(object1 == object3);
// . false
object1.value = 15;
console.log(object2.value);
// . 15
console.log(object3.value);
// . 10
The object1 and object2 variables grasp the same object, which is why
changing object1 also changes the value of object2. The variable object3 points
to a different object, which initially contains the same properties as object1
but lives a separate life.
object1과 object2 는 같은객체이다. object1을 변경하면 object2의 값이 변경된다.
하지만 object3은 다른객체이다. 속성은 같지만 object1과는 별도이다.
JavaScript's == operator, when comparing objects, will return true only if
both objects are precisely the same value. Comparing different objects will
return false, even if they have identical contents. There is no deep comparison
operation built into JavaScript, which looks at object's contents, but it is
possible to write it yourself (which will be one of the exercises at the end of
this chapter).
자바스클립트의 "=="연산자는 객체를 비교할때 두 객체가 정확하게 같은 객체여야 true를 return 한다. 다른 객체를 비교하면 동일한 내용을 가지고 있더라도 false를 리턴한다. 자바스크립트는 객체의 내용 까지 깊이 비교하는 것이 내장되어 있지 않다. 그러나 이장의 끝에서 비교하는 법을 연습한다.
Further Arrayology
Before finishing up this chapter, I want to introduce you to a few more
object-related concepts. We'll start by introducing some generally useful
array methods.
이 장을 마무리하기 전에 몇가지 객체관련 개념을 소개한다.
We saw push and pop, which add and remove elements at the end of an
array, earlier in this chapter. The corresponding methods for adding and
removing things at the start of an array are called unshift and shift.
Push ,pop 이외에 unshift및 shift가 있다.
var todoList = [];
function rememberTo(task) {
todoList.push(task);
}
function whatIsNext() {
return todoList.shift();
}
function urgentlyRememberTo(task) {
todoList.unshift(task);
}
The previous program manages lists of tasks. You add tasks to the end of
the list by calling rememberTo("eat"), and when you're ready to do something,
you call whatIsNext() to get (and remove) the front item from the list. The
urgentlyRememberTo function also adds a task but adds it to the front instead of
the
이 프로그램은 작업목록을 관리한다. rememberTo("eat")를 호출하면 배열에 저장한다. 그리고 whatIsNext()를 호출하면 리스트 제일 앞에 아이템을 가져온다. urgentlyRememberTo 함수는 배열의 마지막에 오지않고 제일 앞에 오게 된다.
The indexOf method has a sibling called lastIndexof, which starts searching
for the given element at the end of the array instead of the front.
indexOf 메소드와 형제로 불리우는 lastIndexof는 주어진 요소의 끝 위치를 반환한다.
console.log([1, 2, 3, 2, 1].indexOf(2));
// . 1
console.log([1, 2, 3, 2, 1].lastIndexOf(2));
// . 3
Both indexOf and lastIndexOf take an optional second argument that indicates
where to start searching from.
indexOf와 lastIndexOf 는 선택적으로 찾는 시작점을 지정할 수있는 두번째 인자를 가진다.
Another fundamental method is slice, which takes a start index and an
end index and returns an array that has only the elements between those
indices. The start index is inclusive, the end index exclusive.
또 다른 메소드인 slice 는 시작 인덱스부터 끝 인덱스 안에 모든 요소를 가져온다. 리턴된 배열은 오직 범위 안에 요소들이다. 시작 인덱스는 포함하지만 끝 인덱스는 포함하지 않는다.
console.log([0, 1, 2, 3, 4].slice(2, 4));
// . [2, 3]
console.log([0, 1, 2, 3, 4].slice(2));
// . [2, 3, 4]
When the end index is not given, slice will take all of the elements after
the start index. Strings also have a slice method, which has a similar effect.
끝 인덱스가 주어지지 않으면, slice메소드는 시작점 이후 모든 인덱스를 가져온다. 문자열 또한 slice메소드와 비슷한 것을 가진다. Concat 메소드는 배열을 합칠 수 있다. 다음 예제는 concat과 slice에제이다.
The concat method can be used to glue arrays together, similar to what
the + operator does for strings. The following example shows both concat
and slice in action. It takes an array and an index, and it returns a new array
that is a copy of the original array with the element at the given index
removed.
Concat 메소드는 배열을 합칠 수 있다. 다음 예제는 concat과 slice에제이다.
function remove(array, index) {
return array.slice(0, index)
.concat(array.slice(index + 1));
}
console.log(remove(["a", "b", "c", "d", "e"], 2));
// . ["a", "b", "d", "e"]
Strings and Their Properties
We can read properties like length and toUpperCase from string values. But if
you try to add a new property, it doesn't stick.
우리는 length 와 toUppercase 문자열 값으로 부터 읽을 수있다. 그러나 새로운 속성을 추가 하려한다면 그것은 정의 되지 않은 것이기 때문에 undefined 이다.
var myString = "Fido";
myString.myProperty = "value";
console.log(myString.myProperty);
doesn't actually store those properties. The values are immutable and cannot
be changed.
But these types do have some built-in properties. Every string value has
a number of methods. The most useful ones are probably slice and indexOf,
which resemble the array methods of the same name.
console.log("coconuts".slice(4, 7));
// . nut
console.log("coconut".indexOf("u"));
// . 5
그러나 이러한 타입들은 몇가지 특성을 가진다. 모든 문자열은 메소드를 가진다. 가장 유용한 것은 slice와 indexOf,이것은 배열 메소드와 유사하다.
One difference is that a string's indexOf can take a string containing
more than one character, whereas the corresponding array method looks
only for a single element.
한가지 차이점은 문자열의 indexOf는 문자를 두개 이상 취할수 있는 반면 array메소드는 한개의 요소만 취할 수있다.
console.log("one two three".indexOf("ee"));
// . 11
The trim method removes whitespace (spaces, newlines, tabs, and similar
characters) from the start and end of a string.
trim 메소드는 공백을 제거한다. (공백들,줄바꿈, tabs, 유사 characters) 시작과 끝의 문자열로 부터
console.log(" okay \n ".trim());
// . okay
We have already seen the string type's length property. Accessing the
individual characters in a string can be done with the charAt method but also
by simply reading numeric properties, like you'd do for an array.
문자타입의 length 속성을 이미 보았다. 개별 문자로 접근하는 것은 charAt메소드 뿐만 아니라 단순하게 numeric 속성으로 (value.x )와 같이 접근 할 수있다.
var string = "abc";
console.log(string.length);
// . 3
console.log(string.charAt(0));
// . a
console.log(string[1]);
// . B
The arguments Object
Whenever a function is called, a special variable named arguments is added
to the environment in which the function body runs. This variable refers to
an object that holds all of the arguments passed to the function. Remember
that in JavaScript you are allowed to pass more (or fewer) arguments to a
function than the function threeArguments(a, b, c) {} threeArguments(); // And so is this
The arguments object has a length property that tells us the number of
arguments that were really passed to the function. It also has a property for
each argument, named 0, 1, 2, and so on.
If that sounds a lot like an array to you, you're right, it is a lot like an
array. But this object, unfortunately, does not have any array methods (like
slice or indexOf), so it is a little harder to use than a real array.
함수가 호출 될 때마다 특수한 가변인자는 함수 본문이 실행되는 환경에서 추가된다.
이 변수는 함수에 전달된 모든 인수를 보유하고 객체를 참조한다. 자바스크립트에서 매개 변수의 수보다 기능자체가 선언하는 인수를 전달하도록 하는것을 명심해라.
function argumentCounter() {
console.log("You gave me", arguments.length, "arguments.");
}
argumentCounter("Straw man", "Tautology", "Ad hominem");
// . You gave me 3 arguments.
Some functions can take any number of arguments, like console.log.
These typically loop over the values in their arguments object. They can be
used to create very pleasant interfaces. For example, remember how we
created the entries to Jacques's journal.
addEntry(["work", "touched tree", "pizza", "running",
"television"], false);
Since he is going to be calling this function a lot, we could create an alternative
that is easier to call.
function addEntry(squirrel) {
var entry = {events: [], squirrel: squirrel};
for (var i = 1; i < arguments.length; i++)
entry.events.push(arguments[i]);
journal.push(entry);
}
addEntry(true, "work", "touched tree", "pizza",
"running", "television");
This version reads its first argument (squirrel) in the normal way and
then goes over the rest of the arguments (the loop starts at index 1, skipping
the first) to gather them into an array.
자주사용하는 객체는 이런식으로 구현할수도 있다.
The Math Object
As we've seen, Math is a grab-bag of number-related utility functions, such as
Math.max (maximum), Math.min (minimum), and Math.sqrt (square root).
다음과 같은 Math기능을 제공한다.
Math.max (maximum), Math.min (minimum), and Math.sqrt (square root).
The Math object
a value. Rather, it provides a namespace so that all these functions and values
do not have to be global variables.
Having too many global variables "pollutes" the namespace. The more
names that have been taken, the more likely you are to accidentally overwrite
the value of some variable. For example, it's not unlikely that you'll
want to name something max in one of your programs. Since JavaScript's
built-in max function is tucked safely inside the Math object, we don't have to
worry about overwriting it.
Many languages will stop you, or at least warn you, when you are defining
a variable with a name that is already taken. JavaScript does neither, so
be careful.
Back to the Math object. If you need to do trigonometry, Math can help.
It contains cos (cosine), sin (sine), and tan (tangent), as well as their inverse
functions, acos, asin, and atan, respectively. The number (pi)—or at least
the closest approximation that fits in a JavaScript number—is available as
Math.PI. (There is an old programming tradition of writing the names of constant
values in all caps.)
function randomPointOnCircle(radius) {
var angle = Math.random() * 2 * Math.PI;
return {x: radius * Math.cos(angle),
y: radius * Math.sin(angle)};
}
console.log(randomPointOnCircle(2));
// . {x: 0.3667, y: 1.966}
If sines and cosines are not something you are very familiar with, don't
worry. When they are used in this book, in Chapter 13, I'll explain them.
The previous example uses Math.random. This is a function that returns a
new pseudorandom number between zero (inclusive) and one (exclusive)
every time you call it.
console.log(Math.random());
// . 0.36993729369714856
console.log(Math.random());
// . 0.727367032552138
console.log(Math.random());
// . 0.40180766698904335
Though computers are deterministic machines—they always react the
same way if given the same input—it is possible to have them produce numbers
that appear random. To do this, the machine keeps a number (or a
bunch of numbers) in its internal state. Then, every time a random number
is requested, it performs some complicated deterministic computations on
this internal state and returns part of the result of those computations. The
machine also uses the outcome to change its own internal state so that the
next "random" number
If we want a whole random number instead of a fractional one, we can
use Math.floor (which rounds down to the nearest whole number) on the
result of Math.random.
console.log(Math.floor(Math.random() * 10));
// . 2
Multiplying the random number by 10 gives us a number greater than
or equal to zero, and below 10. Since Math.floor rounds down, this expression
will produce, with equal chance, any number from 0 through 9.
There are also the functions Math.ceil (for "ceiling," which rounds up to
a whole number) and Math.round (to the nearest whole number).
The Global Object
The global scope, the space in which global variables live, can also be approached
as an object in JavaScript. Each global variable is present as a property
of this object. In browsers, the global scope object is stored in the window
variable.
var myVar = 10;
console.log("myVar" in window);
// . true
console.log(window.myVar);
// . 10
Summary
Objects and arrays (which are a specific kind of object) provide ways to group
several values into a single value. Conceptually, this allows us to put a bunch
of related things in a bag and run around with the bag, instead of trying to
wrap our arms around all of the individual things and trying to hold on to
them separately.
Most values in JavaScript have properties, the exceptions being null and
undefined. Properties are accessed using value.propName or value["propName"].
Objects tend to use names for their properties and store more or less a fixed
set of them. Arrays, on the other hand, usually contain varying numbers
of conceptually identical values and use numbers (starting from 0) as the
names of their properties.
There are some named properties in arrays, such as length and a number
of methods. Methods are functions that live in properties and (usually) act
on the value they are a property of.
Objects can also serve as maps, associating values with names. The in
operator can be used to find out whether an object contains a property with
a given name. The same keyword can also be used in a for loop (for (var
Exercises
The Sum of a Range
The introduction of this book alluded to the following as a nice way to compute
the sum of a range of numbers:
console.log(sum(range(1, 10)));
Write a range function that takes two arguments, start and end, and
returns an array containing all the numbers from start up to (and including)
end.
Next, write a sum function that takes an array of numbers and returns the
sum of these numbers. Run the previous program and see whether it does
indeed return 55.
As a bonus assignment, modify your range function to take an optional
third argument that indicates the "step" value used to build up the array. If
no step is given, the array elements go up by increments of one, corresponding
to the old behavior. The function call range(1, 10, 2) should return
[1, 3, 5, 7, 9]. Make sure it also works with negative step values so that
range(5, 2, -1) produces [5, 4, 3, 2].
Reversing an Array
Arrays have a method reverse, which changes the array by inverting the
order in which its elements appear. For this exercise, write two functions,
reverseArray and reverseArrayInPlace. The first, reverseArray, takes an array
as an argument and produces a new array that has the same elements in
the inverse order. The second, reverseArrayInPlace, does what the reverse
method does: it modifies the array given as argument in order to reverse
its elements. Neither may use the standard reverse method.
Thinking back to the notes about side effects and pure functions in the
previous chapter, which variant do you expect to be useful in more situations?
Which one is more efficient?
A List
Objects, as generic blobs of values, can be used to build all sorts of data
structures. A common data structure is the list (not to be confused with the
array). A list is a nested set of objects, with the first object holding a reference
to the second, the second to the third, and so on.
var list = {
value: 1,
rest: {
value: 2,
78 Chapter 4
rest: {
value: 3,
rest: null
}
}
};
The resulting objects form a chain, like this:
value: 1
rest:
value: 2
rest:
value: 3
rest: null
A nice thing about lists is that they can share parts of their structure.
For example, if I create two new values {value: 0, rest: list} and {value:
-1, rest: list} (with list referring to the variable defined earlier), they are
both independent lists, but they share the structure that makes up their last
three elements. In addition, the original list is also still a valid three-element
list.
Write a function arrayToList that builds up a data structure like the
previous one when given [1, 2, 3] as an argument, and write a listToArray
function that produces an array from a list. Also write the helper functions
prepend, which takes an element and a list and creates a new list that adds
the element to the front of the input list, and nth, which takes a list and a
number and returns the element at the given position in the list, or undefined
when there is no such element.
If you haven't already, also write a recursive version of nth.
Deep Comparison
The == operator compares objects by identity. But sometimes, you would
prefer to compare the values of their actual properties.
Write a function, deepEqual, that takes two values and returns true only if
they are the same value or are objects with the same properties whose values
are also equal when compared with a recursive call to deepEqual.
To find out whether to compare two things by identity (use the ===
operator for that) or by looking at their properties, you can use the typeof
operator. If it produces "object" for both values, you should do a deep comparison.
But you have to take one silly exception into account: by a historical
accident, typeof null also produces "object".
Data Structures: Objects
"There are two ways of constructing a software
design: One way is to make it so simple that
there are obviously no deficiencies, and the
other way is to make it so complicated that
there are no obvious deficiencies"
— C.A.R. Hoare,
1980 ACM Turing Aware