Chapter 1 values, types, and Operators
1.1 value
There are six basic value types in JavaScript: number, string, Boolean, object, function, and undefined.
Figure 1.2
A value of type number is a numeric value. Write it in JavaScript as follows:
13
Note: Treat scores as approximations, not exact values
1.2.1 arithmetic
The arithmetic in JavaScript looks like this:
100 plus 4 times 11
1.2.2 Special Numbers
Positive Infinity: Infinity
Negative Infinity: -infinity
Non-numeric: NaN
1.3 the string
We use strings to represent text information. Enclose the content in quotation marks.
“Patch my boat with chewing gum”
‘Monkeys wave goodbye’
1.4 Unary operators
The console. The log (typeof 4.5); // number console.log(typeof"x"); // string
Copy the code
1.5 Boolean value
There are only two values of this type: true and false
1.5.1 comparison
console.log(3 > 2); // true
console.log(3 < 2); // false
console.log("Aardark" < "Zoroaster"); // true
console.log( NaN == NaN); // false
Copy the code
1.5.2 Logical Operators
JavaScript supports three logical operators: and, or, and not
console.log(true && false); // false
console.log(true && true); // true
console.log(false || true); // true
console.log(false || false); // false// The ternary operator console.log(true? 1, 2); // 1 console.log(false ? 1 : 2); // 2
Copy the code
1.6 Undefined value
Null and undefined are used to represent meaningless values. They represent their own meanings and contain no information beyond that.
1.7 Automatic Type conversion
console.log(8 * null); // 0
console.log("5" - 1); // 4
console.log("5" + 1); // 51
console.log("five" * 2); // NaN
console.log(false= = 0); //true
console.log(""= = =false); // false
Copy the code
Short-circuit characteristics of logical operators
console.log(null || "user"); // user
console.log("Karel" || "user"); // Karel
Copy the code
Chapter 2 program structure
2.1 Expressions and statements
The simplest statement consists of an expression followed by a semicolon. For example, here is a program:
1;
!false;
Copy the code
2.2 variable
var caught = 5 * 5;
var ten = 10;
console.log(ten * ten); // 100
var mood = "light";
console.log(mood); // light
mood = "dark"; console.log(mood); // dark var luigisDebt = 140; luigisDebt = luigisDebt - 35; console.log(luigisDebt); // 105 var one = 1,two = 2; console.log(one + two); / / 3Copy the code
2.3 Keywords and Reserved Words
Some words with special meanings are called keywords, such as var. Keywords cannot be used as variable names. There are also some words reserved for JavaScript.
2.4 environment
We call the set of variables and variable values at a given time the environment.
2.5 the function
Many function types are included in the default environment. A function is a program wrapped in variables that we can use to execute the wrapped program.
alert("Good morning!");
Copy the code
2.6 the console. The log function
var x = 30;
console.log("the value of x is ",x); // the value of x is 30
Copy the code
2.7 the return value
We call the operation of a function to generate a value a return value.
The console. The log (Math. Max (2, 4); // 4 console.log(math.min (2,4) + 100); / / 102Copy the code
2.8 Prompt and confirm functions
These two functions are rarely used in modern Web programming, mainly because you have no control over the style of the pop-up window. However, they can be very useful for small programs or test programs.
confirm("Shall we,then?");
prompt("Tell me everything you know."."...");
Copy the code
2.9 the control flow
If your program contains more than one statement, the statements must be executed from top to bottom.
var theNumber = Number(prompt("Pick a number"."");
alert("Your number is the square root of " + theNumber * theNumber);
Copy the code
2.10 Conditional Execution
var theNumber = Number(prompt("Pick a number"."");
if(! isNaN(theNumber)){ alert("Your number is the square root of " + theNumber * theNumber);
}else{
alert("Hey,Why didn't you give me a number?");
}
var num = Number(prompt("Pick a number"."");
if(num < 10){
alert("small");
}else if(num < 100){
alert("medium");
}else{
alert("large");
}
Copy the code
2.11 While and do loops
var number = 0;
while(number <= 12){ console.log(number); number = number + 2; } var result = 1; var counter = 0;while(counter < 10){
result = result * 2;
counter++;
}
console.log(result);
do{
var name = prompt("who are you?");
}while(! name); console.log(name);Copy the code
2.12 Code indentation
2.13 a for loop
for(var number = 0; number <= 12; number = number + 2){ console.log(number); } var result = 1;for(var counter = 0; counter < 10; counter++){ result = result * 2; } console.log(result);Copy the code
2.14 Break out of the loop
for(var current = 20; ; current++){
if(current % 7 == 0){
break; } } console.log(current); / / 21Copy the code
2.15 Simple method for updating variables
counter += 1;
result *= 2;
counter++;
counter--;
Copy the code
2.16 Switch Conditional branch
switch(prompt("What is the weather like?")) {case "rainly":
console.log("Remember to bring an umbrella");
break;
case "sunny":
console.log("Dress lightly");
break;
case "cloudly":
console.log("Go outside");
break;
default:
console.log("Unknown weather type!");
break;
}
Copy the code
2.17 the capital
2.18 annotations
var accountBalance = calculateBalance(account);
// It's a green hollow where a river sings
accountBalance.adjust();
// Madly catching white tatters in the grass
var report = new Report();
// Where the sun on the proud mountain rings:
addToReport(accountBalance,report);
// It's a little valley,foaming like light in a glass
/*
I first found ths number scrawled on the back of one of
my notebooks a few years ago.Since then,it has often
dropped by,showing up in phone numbers and the serial
numbers of products that I've bought.It obviously likes
me,so I've decided to keep it.
*/
var myNumber = 112213;
Copy the code
2.19 Summary of this chapter
2.20 problem sets
// 1
var str = "";
for(var i = 0; i < 7; i++){ str = str +"#"; console.log(str); } / / 2for(var i = 1; i <= 100; i++){if(i % 3 == 0){
console.log("Fizz");
}else if(i % 5 == 0){
console.log("Buzz")}else{ console.log(i); }}for(var i = 1; i <= 100; i++){if(i % 3 == 0 && i % 5 == 0){
console.log("FizzBuzz");
}else if(i % 3 == 0){
console.log("Fizz")}else if(i % 5 == 0){
console.log("Buzz")}else{
console.log(i);
}
}
// 3
var str = "";
var size = 8;
for(var i = 0; i < size; i++){
for(var j = 0; j < size; j++){if((i + j)% 2 == 0){
str = str + "#";
}else{
str = str + "";
}
}
str += "\n";
}
console.log(str);
Copy the code
Chapter 3 functions
3.1 Defining functions
A function definition is a normal variable definition, but the variable type happens to be a function.
Expressions that create functions begin with the keyword function.
Some functions can produce values, and some don’t. The return statement in a function determines the return value of the function. When a function executes into a return statement, it immediately jumps out of the current function and assigns the return value to the caller. If there is no expression after the return keyword, the function returns undefined.
Var square = functon(x) {var square = functon(x) {return x*x;
}
console.log(square(12)); // 144
var makeNoise = function() {
console.log("Pling!");
}
makeNoise(); // Pling!
var power = function(base,exponent) {
var result = 1;
for(var count = 0; count < exponent; count++) { result *= base;returnresult; }} to the console. The log (power (2, 10)); / / 1024Copy the code
3.2 Parameters and scope
The argument to a function is like an ordinary variable, but its initial value is provided by the caller of the function, not by the internal code of the function itself.
One important property of a function is that the variables and parameters created internally are local variables of the function. This means that the result variable of the power function in the example is recreated with each function call, and this isolation mechanism ensures that the different functions do not interfere with each other.
var x = "outside";
var f1 = function() {
var x = "inside f1";
}
f1();
console.log(x); // outside
var f2 = function() {
x = "inside f2";
}
f2();
console.log(x); // inside f2
Copy the code
3.3 Nested scopes
JavaScript can not only distinguish between global variables and local variables, but also create other functions within functions, with varying degrees of local scope.
var landscape = function(){
var result = "";
var flat = function(size){
for(var count = 0; count < size; count++){ result +="_";
}
}
var mountain = function(size) {
result +="/";
for(var count = 0; count < size; count++){ result +="'";
}
result += "\ \";
}
flat(3);
mountain(4);
flat(6);
mountain(1);
flat(1);
return result;
};
console.log(landscape());
Copy the code
3.4 function value
Function variables are usually just the name of a particular program. This type of variable only needs to be defined once and never changes.
Not only can you call a function directly, you can use the value of a function type just like any other type of value, use it in any expression, store it in a new variable, or pass it as an argument to another function, and so on. Similarly, a variable used to store a function is just a normal variable that can be assigned a new value.
var launchMissiles = function(value) {
missileSystem.launch("now");
};
if(safeMode){
launchMissiles = function(value){
// do something
}
}
Copy the code
3.5 Symbol Declaration
Var square = function… Expressions are used to declare functions, and there is another, more concise way to declare functions.
function square(x) {
return x*x;
}
Copy the code
Conceptually, function declarations are moved to the top of their scope, and all scoped function calls are fine.
console.log("The future says:",future());
function future() {return "We STILL have no flying cars."
}
console.log("The future says:",future1()); // Uncaught TypeError: future1 is not a function
var future1 = function () {
return "1111";
}
Copy the code
3.6 the call stack
function greet(who){
console.log("Hello" + who);
}
greet("Harry");
console.log("Bye");
Copy the code
Because a function needs to jump back to the code that called it after execution, the computer must remember the context in which the function was called.
We call the area of the computer where this context is stored the call stack. Each time a function is called, the current context information is stored at the top of the stack. When the function returns, the system removes the context information stored at the top of the stack and uses that information to continue executing the program.
The stack needs to be kept in computer memory. If the stack storage space is too large, the computer will prompt a message like “stack space overflow” or “too much recursion”.
function chicken() {return egg();
}
function egg() {return chicken();
}
console.log(chicken() + "came first.");
Copy the code
3.7 Optional Parameters
JavaScript imposes almost no restrictions on the number of arguments passed to a function. If you pass too many arguments, the extra arguments will be ignored, and if you pass too few arguments, the missing arguments will be assigned undefined.
The downside of this feature is that you may pass exactly the wrong number of arguments to the function, but no one will tell you about the error.
The advantage of this feature is that we can use this behavior to make the function accept optional arguments.
function power(base,exponent){
if(exponent == undefined) {
exponent = 2;
}
var result = 1;
for(var count = 0; count < exponent; count++){ result *= base; }returnresult; } console.log(power(4)); / / 16 console. The log (power (4, 3)); / / 64Copy the code
3.8 the closure
Functions can be used as values, and their local variables are recreated with each function call.
function wrapValue(n) {
var localVariable = n;
return function() {
return localVariable; } } var wrap1 = wrapValue(1); var wrap2 = wrapValue(2); console.log(wrap1()); // 1 console.log(wrap2()); / / 2Copy the code
In fact, multiple instances of the same variable can exist at the same time, which is a good example of how local variables are recreated each time a function is called. Different function calls do not affect local variables in other functions.
We call this ability to refer to a particular local variable instance a closure. A function that wraps some local variables is a closure.
function multiplier(factor) {
return function(number) {
returnnumber * factor; } } var twice = multiplier(2); console.log(twice(5)); / / 10Copy the code
3.9 the recursive
Functions can call themselves, as long as stack overflow is avoided. We call the behavior of a function call itself recursion.
function power(base,exponent){
if(exponent == 0){
return 1;
}else{
returnbase * power(base,exponent -1); }} to the console. The log (power (2, 3)); / / 8Copy the code
In standard JavaScript implementations, functions written recursively execute about 10 times more slowly than functions written looping. Performing a simple loop is much more efficient than making multiple function calls.
Rule of thumb: Don’t worry about efficiency unless your program is really slow. As soon as it’s too slow, figure out what takes the most time and replace it with more efficient code.
However, we cannot generalize to say that recursion is only less efficient than loops. For some problems, recursion is better than looping. This type of problem usually involves executing and handling multiple branches, each of which leads to more execution branches.
// Start with the number 1, add 5 or multiply by 3 each time, loop. This can produce an infinite number of new numbers. So how do you write a function to find an additive multiplication sequence that produces the specified number? For example, the number 13 can be generated by one multiplication and two additions, while the number 15 can never be obtained. The solution using recursive coding is as follows:function findSolution(target){
function find(start,history) {if(start == target){
return history;
}else if(start > target){
return null;
}else{
return find(start + 5,"(" + history + "+5 )") || find(start * 3,"(" + history + "*3 )")}}return find(1,"1");
}
console.log(findSolution(24));
Copy the code
3.10 Adding new Functions
There are two common ways to introduce functions into a program.
The first approach is to find similar code that appears multiple times in your program. We can extract the code for the repeated functions into a function and give it a proper name.
The second way is when you write some new code that you think should be a function, we write it into a function and give it a name.
// Write a program to print two numbers. The first number is the number of Cows on the farm, and the second number is the number of Chickens on the farm, followed by Cows and Chickens, and preceded by 0 so that each number always consists of three digits.function printFarmInventory(cows,chickens) {
var cowString = String(cows);
while(cowString.length < 3){
cowString = "0" + cowString;
}
console.log(cowString + " cows");
var chickenString = String(chickens);
while(chickenString.length < 3){
chickenString = "0" + chickenString;
}
console.log(chickenString + " Chickens");
}
printFarmInventory (7, 11); // Extend the software to output the number of pigsfunction printZeroPaddedWithLabel(number,label){
var numberString = String(number);
while(numberString.length < 3){
numberString = "0" + numberString;
}
console.log(numberString + "" + label);
}
function printFarmInventory(cows,chickens,pigs){
printZeroPaddedWithLabel(cows,"Cows");
printZeroPaddedWithLabel(chickens,"Chickens");
printZeroPaddedWithLabel(pigs,"Pigs");
}
print,11,3 FarmInventory (7); // Continue optimizationfunction zeroPad(number,width){
var string = String(number);
while(string.length < width){
string = "0" + string;
}
return string;
}
function printFarmInventory(cows,chickens,pigs){
console.log(zeroPad(cows,3) + "Cows");
console.log(zeroPad(chickens,3) + "Chickens");
console.log(zeroPad(pigs,3) + "pigs");
}
print,16,3 FarmInventory (7);Copy the code
A better approach is to try not to add too much functionality to a function unless you really need it. We always want to write a common framework to solve all kinds of problems we encounter. But don’t worry, this isn’t going to solve anything, and no one is actually going to use it.
3.11 function and its side effects
We can divide functions into two classes: those that produce side effects when called, and those that produce a return value (of course we can also define functions that produce both side effects and return values).
Functions that generate a return value are easier to integrate into a new environment than functions that directly produce side effects.
A pure function is one that produces values and does not affect anything outside of its scope.
3.12 Summary of this chapter
3.13 problem sets
/ / 1function min(a,b){
if(a> b){
return b;
}else{
returna; }} to the console. The log (min (1, 2)); / / 2function isEven(n){
if(n == 0){
return true;
}else if(n == 1){
return false;
}else if (n < 0){
return isEven(-n);
}else{
return isEven(n-2);
}
}
console.log(isEven(50)); // true
console.log(isEven(75)); // false
console.log(isEven(-1)); // false/ / 3function countBs(str){
var count = 0;
for(var i = 0; i < str.length; i++){if(str[i] == 'B'){ count++; }}return count;
}
console.log(countBs("12B45B12B"));
function countChar(str,target){
var count = 0;
for(var i = 0; i < str.length; i++){if(str[i] == target){ count++; }}return count;
}
console.log(countChar("12A345AaA"."A")); // The official solutionfunction countChar(string, ch) {
let counted = 0;
for (let i = 0; i < string.length; i++) {
if(string[i] == ch) { counted += 1; }}return counted;
}
function countBs(string) {
return countChar(string, "B");
}
console.log(countBs("BBC"));
console.log(countChar("kakkerlak"."k"));
Copy the code
Chapter 4 data Structures: Objects and arrays
Numbers, Booleans, and strings form the basic data structure. Without any of these, you might struggle to construct a complete structure. We can construct more complex structures by using objects to organize values with other objects.
4.1 the squirrel people
4.2 the data set
JavaScript provides a data type designed to store a series of values. We call this data type array and write a series of values in square brackets, separated by commas (,).
Var listOfNumbers =,3,5,7,11 [2]; console.log(listOfNumbers[1]); // 3 console.log(listOfNumbers[1 -1]); / / 2Copy the code
4.3 attributes
In JavaScript, almost all values have attributes. But null and undefined don’t.
There are two most common methods of accessing properties in JavaScript: using points (.) And square brackets []. If a dot is used, the part after the dot must be a legal variable name, that is, write the property name directly. If square brackets are used, JavaScript treats the return value of the expression in square brackets as the attribute name.
4.4 methods
In addition to the Length attribute, string and array objects contain many other properties that are function values.
var doh = "Doh";
console.log(typeof doh.toUpperCase); // function
console.log(doh.toUpperCase()); // DOH
Copy the code
We usually refer to the property that contains a function as a method of some value. For example, “toUpperCase is a method of a string.”
var mack = [];
mack.push("Mack");
mack.push("the"."knife");
console.log(mack);
console.log(mack.join(""));
console.log(mack.pop());
console.log(mack);
Copy the code
We can use the push method to add a value to the end of the array. The POP method does the opposite: it removes the value from the end of the array and returns it to the caller. We can concatenate an array of strings into a single string using the join method, which takes the text content of the concatenated array elements.
4.5 object
The value of an object type can store attributes of any type, which can be added or deleted at will. One way to create an object is to use curly braces.
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
Copy the code
In braces, we can add a list of attributes, separated by commas. Each attribute starts with a name, followed by a colon, and then the expression for the corresponding attribute. If the attribute name is not a valid variable name or number, you need to enclose it in quotes.
var description = {
work: "Went to work"."touched tree": "Touched a tree"
}
Copy the code
Reading a nonexistent property produces undefined.
Delete is a unary operator whose operands are expressions that access properties and remove specified properties from an object.
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
Copy the code
The first operand of the binary operator in is a string representing the name of the property, and the second operand is an object that returns a Boolean indicating whether the object contains the property. The difference between setting the attribute to undefined and deleting it using DELETE is that in the first case, the object still contains the left attribute, but it does not reference any value. In the second case, the left attribute no longer exists in the object, so the IN operator returns false.
Arrays are simply special objects for storing sequences of data, so the result of typeof[1,2] execution is “Object”.
Var journal = [{events: ["work"."touched tree"."pizza"."running"."television"],
squirrel: false
},
{
events: ["work"."ice cream"."cauliflower"."lasagna"."touched tree"."brushed teeth"],
squirrel: false
}
/* and so on */
];
Copy the code
4.6 variability
Numbers, strings, and Booleans are immutable values, and we cannot modify the contents of these types of values.
But for objects, we can change the contents of the object by modifying its properties.
var object1 = {value: 10};
var object2 = object1;
var object3 = {value: 10};
console.log(object1 == object2); // true
console.log(object1 == object3); // falseobject1.value = 15; console.log(object2.value); // 15 console.log(object3.value); / / 10Copy the code
In JavaScript, when you compare two objects using the == operator, the result will return true only if both objects reference the same value. Comparing two different objects will return false, even if the objects have the same contents. There is no built-in depth comparison operator (compare object content) in JavaScript, but you can write one yourself.
4.7 Records of Squirrel Man
var journal = [];
function addEntry(events,didITurnIntoASquirrel){
journal.push({
events: events,
squirrel: didITurnIntoASquirrel
})
}
addEntry(["work"."touched tree"."pizza"."running"."television"].false);
addEntry(["work"."ice cream"."cauliflower"."lasagna"."touched tree"."brushed teeth"].false);
addEntry(["weekend"."cycling"."break"."peanuts"."beer"].true);
Copy the code
4.8 Calculating Correlation
// Calculate the array coefficient φfunction phi(table) {
return(table[3] * table[0] - table[2] * table[1])/Math.sqrt((table[2] + table[3]) * (table[0] + table[1]) * (table[1] + table[3]) * (table[0] + table[2])); } the console. The log (phi (,9,4,1 [76])); // Loop through the record and count the number of squirrel related events. var JOURNAL = [ {"events": ["carrot"."exercise"."weekend"]."squirrel":false},
{"events": ["bread"."pudding"."brushed teeth"."weekend"."touched tree"]."squirrel":false},
{"events": ["carrot"."nachos"."brushed teeth"."cycling"."weekend"]."squirrel":false},
{"events": ["brussel sprouts"."ice cream"."brushed teeth"."computer"."weekend"]."squirrel":false},
{"events": ["potatoes"."candy"."brushed teeth"."exercise"."weekend"."dentist"]."squirrel":false},
{"events": ["brussel sprouts"."pudding"."brushed teeth"."running"."weekend"]."squirrel":false},
{"events": ["pizza"."brushed teeth"."computer"."work"."touched tree"]."squirrel":false},
{"events": ["bread"."beer"."brushed teeth"."cycling"."work"]."squirrel":false},
{"events": ["cauliflower"."brushed teeth"."work"]."squirrel":false},
{"events": ["pizza"."brushed teeth"."cycling"."work"]."squirrel":false},
{"events": ["lasagna"."nachos"."brushed teeth"."work"]."squirrel":false},
{"events": ["brushed teeth"."weekend"."touched tree"]."squirrel":false},
{"events": ["lettuce"."brushed teeth"."television"."weekend"]."squirrel":false},
{"events": ["spaghetti"."brushed teeth"."work"]."squirrel":false},
{"events": ["brushed teeth"."computer"."work"]."squirrel":false},
{"events": ["lettuce"."nachos"."brushed teeth"."work"]."squirrel":false},
{"events": ["carrot"."brushed teeth"."running"."work"]."squirrel":false},
{"events": ["brushed teeth"."work"]."squirrel":false},
{"events": ["cauliflower"."reading"."weekend"]."squirrel":false},
{"events": ["bread"."brushed teeth"."weekend"]."squirrel":false},
{"events": ["lasagna"."brushed teeth"."exercise"."work"]."squirrel":false},
{"events": ["spaghetti"."brushed teeth"."reading"."work"]."squirrel":false},
{"events": ["carrot"."ice cream"."brushed teeth"."television"."work"]."squirrel":false},
{"events": ["spaghetti"."nachos"."work"]."squirrel":false},
{"events": ["cauliflower"."ice cream"."brushed teeth"."cycling"."work"]."squirrel":false},
{"events": ["spaghetti"."peanuts"."computer"."weekend"]."squirrel":true},
{"events": ["potatoes"."ice cream"."brushed teeth"."computer"."weekend"]."squirrel":false},
{"events": ["potatoes"."ice cream"."brushed teeth"."work"]."squirrel":false},
{"events": ["peanuts"."brushed teeth"."running"."work"]."squirrel":false},
{"events": ["potatoes"."exercise"."work"]."squirrel":false},
{"events": ["pizza"."ice cream"."computer"."work"]."squirrel":false},
{"events": ["lasagna"."ice cream"."work"]."squirrel":false},
{"events": ["cauliflower"."candy"."reading"."weekend"]."squirrel":false},
{"events": ["lasagna"."nachos"."brushed teeth"."running"."weekend"]."squirrel":false},
{"events": ["potatoes"."brushed teeth"."work"]."squirrel":false},
{"events": ["carrot"."work"]."squirrel":false},
{"events": ["pizza"."beer"."work"."dentist"]."squirrel":false},
{"events": ["lasagna"."pudding"."cycling"."work"]."squirrel":false},
{"events": ["spaghetti"."brushed teeth"."reading"."work"]."squirrel":false},
{"events": ["spaghetti"."pudding"."television"."weekend"]."squirrel":false},
{"events": ["bread"."brushed teeth"."exercise"."weekend"]."squirrel":false},
{"events": ["lasagna"."peanuts"."work"]."squirrel":true},
{"events": ["pizza"."work"]."squirrel":false},
{"events": ["potatoes"."exercise"."work"]."squirrel":false},
{"events": ["brushed teeth"."exercise"."work"]."squirrel":false},
{"events": ["spaghetti"."brushed teeth"."television"."work"]."squirrel":false},
{"events": ["pizza"."cycling"."weekend"]."squirrel":false},
{"events": ["carrot"."brushed teeth"."weekend"]."squirrel":false},
{"events": ["carrot"."beer"."brushed teeth"."work"]."squirrel":false},
{"events": ["pizza"."peanuts"."candy"."work"]."squirrel":true},
{"events": ["carrot"."peanuts"."brushed teeth"."reading"."work"]."squirrel":false},
{"events": ["potatoes"."peanuts"."brushed teeth"."work"]."squirrel":false},
{"events": ["carrot"."nachos"."brushed teeth"."exercise"."work"]."squirrel":false},
{"events": ["pizza"."peanuts"."brushed teeth"."television"."weekend"]."squirrel":false},
{"events": ["lasagna"."brushed teeth"."cycling"."weekend"]."squirrel":false},
{"events": ["cauliflower"."peanuts"."brushed teeth"."computer"."work"."touched tree"]."squirrel":false},
{"events": ["lettuce"."brushed teeth"."television"."work"]."squirrel":false},
{"events": ["potatoes"."brushed teeth"."computer"."work"]."squirrel":false},
{"events": ["bread"."candy"."work"]."squirrel":false},
{"events": ["potatoes"."nachos"."work"]."squirrel":false},
{"events": ["carrot"."pudding"."brushed teeth"."weekend"]."squirrel":false},
{"events": ["carrot"."brushed teeth"."exercise"."weekend"."touched tree"]."squirrel":false},
{"events": ["brussel sprouts"."running"."work"]."squirrel":false},
{"events": ["brushed teeth"."work"]."squirrel":false},
{"events": ["lettuce"."brushed teeth"."running"."work"]."squirrel":false},
{"events": ["candy"."brushed teeth"."work"]."squirrel":false},
{"events": ["brussel sprouts"."brushed teeth"."computer"."work"]."squirrel":false},
{"events": ["bread"."brushed teeth"."weekend"]."squirrel":false},
{"events": ["cauliflower"."brushed teeth"."weekend"]."squirrel":false},
{"events": ["spaghetti"."candy"."television"."work"."touched tree"]."squirrel":false},
{"events": ["carrot"."pudding"."brushed teeth"."work"]."squirrel":false},
{"events": ["lettuce"."brushed teeth"."work"]."squirrel":false},
{"events": ["carrot"."ice cream"."brushed teeth"."cycling"."work"]."squirrel":false},
{"events": ["pizza"."brushed teeth"."work"]."squirrel":false},
{"events": ["spaghetti"."peanuts"."exercise"."weekend"]."squirrel":true},
{"events": ["bread"."beer"."computer"."weekend"."touched tree"]."squirrel":false},
{"events": ["brushed teeth"."running"."work"]."squirrel":false},
{"events": ["lettuce"."peanuts"."brushed teeth"."work"."touched tree"]."squirrel":false},
{"events": ["lasagna"."brushed teeth"."television"."work"]."squirrel":false},
{"events": ["cauliflower"."brushed teeth"."running"."work"]."squirrel":false},
{"events": ["carrot"."brushed teeth"."running"."work"]."squirrel":false},
{"events": ["carrot"."reading"."weekend"]."squirrel":false},
{"events": ["carrot"."peanuts"."reading"."weekend"]."squirrel":true},
{"events": ["potatoes"."brushed teeth"."running"."work"]."squirrel":false},
{"events": ["lasagna"."ice cream"."work"."touched tree"]."squirrel":false},
{"events": ["cauliflower"."peanuts"."brushed teeth"."cycling"."work"]."squirrel":false},
{"events": ["pizza"."brushed teeth"."running"."work"]."squirrel":false},
{"events": ["lettuce"."brushed teeth"."work"]."squirrel":false},
{"events": ["bread"."brushed teeth"."television"."weekend"]."squirrel":false},
{"events": ["cauliflower"."peanuts"."brushed teeth"."weekend"]."squirrel":false}];function hasEvent(event,entry) {
return entry.events.indexOf(event) != -1;
}
functionTableFor (event,journal) {var table = [0,0,0,0];for(var i = 0; i < journal.length; i++){
var entry = journal[i];
var index = 0;
if(hasEvent(event,entry)){
index += 1;
}
if(entry.squirrel){
index += 2;
}
table[index] += 1;
}
return table;
}
console.log(tableFor("pizza",JOURNAL));
Copy the code
4.9 Object Mapping
A mapping table (MAP) can take one value (in this case, the event name) and get the corresponding value (in this case, the φ coefficient).
var map = {};
function storePhi(event,phi) {
map[event] = phi;
}
storePhi("pizza", 0.069); storePhi("touched tree",-0.081);
console.log("pizza" in map); // true
console.log(map["touched tree"]); // -0.081
Copy the code
JavaScript provides another looping statement that iterates over object properties. It looks a lot like a regular for loop, except instead of using the for keyword, we use in.
for(var event in map) {
console.log("The correlation for '" + event + "' is " + map[event]);
}
// The correlation for 'pizza'Is 0.069 // The correlationfor 'touched tree'Is 0.081Copy the code
4.10 Analysis results
To find all the event types that exist in the dataset, we simply process each record in turn and iterate through all the events in the record.
function gatherCorrelations(journal) {
var phis = {};
for(var entry = 0; entry < journal.length; entry++){ var events = journal[entry].events;for(var i = 0; i < events.length; i++){ var event = events[i];if(! (eventinphis)){ phis[event] = phi(tableFor(event,journal)); }}}return phis;
}
var correlations = gatherCorrelations(JOURNAL);
console.log(correlations.pizza);
for(var event in correlations) {
console.log(event + ":" + correlations[event]);
}
for(var event in correlations) {
var correlation = correlations[event];
if(the correlation > 0.1 | | the correlation {< 0.1). The console log (event +":"+ correlation); }}for(var i = 0; i < JOURNAL.length; i++){ var entry = JOURNAL[i];if(hasEvent("peanuts",entry) && ! hasEvent("brushed teeth",entry)){
entry.events.push("peanut teeth");
}
}
console.log(phi(tableFor("peanut teeth",JOURNAL))); / / 1Copy the code
4.11 Detail array
Some useful array methods
Push and POP, used to add or remove elements at the end of an array, respectively.
Unshift and shift, used to add or remove elements at the beginning of an array, respectively.
var todoList = [];
function rememberTo(task) {
todoList.push(task);
}
function whatIsNext() {
return todoList.shift();
}
function urgentlyRememberTo(task) {
todoList.unshift(task);
}
Copy the code
IndexOf, which searches backwards from the first element of the array.
LastIndexOf, which searches forward from the last element of the array.
Both the indexOf and lastIndexOf methods have an optional parameter that can be used to specify the starting position of the search.
The console. The log (,2,3,2,1 [1]. IndexOf (2)); / / 1 console. The log (,2,3,2,1 [1]. LastIndexOf (2)); / / 3Copy the code
Slice, which takes a start index and an end index, and then returns the elements in the array within the two index ranges. The start index element is included in the return result, but the end index element is not. If no end index is specified, Slice returns all elements from the starting position. For strings, there is a slice method for developers to use with the same functionality.
The console. The log (,1,2,3,4 [0]. Slice (2, 4)); / / [2, 3] the console. The log (,1,2,3,4 [0]. Slice (2)); / / / 2 and 4Copy the code
The concat method is used to concatenate two arrays, acting like the string + operator.
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"]
Copy the code
4.12 Strings and Their Properties
We can call attributes like length or toUpperCase of a string, but we can’t add any new attributes to the string.
var myString = "Fido";
myString.myProperty = "value";
console.log(myString.myProperty); // undefined
Copy the code
Strings, numbers, and Boolean values are not objects, so JavaScript doesn’t report an error when you add attributes to these values, but you don’t actually add them. These values are immutable, and you cannot add any attributes to them.
But these types of values contain some built-in attributes. Each string contains several methods for us to use, the most useful of which are probably Slice and indexOf, which function similarly to the methods of the same name in arrays.
console.log("coconuts"Slice (4, 7)); // nut console.log("coconuts".indexOf("u")); / / 5Copy the code
The only difference is that an indexOf method on a string can use multiple characters as search criteria, whereas an indexOf method on an array can search only for a single element.
console.log("one two three".indexOf("ee")); / / 11Copy the code
The trim method is used to remove beginning and ending whitespace (characters such as Spaces, newlines, and tabs) from a string.
console.log(" okay \n ".trim()); // okay
Copy the code
// Get a particular character in the string"abc";
console.log(string.length); // 3
console.log(string.charAt(0)); // a
console.log(string[1]); // b
Copy the code
4.13 the arguments object
Each time a function is called, a special variable arguments is added to the runtime environment of the function body. This variable refers to an object that contains all the input arguments. In JavaScript, we can pass more (or less) arguments than the number defined in the function argument list.
function noArguments() {}; NoArguments (1, 2, 3); // This is okayfunction threeArgumnents(a,b,c){};
threeArguments(); // And so is this
Copy the code
The Arguments object has a length property that represents the number of arguments actually passed to the function. Each parameter corresponds to an attribute, named 0,1,2, and so on.
function argumentCounter() {
console.log("You gave me",arguments.length,"arguments.");
}
argumentCounter("Straw man"."Tautology"."Ad hominem"); // You gave me 3 arguments.
Copy the code
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");
Copy the code
4.14 Math object
The Math object simply packages a set of related functions into a single object for use by the user. There is only one Math object globally, and the object itself has no practical use. The Math object actually provides a “namespace” that encapsulates all mathematical operations and values, ensuring that these elements do not become global variables.
Too many global variables contaminate the namespace. The more global variables you have, the more likely you are to accidentally overwrite some variable’s value.
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));
Copy the code
Math.random, which returns a pseudo-random number ranging from 0 (inclusive) to 1 (exclusive) each time this function is called.
console.log(Math.random());
console.log(Math.random());
console.log(Math.random());
Copy the code
Math.floor, round down
Math.ceil, round up
Math.round, round
console.log(Math.floor(Math.random() * 10)); // Select any number from 0 to 9 with equal probability.Copy the code
4.15 Global Objects
There are many global variables in the JavaScript global scope, all of which can be accessed through global objects. Each global variable is stored as a property in the global object. In the browser, global objects are stored in the window variable.
var myVar = 10;
console.log("myVar" in window); // trueconsole.log(window.myVar); / / 10Copy the code
4.16 Summary of this chapter
Objects and arrays (a special kind of object) can combine several values to form a new value.
In JavaScript, with the exception of null and undefined, most values contain attributes.
There are some named properties in the array, like length and some methods.
Object can be used as a mapping table to associate names with values. We can use the IN operator to determine whether an object contains attributes of a particular name. We can also use the keyword in the for loop (for (var name in object) to iterate over the properties contained in the object.
4.17 problem sets
// 1 Write a range function that takes two arguments, start and end, and returns all numbers between start and end.function range(start,end){
var arr = [];
if(start > end){
for(var i = start; i >= end;i--){
arr.push(i);
}
}else{
for(var i = start; i <= end;i++){
arr.push(i);
}
}
returnarr; } the console. The log (range (1, 10)); The console. The log (range (5, 2, 1)); // 2 Write a sum function that takes an array of numbers and returns the sum of all numbersfunction sum(arr){
var sum = 0;
for(var i = 0; i < arr.length; i++){ sum += arr[i]; }returnsum; } console.log(sum(range(1, 10))); // 3 Add-ons Modify the range function to take the third optional argument, specifying the number of steps (step) to build the array.function range(start,end,step){
var arr = [];
if(step == undefined){
step = 1;
}
if(start > end){
for(var i = start; i >= end;i= i + step){
arr.push(i);
}
}else{
for(var i = start; i <= end;i = i + step){
arr.push(i);
}
}
returnarr; } the console. The log (range,10,2 (1)); The console. The log (range (5, 2, 1)); // The official solutionfunctionrange(start, end, step = start < end ? 1:1) {let array = [];
if (step > 0) {
for (let i = start; i <= end; i += step) array.push(i);
} else {
for (let i = start; i >= end; i += step) array.push(i);
}
return array;
}
function sum(array) {
let total = 0;
for (let value of array) {
total += value;
}
returntotal; } // Reverse the arrayfunction reverseArray(arr){
var output = [];
for(var i = arr.length-1; i >= 0; i--){ output.push(arr[i]); }returnoutput; } the console. The log (reverseArray ([1, 2, 3, 4, 5])); // Reverse array 2function reverseArrayInPlace(array){
for(leti = 0; i < Math.floor(array.length / 2); i++){let old = array[i];
array[i] = array[array.length -1-i];
array[array.length-1-i]= old;
}
return array;
}
console.log(reverseArrayInPlace([1,2,3,4,5]));
// 实现列表
var list = {
value: 1,
rest: {
value: 2,
rest: {
value: 3,
rest: null
}
}
}
function arrayToList(array) {
let list = null;
for (let i = array.length - 1; i >= 0; i--) {
list = {value: array[i], rest: list};
}
returnlist; } the console. The log (arrayToList ([1, 2, 3])); // Lists are converted to arraysfunction listToArray(list) {
let array = [];
for (let node = list; node; node = node.rest) {
array.push(node.value);
}
return array;
}
function listToArray(list){
let array = [];
for(letnode = list; node; node = node.rest){ array.push(node.value); }returnarray; } console.log(listToArray(list)); Create a new listfunction prepend(value,list) {
return{ value, rest: list }; } // Returns the element at the specified position in the listfunction nth(list, n) {
if(! list)return undefined;
else if (n == 0) return list.value;
else return nth(list.rest, n - 1);
}
function nth(list,n) {
if(! list){return undefined;
}else if(n == 0){
return list.value;
}else {
returnnth(list.rest,n-1); } } console.log(list,3); Write a function deepEqual that takes two arguments. If two objects are the same value or have the same property in both objects, and deepEqual returns both valuestrueWhen to return totrue
function deepEqual(a, b) {
if (a === b) return true;
if(a == null || typeof a ! ="object"|| b == null || typeof b ! ="object") return false;
let keysA = Object.keys(a), keysB = Object.keys(b);
if(keysA.length ! = keysB.length)return false;
for (let key of keysA) {
if(! keysB.includes(key) || ! deepEqual(a[key], b[key]))return false;
}
return true;
}
Copy the code
Chapter 5 higher-order functions
Let’s briefly review two examples from the introduction. The first program contains six lines of code and can be run directly.
var total = 0,count = 1;
while(count <= 10){
total += count;
count += 1;
}
console.log(total);
Copy the code
The second program relies on external functions to execute and has only one line of code.
The console. The log (sum (range (1, 10)));Copy the code
The second program writes code that nicely expresses the problem we want to solve. This is simpler and error-free than writing the code together.
5.1 the abstract
In programming, we call this way of writing code abstraction. Abstraction hides the underlying implementation details and gives us a higher (or more abstract) view of the problem we are trying to solve.
As a programmer, we need to be able to abstract out code at the right time to form a new function or concept.
5.2 Array traversal abstraction
Var array = [1,2,3];for(var i = 0; i < array.length; i++){ var current = array[i]; console.log(current); } // 2. Abstract 1 into a functionfunction logEach(array){
for(var i = 0; i < array.length;i++){
console.log(array[i]);
}
}
function forEach(array,action){
for(var i = 0; i < array.length;i++){
action(array[i]);
}
}
forEach(["Wampeter"."Foma"."Granfalloon"],console.log); // 3. Generally speaking, we don'tforEach passes a predefined function, instead creating a new function value directly. Var numbers = [1,2,3,4,5];forEach(numbers,function(number){
sum += number;
});
console.log(sum);
Copy the code
In fact, we don’t need to write our own forEach function, which is actually a standard method for arrays.
function gatherCorrelations(journal) {
var phis = {};
for(var entry = 0; entry < journal.length; entry++){ var events = journal[entry].events;for(var i = 0; i < events.length; i++){ var event = events[i];if(! (eventinphis)){ phis[event] = phi(tableFor(event,journal)); }}}returnphis; } / / useforEach overwrites the code abovefunction gatherCorrelations(journal){
var phis = {};
journal.forEach(function(entry){
entry.events.forEach(function (event){
if(! (eventinphis)){ phis[event] = phi(tableFor(event,journal)); }})})return phis;
}
Copy the code
5.3 Higher-order functions
A function can be called a higher-order function if it operates on other functions, either as arguments or as a return value.
We can use higher-order functions to abstract a series of operations and values.
// Create some new functions using higher-order functionsfunction greaterThan(n) {
return function(m){
return m > n;
}
}
var greaterThan10 = greaterThan(10);
console.log(greaterThan10(11)); // true// Use higher-order functions to modify other functionsfunction noisy(f) {
return function(arg){
console.log("calling with",arg);
var val = f(arg);
console.log("called with",arg,"-got",val);
return val;
}
}
noisy(Boolean)(0);
// calling with 0
// called with 0 -got false// Use higher-order functions to implement the new control flowfunction unless(test.then) {
if(!test) {then();
}
}
function repeat(times,body){
for(var i = 0; i <times; i++){ body(i); } } repeat(3,function(n){
unless(n % 2,function (){
console.log(n,"is even"); })})Copy the code
5.4 Parameter Transfer
The function we defined earlier is noisy, which can cause quite a problem by passing arguments to another function.
function noisy(f) {
return function(arg){
console.log("calling with",arg);
var val = f(arg);
console.log("called with",arg,"-got",val);
returnval; }}Copy the code
If a function f takes more than one argument, then the function can only take the first argument. Function f has no way of knowing the number of arguments the caller passed to Noisy.
The Apply method of the JavaScript function solves this problem.
function transparentWrapping(f){
return function() {returnf.apply(null,arguments); }}Copy the code
The transparentWrapping function here is of no practical use, but it returns an internal function that passes all the user-specified parameters to F.
5.5 JSON
[{"name": "Emma de Milliano"."sex": "f"."born": 1876,
"died": 1956,
"father": "Petrus de Milliano"."mother": "Sophia van Damme"
},
{
"name": "Carolus"."sex": "m"."born": 1832,
"died": 1905,
"father": "Carel Haverbeke"."mother": "Maria van Brussel"}... and so on ]Copy the code
This format is the JSON format, which is short for JavaScript Object Notation. The format is widely used for data storage and Web communication.
All attribute names must be enclosed in double quotes, and only simple data expressions can be used. Function calls, variables, and any code that contains actual computation cannot be filled in.
JavaScript provides a json.stringify function to convert data into this format. There is also a json. parse function that converts the formatted data to the original data type.
var string = JSON.stringify({ name: "X",born: 1980}); console.log(string); / / {"name":"X"."born":1980} console.log(JSON.parse(string).born); / / 1980Copy the code
5.6 Array Filtering
function filter(array,test){
var passed = [];
for(var i = 0; i < array.length; i++){if(test(array[i])){ passed.push(array[i]); }}return passed;
}
console.log(filter(ancestry,function(person) {
return person.born > 1990 && person.born < 1925
}))
Copy the code
This function takes the test function as an argument to implement the filtering operation. We call test on each element in the array and return a value to determine if the current element meets the criteria.
Like forEach, the filter function is a standard method provided in arrays. The functions defined in this example are only used to demonstrate the internal implementation.
console.log(ancestry.filter(function (person){
return person.father == "Carel Haverbeke";
}))
Copy the code
5.7 Converting Arrays using the Map Function
The map method can call a function on each element in the array and then use the returned value to construct a new array that transforms the array.
function map(array,transform){
var mapped = [];
for(var i = 0; i < array.length; i++){ mapped.push(transform(array[i]); }return mapped;
}
var overNinety = ancestry.filter(function(person){
return person.died - person.born > 90;
})
console.log(map(overNinety,function(person){
return person.name;
}))
Copy the code
Like forEach and filter, map is a standard method in arrays.
5.8 Using Reduce to Summarize data
Compute a value based on the entire array.
The reduce function takes three arguments: the array, the function that performs the merge, and the initial value.
function reduce(array,combine,start) {
var current = start;
for(var i = 0; i < array.length; i++){ current = combine(current,array[i]); }returncurrent; } the console. The log (reduce ([1, 2, 3, 4],function(a,b){
returna+b; }, 0))Copy the code
Arrays have a standard Reduce method, consistent with the one we saw above, that simplifies merging.
console.log(ancestry.reduce(function(min,cur){
if(cur.born < min.born){
return cur;
}else{
returnmin; }}))Copy the code
5.9 Composability
// Implement the above example var min = ancestry[0] without using higher-order functions;for(var i = 1; i < ancestry.length; i++){ var cur = ancestry[i];if(cur.born < min.born){
min = cur;
}
}
console.log(min);
Copy the code
There are a few more variables in this code, and although there are two more lines of code, the logic is easy to understand.
The value of higher-order functions becomes apparent when you encounter situations where you need to combine functions. For example, write a piece of code to find the average age of men and women in a data set.
function average(array) {
function plus(a,b){
return a+b;
}
return array.reduce(plus) / array.length;
}
function age(p){
return p.died -p.born;
}
function male(p){
return p.sex == "m";
}
function female(p){
return p.sex == "f";
}
console.log(average(ancestry.filter(male).map(age)));
console.log(average(ancestry.filter(female).map(age)));
Copy the code
Instead of putting logic into the body of the loop, this code neatly assembles logic into several areas we care about: determining gender, calculating age, and calculating averages.
We can write logical code this way. However, writing such code comes at a cost.
5.10 Performance Cost
Passing functions to forEach to handle array iteration is really convenient and easy to read. But function calls in JavaScript are more expensive than a simple loop structure.
When a program executes slowly, the problem is often caused by only a small portion of the code in the body of the deepest nested loop.
5.11 Have ever been…… My grandfather
Var byName = {}; var byName = {}; ancestry.forEach(function(person){
byName[person.name] = person;
})
console.log(byName["Philibert Haverbeke"]); // Write the reducerooted function to extract a value from the family tree.function reduceAncestors(person,f,defaultValue){
function valueFor(person){
if(person == null){
return defaultValue;
}else{
returnf(person,valueFor(byName[person.mother]),valueFor(byName[person.father])); }}return valueFor(person);
}
function sharedDNA(person,formMother,formFather){
if(person.name == "Pauwels van Haverbeke") {return 1;
}else{
return (formMother + formFather) / 2;
}
}
var ph = byName["Philibert Haverbeke"]; console.log(reduceAncestors(ph,sharedDNA,0) / 4); // Find the percentage of ancestors that meet certain criteria, such as those over 70 years oldfunction countAncestors(person,test) {function combine(person,formMother,formFather){
var thisOneCounts = test(person);
returnfromMather + formFather + (thisOneCounts ? 1:0); }return reduceAncestors(person,combine,0);
}
function longLivingPercentage(person){
var all = countAncestors(person,function(person){
return true;
})
var longLiving = countAncestors(person,function(person){
return (person.died - person.born) >= 70;
})
return longLiving / all;
}
console.log(longLivingPercentage(byName(["Emile Haverbeke"]));
Copy the code
5.12 binding
Each function has a bind method that can be used to create new functions, called bind functions.
var theSet = ["Carel Haverbeke"."Maria van Brussel"."Donald Duke"];
function isInSet(set,person){
return set.indexOf(person.name) > -1;
}
console.log(ancestry.filter(function(person){
return isInset(theSet,person);
}))
console.log(ancestry.filter(isInSet.bind(null,theSet))); // same result
Copy the code
Calling bind returns a new function that calls isInSet with theSet as its first argument and passes to isInSet any remaining arguments passed to the function.
5.13 Summary of this chapter
Passing the value of a function type to other functions is not only useful, but also an important feature of JavaScript. We can reserve some specific operations when writing functions, and pass the specific operations as functions in the real function call, to achieve the complete calculation process.
Arrays provide a number of useful higher-order functions. ForEach is used to iterate over arrays of elements for specific purposes. Filter is used to filter out elements and construct a new array. The map builds a new array and processes each element with a function that puts the results into the new array. Reduce reduces the array elements to a value.
The function object has a apply method that calls the function and uses arrays to specify function parameters. There is also a bind method that creates a new function and predetermines some of its parameters.
5.14 problem sets
Var arrays = [[1, 2, 3], [4, 5], [6]]; var arrays = [[1, 2, 3]; console.log(arrays.reduce(function(flat, current) {
returnflat.concat(current); } [])); // 2. Calculate the age difference between mother and childfunction average(array) {
function plus(a, b) { return a + b; }
return array.reduce(plus) / array.length;
}
var byName = {};
ancestry.forEach(function(person) {
byName[person.name] = person;
});
var differences = ancestry.filter(function(person) {
returnbyName[person.mother] ! = null; }).map(function(person) {
returnperson.born - byName[person.mother].born; }); console.log(average(differences)); // 3. Calculate the average lifefunction average(array) {
function plus(a, b) { return a + b; }
return array.reduce(plus) / array.length;
}
function groupBy(array, groupOf) {
var groups = {};
array.forEach(function(element) {
var groupName = groupOf(element);
if (groupName in groups)
groups[groupName].push(element);
else
groups[groupName] = [element];
});
return groups;
}
var byCentury = groupBy(ancestry, function(person) {
return Math.ceil(person.died / 100);
});
for (var century in byCentury) {
var ages = byCentury[century].map(function(person) {
return person.died - person.born;
});
console.log(century + ":"+ average(ages)); } // 4. Use every and somefunction every(array, predicate) {
for (var i = 0; i < array.length; i++) {
if(! predicate(array[i]))return false;
}
return true;
}
function some(array, predicate) {
for (var i = 0; i < array.length; i++) {
if (predicate(array[i]))
return true;
}
return false; } console.log(every([NaN, NaN, NaN], isNaN)); / / -trueconsole.log(every([NaN, NaN, 4], isNaN)); / / -falseconsole.log(some([NaN, 3, 4], isNaN)); / / -trueconsole.log(some([2, 3, 4], isNaN)); / / -false
Copy the code
Chapter 6: Understand objects in depth
6.1 history
6.2 methods
Methods simply refer to properties of function values. Here’s a simple way to do it:
var rabbit = {};
rabbit.speak = function(line){
console.log("The rabbit says '" + line + "'");
}
rabbit.speak("I'm alive."); // The rabbit says 'I'm alive.'
Copy the code
Methods usually perform some action when the object is called. When a function is called as a method of an object, the corresponding property in the object is found and called directly. When object.method() is called, a special variable in the object, this, points to the object to which the current method belongs.
function speak(line){
console.log("The " + this.type + " rabbit says '" + line + "'");
}
var whiteRabbit = { type: "white",speak: speak };
var fatRabbit = { type: "fat",speak: speak };
whiteRabbit.speak("Oh my ears and whiskers, " + "how late it's getting!");
fatRabbit.speak("I could sure use a carrot right now.");
// The white rabbit says 'Oh my ears and whiskers, how late it's getting!'
// The fat rabbit says 'I could sure use a carrot right now.'
Copy the code
This code uses the keyword this to output the type of rabbit that is talking. Recall that the apply and bind methods accept the first argument that can be used to simulate a call to a method on an object. These two methods copy the first argument to this.
The call function has a call method, similar to the apply method. This method can also be used for function calls, but it takes arguments just like a normal function, and we don’t need to put them in an array. As with the apply and bind methods, you can pass a specific this value to the call method.
speak.apply(fatRabbit,["Burp!"]); // The fat rabbit says 'Burp! '
speak.call({type: "old"},"Oh my."); // The old rabbit says 'Oh my.'
Copy the code
6.3 the prototype
Let’s take a closer look at the following code.
var empty = {}; console.log(empty.toString); / / ƒtoString() { [native code] }
console.log(empty.toString()); // [object Object]
Copy the code
In addition to having its own attributes, almost every object contains a prototype. A stereotype is another object, a source of properties for that object. When a developer accesses a property that an object does not contain, the property is searched from the object prototype, followed by the prototype of the prototype, and so on.
So what is the prototype for an empty object? Object. Prototype, which is the parent of the prototype in all objects.
console.log(Object.getPrototypeOf({}) == Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype)); // null
Copy the code
JavaScript Object prototype relationship is a tree structure, the root of the whole tree structure is Object.prototype. Object.prototype provides methods that can be used on all objects. For example, the toString method converts an object to its string representation.
Many objects don’t use Object.prototype directly as their prototype. Instead, they use another prototype Object that provides their own default properties. Functions inherit from function. prototype and arrays inherit from array. prototype.
console.log(Object.getPrototypeOf(isNaN) == Function.prototype); // true
console.log(Object.getPrototypeOf([]) == Array.prototype); // true
Copy the code
For such prototype objects, they also contain a prototype Object, usually Object.prototype, so they can provide methods like toString indirectly.
var protoRabbit = {
speak: function(line){
console.log("The " + this.type + " rabbit says '" + line +"'");
}
}
var killerRabbit = Object.create(protoRabbit);
killerRabbit.type = "killer";
killerRabbit.speak("SKREEEE!"); // The killerrabbit says 'SKREEEE! '
Copy the code
The prototype object protoRabbit is a container that contains the public properties of all rabbit objects. Each individual rabbit object (such as killerRabbit) can contain its own attributes (such as the Type attribute in this example) or can derive attributes that are common to its prototype object.
6.4 Constructors
In JavaScript, adding the keyword new before calling a function means calling its constructor. The constructor contains the variable this that points to the new object, and returns the newly created object unless the constructor explicitly returns the value of another object.
The object created with the keyword new is called an instance of the constructor.
Here is a simple constructor for creating rabbit. Constructor names generally start with a capital letter.
function Rabbit(type){
this.type = type;
}
var killerRabbit = new Rabbit("killer");
var blackRabbit = new Rabbit("black");
console.log(blackRabbit.type); // black
Copy the code
For constructors (in fact, for all functions), you automatically get a property called Prototype. By default, this property is a plain empty Object derived from Object.prototype. All objects created using a particular constructor will have the constructor’s Prototype property as their prototype. Therefore, we can easily add the Speak method to all objects created using the Rabbit constructor.
Rabbit.prototype.speak = function(line){
console.log("The " + this.type + " rabbit says '" + line +"'");
}
blackRabbit.speak("Doom...");
Copy the code
Constructors are functions, so the actual prototype is function.prototype. The constructor’s Prototype property is the prototype of the instance it creates, not the prototype of the constructor itself.
6.5 Overriding inherited attributes
When you add a property to an object, regardless of whether the property already exists in the object stereotype, the property is added to the object and used as its own genus. If there is a property with the same name in the stereotype, when you call that property, you don’t call the property in the stereotype anymore, you call the property we added to the object instead. But the prototype itself will not be modified.
Rbbit.prototype.teeth = "small";
console.log(killerRabbit.teeth); // small
killerRabbit.teeth = "long, sharp, and bloody";
console.log(blackRabbit.teeth); // small
console.log(killerRabbit.teeth); // long, sharp, and bloody
console.log(Rabbit.prototype.teeth); // small
Copy the code
Overwriting properties that exist in stereotypes is a useful feature.
We can also provide a toString method for standard functions and array prototypes that is different from the Object prototype.
console.log(Array.prototype.toString == Object.prototype.toString); // falseThe console. The log ([1, 2]. The toString ()); / / 1, 2Copy the code
Call directly using the array Object. The prototype. ToString will produce a different string.
The console. The log (Object. The prototype. ToString. Call ([1, 2])); // [object Array] ps: the best method for detecting object typesCopy the code
6.6 Prototype contamination
We can always add new properties and methods using prototype objects.
Rabbit.prototype.dance = function(){
console.log("The " + this.type + " rabbit dances a jig.");
}
killerRabbit.dance(); // The killer rabbit dances a jig.
Copy the code
Review the example in Chapter 4:
var map = {};
function storePhi(event,phi){
map[event] = phi;
}
storePhi("pizza", 0.069); storePhi("touched tree",-0.081);
Copy the code
We can use a for/in loop to iterate over all the PHI coefficients in an object and use the IN operator to test whether the object contains the corresponding attributes. Unfortunately, this approach looks for properties in the object’s prototype.
Object.prototype.nonsense = "hi";
for(var name in map){
console.log(name);
}
// pizza
// touched tree
// nonsense
console.log("nonsense" in map); // true
console.log("toString" in map); // true
Copy the code
ToString does not appear in the for/in loop and returns true when tested using the IN operator. This is because JavaScript distinguishes between an enumerable and a nonenumerable property.
All properties we create and assign to objects are enumerable. The standard properties in Object.prototype are not enumerable, so they do not appear in for/ IN loops.
We can define our own non-enumerable properties using the Object.defineProperty function.
Object.defineProperty(Object.prototype,"hiddenNonsense",{
enumerable: false,
value: "hi"
})
for(var name in map){
console.log(name);
}
// pizza
// touched tree
console.log(map.hiddenNonsense); // hi
Copy the code
The regular IN operator would assume that the properties in Object.prototype are present in our Object. The object’s hasOwnProperty method tells us whether the object itself contains a property, rather than searching for its prototype.
console.log(map.hasOwnProperty("toString")); // false
Copy the code
When you are worried that someone (some other code loaded into your program) will interfere with the prototype of the underlying object, I recommend using the for/in loop like this:
for(var name in map){
if(map.hasOwnProperty(name)){
// ... this is an own property
}
}
Copy the code
6.7 No Prototype Object
We can use the object.create function and create objects based on a specific prototype. You can pass NULL as a prototype and create a prototype-free object.
var map = Object.create(null);
map["pizza"] = 0.069;
console.log("toString" in map); // false
console.log("pizza" in map); // true
Copy the code
6.8 polymorphic
When writing a piece of code, we can work with objects that contain specific interfaces. In this case, the toString method, we can insert objects into our code and keep it working as long as they support these interfaces.
We call this technique polymorphism. That’s what we call it, even though we didn’t change the shape of anything in the process. We can use polymorphism to manipulate different types of values, as long as the values support the desired interface.
6.9 Drawing a Table
Let’s take a closer look at the idea of polymorphism and object-oriented programming with a slightly more complex example. We write a program to convert a two-dimensional array of table cells into a string, which contains the corresponding two-dimensional array and the layout of the table, each column must be straight and tidy, and each row must be aligned.
First, the program calculates the minimum width of each column and the maximum height of each row and saves them into an array. The variable rows is a two-dimensional array in which each array element represents a row of cells.
function rowHeights(rows){
return rows.map(function(row){
return row.reduce(function(max,cell){
returnMath.max(max,cell.minHeight()); }, 0); }); }function colWidths(rows){
return rows[0].map(function(_,i){
return rows.reduce(function(max,row){
returnMath.max(max,row[i].minWidth()); }, 0); }); }Copy the code
Here is the code to draw the table:
function drawTable(rows) {
var heights = rowHeights(rows);
var widths = colWidths(rows);
function drawLine(blocks,lineNo){
return blocks.map(function (block){
return block[lineNo]
}).join("");
}
function drawRow(row,rowNum) {
var blocks = row.map(function(_,lineNo){
return drawLine(blocks,lineNo);
}).join("\n");
}
return rows.map(drawRow).join("\n");
}
Copy the code
Now, let’s write a constructor that creates text cells to implement the table’s cell interface.
function repeat(string,times){
var result = "";
for(var i = 0; i < times; i++){
result += string;
}
return result;
}
function TextCell(text){
this.text = text.split("\n");
}
TextCell.prototype.minWidth = function() {return this.text.reduce(function (width,line){
return Math.max(width,line.length);
},0)
}
TextCell.prototype.minHeight = function() {return this.text.length;
}
TextCell.prototype.draw = function(width,height){
var result = [];
for(var i = 0; i < height; i++){ var line = this.text[i] ||"";
result.push(line + repeat("",width - line.height));
}
return result;
}
Copy the code
Let’s use the program we’ve written to create a 5 by 5 checkerboard.
var rows = [];
for(var i = 0; i < 5; i++){
var row = [];
for(var j = 0; j < 5; j++){if((j + i) % 2 == 0){
row.push(new TextCell("# #"));
}else{
row.push(new TextCell(""));
}
}
rows.push(row);
}
console.log(drawTable(rows));
Copy the code
Getter and Setter
In an object, the get or set methods are used to specify the read and modify functions of the property, which are automatically called when the property is read or modified.
var pile = {
elements: ["eggshell"."orange peel"."worm"],
get height() {return this.elements.length;
},
set height(value){
console.log("Ignoring attempt to set height to",value"); } } console.log(pile.height); // 3 pile.height = 100; // Ignoring attempt to set height to",value
Copy the code
6.11 inheritance
Update from time to time every day ~, welcome criticism and correction ~