Back
Featured image of post JavaScript | FCC Basic Record

JavaScript | FCC Basic Record

基础写这里,这样一篇文章直接ctrl+F 找到,又方便了很多

背景

所有内容大致基于freecodecamp,是一些总结出来常用的需要记住的内容。

basic JavaScript

这个部分是113个小题目,我觉得难点是 Recursion 以及针对对象的各种处理。

JavaScript object

object值的覆盖

const cat = {
  "name": "Whiskers",
  "legs": 4,
  "tails": 1,
  "enemies": ["Water", "Dogs"]
};

变为如下以后,legs的值变为了5,也没报错。

    const cat = {
  "name": "Whiskers",
  "legs": 4,
  "legs": 5,
  "tails": 1,
  "enemies": ["Water", "Dogs"]
};

对象的properies命名有几种方式

如果prop有空格,必然需要引号来括号起来:

    const cat = {
  "the name": "Whiskers",
  "how much legs": 4,
  "howMuch tails": 1,
  "whois enemies": ["Water", "Dogs"]
};

如果prop没有空格,那么就爱用不用引号:

const anotherCat = {
  name: "niconico",
  legs: 4,
  tails: 1,
  enemies: ["Water", "Dogs"]
};

获取对象属性 access object prop

如果prop没空格,可以采用notation(.)来获取

const anotherCat = {
  name: "niconico",
  legs: 2,
  tails: 9,
  enemies: ["vegetables", "DRM"]
};
console.log(anotherCat.name)
// niconiconi

如果prop有空格,只能采用bracket notation([])来获取

    const cat = {
  "the name": "Whiskers",
  "how much legs": 4,
  "howMuch tails": 1,
  "whois enemies": ["Water", "Dogs"]
};
console.log(cat["the name"])
// Whiskers

Nested Object情况,需要保证以上两点。

删除对象的prop, delete objects prop

只需要在获取的添加一个关键词 delete

const cat = {
  "name": "Whiskers",
  "legs": 4,
  "tails": 1,
  "enemies": ["Water", "Dogs"]
};
/**step 1
删除掉的是该元素内容,而非元素**/
delete cat.enemies[0]
console.log(cat.enemies)
// [null,"Dogs"]

/**step 2 
删除掉的是元素**/
delete cat.legs
console.log(cat)
/**
{name: 'Whiskers', tails: 1, enemies: Array(2)}
**/

对象是否有某个prop

method of objects .hasOwnProperty(propname)

const niconiconi = {
  name: "niconiconi",
  hobbies: ["electric","computer tech"],
  enemies: ["GOV", "cat"],
  1:100
};
/**step 1 ,
双引号的存在还是很必要的,即便原本的prop并没有引号。**/
console.log(niconiconi.hasOwnProperty("name"));
// true
console.log(niconiconi.hasOwnProperty(name));
// false

/**step 2 ,
这个是自然没有的**/
console.log(niconiconi.hasOwnProperty("weight"));
// false

/**step 3,
数字又可以被直接读到**/
console.log(niconiconi.hasOwnProperty(1));
// true
console.log(niconiconi.hasOwnProperty("1"));
// true

/**step 4,
问题再次出现,和name区别很大**/
console.log(niconiconi.hasOwnProperty("hobbies"));
// true
console.log(niconiconi.hasOwnProperty(hobbies));
// Uncaught ReferenceError: hobbies is not defined

prop in object

const niconiconi = {
  name: "niconiconi",
  hobbies: ["electric","computer tech"],
  enemies: ["GOV", "Job"],
  "sex":"cute girl",
  1:100
};
console.log("name" in niconiconi);
// true
console.log(name in niconiconi);
// false
console.log("1" in niconiconi);
// true
console.log(1 in niconiconi);
// true
console.log("hobbies" in niconiconi);
// true
console.log("sex" in niconiconi);
// true
console.log(sex in niconiconi);
// Uncaught ReferenceError: sex is not defined

Destructuring Assignment about object

点击跳转

Object Literal Declarations

这个还是值得说一下,主要是当你想当然的以为=> 后是{ ... },它给你一个({...}), 一种简写形式可以说是。

const getMousePosition = (x, y) => ({
  x: x,
  y: y
});
// 推荐使用下面这种,更简单。
const getMousePosition = (x, y) => ({ x, y });
console.log(getMousePosition(2,4));
// {x: 2, y: 4}


// 另一个例子,我感觉这个生成对象的方法还是蛮简单的,毕竟很多时候确实, 懒得写。

const createPerson = (name, age, gender) => {
  // Only change code below this line
  return ({name,age,gender});
  // Only change code above this line
};
const test = createPerson("tom",16,"F");
// test = {name: 'tom', age: 16, gender: 'F'}

Recursion 递归

先空起,做题是做起了,但是感觉再稍微难一点的绝对又做不起了。想法不是太清晰。

var,let,const的区别

var的使用:global,function,redeclared

下面这个用在了函数内,因此只有函数内的引用是合法的,全局并未定义过,所以会error

function numArray(num){
  var numArray = [];
  for (var i = 0; i < num; i++) {
  numArray.push(i);
}
  console.log(i);
  return numArray;
}
console.log(numArray(5));
// 5
// [0, 1, 2, 3, 4]
console.log(i);
// error: i is not defined

但是,当全局有过这个东西,那么就会在这个层级去读取,而且,var的变量是可以在同一层级覆盖声明的。

var i = 100;
function numArray(num){
  var numArray = [];
  for (var i = 0; i < num; i++) {
  numArray.push(i);
}
  console.log(i);
  return numArray;
}
console.log(numArray(5));
// 5
// [0, 1, 2, 3, 4]
console.log(i);
// 100
var i = 99;
console.log(i);
// 99

let的使用:block,statement,expression

下面这个使用了let,首先let的declaration的区域是比较狭窄的,可以比function更细的粒度。同时不能在一个作用区域覆盖声明。

let i = 100;
function numArray(num){
  var numArray = [];
  for (let i = 0; i < num; i++) {
  numArray.push(i);
}
  console.log(i);
  return numArray;
}
console.log(numArray(5));
// 100
// [0, 1, 2, 3, 4]
console.log(i);
// 100
let i = 99;
console.log(i);
// error: 'i' has already been declared

尽管不能redeclared,但是let 可以进行内容的改写。reassign the value

let i = 100;
i = 99;
console.log(i);
// 99

let test = ["hello",1,2];
test = [100,99,98];
test[4] = "hellotest";
console.log(test);
// [100, 99, 98, empty, 'hellotest']

const的使用:Read-Only,Mutate Array&Function

const和let非常像,作用域类似,也不能redeclared。

但多了一条:不能进行内容改写 。Read-Only,NOT reassign the value

const i = 100;
i = 99;
console.log(i);
// TypeError: Assignment to constant variable.

当作为一个固定的常量时候,通常使用全大写和下滑线_符号的作为声明。

const NUMBER = 100;
const MAX_NUM = 999;
const MIN_NUM = 0;

const 用于 Mutate an Array Declared,

const testArray = ["hello","你好","Bonjour"];
testArray[0]="halo";
console.log(testArray);
// ['halo', '你好', 'Bonjour']


console.log(testArray);
// TypeError: Assignment to constant variable.

const 用于object:

const testObject = {
  1:100,
  2:200,
  3:300
};
testObject[1] = 111;
console.log(testObject);
// {1: 111, 2: 200, 3: 300}


testObject = {
  1:111,
  2:222,
  3:333
};
console.log(testObject);
// TypeError: Assignment to constant variable.

const 在function中的表现:

  function numArray(num){
  const numArray = [];
  for (let i = 0; i < num; i++) {
  numArray.push(i);
}
  console.log(i);
  // i is not defined
  return numArray;
}
console.log(numArray(5));
// [0, 1, 2, 3, 4]

上中let i = 0倘若更改为const i = 0 则会报错(TypeError: Assignment to constant variable.),因此需要变动的量,使用let而非const.

小结

  • var ,let , const 都可以作为变量声明用。
  • const更为常用,实在需要变通的地方,用let。ES6中这两更为常见,抛弃var吧。
  • 即便是const 定义常规变量也会出现“一不小心mutation value”的情况,因此:
 function freezeObj() {
  const MATH_CONSTANTS = {
    PI: 3.14
  };
Object.freeze(MATH_CONSTANTS);
  
  try {
    MATH_CONSTANTS.PI = 99;
  } catch(ex) {
    console.log(ex);
  }
  return MATH_CONSTANTS.PI;
}
const PI = freezeObj();
// TypeError: Cannot assign to read only property 'PI' of object '#<Object>'

Object.freeze(obj); 也是更严格的“prevent object mutation” 手段。

Arrow Function

arrow function是ES6特有的,=> 作为特征。JavaScript中很喜欢直接声明变量后直接写函数对应起来,因此这样的箭头指向也具有识别度。

const name = function()

Anonymous function

东西多就放{},东西少就直接跟。anonymous函数感觉主要就是不传参,想看看实际项目里怎么用到的。

/*step 1: string */
const MARRY = () => "Marry Christmas";

console.log(MARRY(123));
// Marry Christmas

/* step 2 object */
const nico = {
  name:"niconiconi",
  sex:"girl"
}
const WIFE = () => nico;
console.log(WIFE(['smart','lovely','keyboard genius','cat','1999\'s after']));
// {name: 'niconiconi', sex: 'girl'}

/* step 3 Oprator*/
const test1 = ()=> true & true;
console.log(test1());
// 1
const test2 = ()=> true & false;
console.log(test2());
// 0
const test3 = ()=> 199+201;
console.log(test3());
// 400

/* step 4 function */
const magic =() => {return new Date();}
console.log(magic);
//() => {return new Date();}
console.log(magic(1));
// Wed Jan 12 2022 22:51:48 GMT+0800 (China Standard Time)

Parameters Function

普通一点的传参,要多少,传多少

const multiplier = (item, multi) => item * multi;
console.log(multiplier(1111,1111));
// 1234321

const arrConcat = (arr1,arr2) => {
  return arr1.concat(arr2);
}
console.log(arrConcat(["hello","baby"],['Do ','you ','like ','me']));
// ['hello', 'baby', 'Do ', 'you ', 'like ', 'me']

稍微体面点的传参,稍微设定一下

const arrConcat = (arr1,arr2="sweet heart") => {
  return arr1.concat(arr2);
}
console.log(arrConcat(['Do ','you ','love ','me']));
// ['Do ', 'you ', 'love ', 'me', 'sweet heart']

更弹性的传参,“来多少,收多少”

const sum = (...args) => {
  const reducer = (a,b) => a+b; 
  return args.reduce(reducer);
}
console.log(sum(1,2,3,4,5,6));
// 21

扩展阅读

The rest parameter eliminates the need to check the args array and allows us to apply map(), filter() and reduce() on the parameters array.

Declarative Functions with ES6 in a Object

不得不说,对象里面定义函数,还是蛮不错的,简单好懂,结构也清晰。

const person = {
  name: "Taylor",
  sayHello() {
    return `Hello! My name is ${this.name}.`;
  },
  age:18,
  afterYears(num){
    return `after ${num} years,he is ${this.age+num} years old.`
  }
};
console.log(person.sayHello())
//Hello! My name is Taylor.
console.log(person.afterYears(15));
// after 15 years,he is 33 years old.

spread operator

ES6引入的一个操作,典型操作是expand/speard arrays

MDN spread operator

sum of number array

const arr = [6, 89, 3, 45];
const maximus = Math.max(...arr);
// maximus = 89

其他求和方法:for, reduce(), lodash

copy array to new array

// shallow copy
const arr = [6, 89, 3, 45];
const arr2 = [...arr];
// arr2 = [6, 89, 3, 45];

其他clone方法:

Destructuring Assignment

Destructuring assignment is special syntax introduced in ES6, for neatly assigning values taken directly from an object.'

Extract Values from Objects

const HIGH_TEMPERATURES = {
  yesterday: 75,
  today: 77,
  tomorrow: 80
};
const {today,tomorrow} =  HIGH_TEMPERATURES;
// today = 77
// tomorrow = 80

Extract Values and Rename from Objects

const HIGH_TEMPERATURES = {
  yesterday: 75,
  today: 77,
  tomorrow: 80
};
const {today:hiToday,tomorrow:hiTomorrow} =  HIGH_TEMPERATURES;
// hiToday = 77
// hiTomorrow = 80

Assign Variables from Nested Objects

const HIGH_TEMPERATURES = {
  yesterday: 75,
  today: {
      low:66,
      high:88,
      avange:77
},
  tomorrow: 80
};
const {today:{low:hiLT,high:hiHT}} =  HIGH_TEMPERATURES;
// hiLT = 66;
// hiHT = 88;

Assign Variables from Arrays

var [a, b,,, c] = [1, 2, 3, 4, 5, 6];
// a = 1, b = 2;
// c = 5;
var [a,b,...c] = [1, 2, 3, 4, 5, 6];
// a = 1, b = 2;
// c = [3, 4, 5, 6];

Pass an Object as a Function’s Parameters

当需要传参的是一个对象,大概率不是要个对象,而是对象的一些 key 和 value,可以使用Destructuring Assignment的方式,省略函数内部取值的步骤。算是个简写方法,个人不太喜欢。

const stats = {
  max: 56.78,
  standard_deviation: 4.34,
  median: 34.54,
  mode: 23.87,
  min: -0.75,
  average: 35.85
};
// 一般写法
const half = (stats) => {
  return (stats.min+stats.max)/2;
}
// Destructuring Assignment
const half = ({min,max}) =>{
   return (min +max) /2;
} 

Template Literals

a special type of string, multi-line, string interpolation.

string template literals

const result = {
  success: ["max-length", "no-amd", "prefer-arrow-functions"],
  failure: ["no-var", "var-on-top", "linebreak"],
  skipped: ["no-extra-semi", "no-dup-keys"]
};

function makeList(arr) {
  const failureItems = [];
  for(let i = 0; i< arr.length; i++){
    let item = `<li class=\"text-warning\">${arr[i]}</li>`
    failureItems.push(item);
  }

  return failureItems;
}

const failuresList = makeList(result.failure);
// failuresList = [
//    '<li class="text-warning">no-var</li>', 
//    '<li class="text-warning">var-on-top</li>', 
//    '<li class="text-warning">linebreak</li>'
//    ]

class Syntax

和java啥的里面的class不是一个东西,只是一个比较特别的函数。

class Syntax to Define a Constructor Function

A class may only have one constructor, 一个class只能有一个constructor。我觉得也算对象快捷生成的一种办法。但这么看还是 Object Literal Declarations 这个方法更简洁。

class Vegetable {
  constructor(name,weight,color){
    this.name = name;
    this.weight = weight;
    this.color = color;
  }
}

const carrot = new Vegetable('carrot',1.1,"light green");
console.log(carrot); 
// {
//    "name": "carrot",
//    "weight": 1.1,
//    "color": "light green"
// }

getters and setters to Control Access to an Object

getters 和setter乍看感觉没啥用,没啥优越性的感觉。

getter拿来取某个key的value,只是定义了一个简写,以前是“把狗王头上悬着的那把达摩克斯拿给我”,现在是“狗王之剑”/“kkj”(看看剑) ,这种“暗号”就知道啥意思。

setter 是 更改某个key的value,也是定义了一个简写,“今天起你就叫《大宝剑》了”,改成了“Hi,《大宝剑》”,没意思。

对同一个key来说,这两不用同时都必须写,按需要写。

class Vegetable {
  constructor(name,weight,color){
    this.name = name;
    this.weight = weight;
    this.color = color;
  }
  //getter
  get wt(){
      return this.weight
  }
  // setter
  set wt(num){
    this.weight = num;
  }
}

const carrot = new Vegetable('carrot',1.1,"light green");
console.log(carrot); 
// {name: 'carrot', weight: 1.1, color: 'light green'}

这种简写不是一个函数,虽然用了很像函数的结构。

console.log(carrot.wt);
// 1.1
console.log(carrot.wt());
// error: carrot.wt is not a function

可以看到实现了更改的效果,而且是深更改?shallow edit?有这个说法吗,类比shallow copy 和deep copy。

carrot.wt = 1.2
console.log(carrot.wt);
// 1.2
//carrot {name: 'carrot', weight: 1.2, color: 'light green'}

但是,不用这个方法,直接改也不是不行。所以不知道优势是什么。

carrot.name = "hello";
console.log(carrot); 
// {name: 'hello', weight: 1.2, color: 'light green'}

Module Script

这个章节我觉得巨重要,一个项目结构和功能分布,让人读代码和用代码都爽得一批,怎么安排module是个学问大概。

个人觉得MDN的JavaScript modules 提供的modules example 是比较不错的,先下下来,不用每行都读懂,只看怎么安排import 和export和文件。

basic module

Simple example that demonstrates module basics

文件结构大概是这样,html的预览需要启用vscode里的live server,不然要报错,有个解决办法是file:// 这个就不学了。

  • index.html
  • src
    • main.js
  • lib
    • counter.js

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>测试basic module的使用</title>
    <!-- 引入了一个main.js -->
    <script type="module" src="src/main.js"></script>
</head>
<body>
    
</body>
</html>

main.js

import { add,sub } from "../lib/counter.js";

const test1 = add(1,2);
const test2 = sub(5,100);
console.log(test1,test2);
// 这一行的输出,确实出现在index.html的console

counter.js

const add = (a ,b) => {
  return a+b;
}

const sub = (a,b) => {
  return b-a;
}
export {add,sub};

Export and Import Fallback with export default

export 的就是个函数的retun,也只准file/module有一个。所以经常被用作fallback value for a file or module.

export default 不准用于 var ,let ,const

export default function subtract(x, y) {
  return x - y;
}

在被引用的文件,就是如下导入

import subtract from "url"  
subtract(7,4);

总结:import 和export是一对,按理说需要同时存在。html不是编程语言的原因:只是一个厨房,但是厨房能用起来主要还是靠里面的厨具和工具。

renaming

Shows how exports can be renamed to avoid conflicts, using x as y syntax

同上部分相比,变化如下:

main.js

import { add as newAdd } from "../lib/counter.js";
const test3 = newAdd(3,4);
console.log(test3);

感觉这个在引入多个js文件中的多个function时候有用,毕竟,干活用的英语单词就那么多,很容易重名。(侧面说明注释也很重要,不然看起来真的就跟“找不同”游戏有点像了。)

module-objects

Shows how to import an entire module as an object using import * as x from ‘y.js’ syntax

同上部分相比,变化如下: main.js

import * as counted  from "../lib/counter.js";
const test4 = counted.add(5,6);
const test5 = counted.sub(1,10);
console.log(test4,test5);

这个办法蛮好的,更精简,也等于标注了内容的来源,看起来用起来肯定舒服的。

classes

importing a class from a module

这个要重新写class,重新写的内容比较多。 main.js

import {makeNum as test} from "../lib/counter.js";
const num1 = new test(100);
console.log(num1.value);
// 100
console.log(num1.cube());
// 10000
console.log(num1.cicleC());
// 628.3185307179587

counter.js

class makeNum{
  constructor(value){
    this.value = value;
  }
  cube() {
    const cube = this.value * this.value;
    return cube;
  }
  
  cicleC()  {
    return 2 * Math.PI * this.value;
  }
}

export {makeNum};

module-aggregation

Shows how sub module features can be aggregated into a parent module using export { x } from ‘y.js’ syntax

就是当引入的js多了,有些可以合并,但是又不想真的合并成一个js文件,就会考虑用这个办法写个清单,最后的main.js 引用这个清单就好。

这个举例一下结构,假设原本的main.js

import {makeNum as make} from "../lib/file1.js";
import {sumNum as sum} from "../lib/file2.js";
import {subNum as sub} from "../lib/file3.js";
import {roundNum as round} from "../lib/file4.js";
import {bigNum as big} from "../lib/file5.js";
import {smallNum as small} from "../lib/file6.js";

确实太多了,而且又都是同类操作/同一个业务模块,就会新增一个文件夹在lib下,把文件挪进去。在number文件夹同级,新增一个文件:number.js

  • lib
    • numer
      • file1.js
      • file2.js
      • file3.js
      • file4.js
      • file5.js
      • file6.js
    • number.js

number.js

export {makeNum as make} from "./number/file1.js";
export {sumNum as sum} from "./number/file2.js";
export {subNum as sub} from "./number/file3.js";
export {roundNum as round} from "./number/file4.js";
export {bigNum as big} from "./number/file5.js";
export {smallNum as small} from "./number/file6.js";

main.js 就会变成如下神清气爽的样子,但是看看number.js,哪有什么岁月静好,都是别的文件为你负重前行……

import {make,sum,sub,round,big,small} from "../lib/number.js";

dynamic-module-imports

Demonstrates dynamic module loading using import().then()

稍微看了下,现在暂时没必要学,因为我写不出一个sample来说明。

JavaScript Promise

这个感觉是一种类似linux进程管理(阻塞,挂起,结果),或者代码中if... else..., try...catch 这种对单元事件的流程管控。 估计是JavaScript中这种事情太多了,给整出一个这个来简化。 promise本身是个函数。

要么在pending,要么在resolve ,要么在reject,就这三个状态,对于一个事件。

悄咪咪:我确实对各种异常处理深恶痛绝。

Create a JavaScript Promise

new关键词配套的就是class函数,所以promise是函数没跑,下面例子中,Promise() ,()中接受的是一个函数(resolve, reject) => {}作为参数。

const makeServerRequest = new Promise((resolve, reject) => {

});

Complete a Promise with resolve and reject

就是两条路,resolve了就咋办,reject了就咋办。if else 的复杂版?

const makeServerRequest = new Promise((resolve, reject) => {
  // responseFromServer represents a response from a server
  let responseFromServer;
    
  if(responseFromServer) { 
    resolve("We got the data");
  } else {  
    reject("Data not received");
  }
});

Handle a Fulfilled Promise with then

then等于是个额外操作,就是流程之上你再安排个流程。毕竟resolve和reject两个分支就会走一个,走完就直接关掉了。估计是这个原因,搞了个then用来延长整个函数的运行范围。

const makeServerRequest = new Promise((resolve, reject) => {
  // responseFromServer is set to true to represent a successful response from a server
  let responseFromServer = true;
	
  if(responseFromServer) {
    resolve("We got the data");
  } else {	
    reject("Data not received");
  }
});
// Add the then method to your promise. Use result as the parameter of its callback function and log result to the console.
makeServerRequest.then(result => {
  console.log(result);
});

Handle a Rejected Promise with catch

感觉then不一定要有,但是catch一定要有….不然reject也不能说毫无意义吧就是写bug已经很多了,还要改,能轻松一点就轻松一点。

const makeServerRequest = new Promise((resolve, reject) => {
  // responseFromServer is set to false to represent an unsuccessful response from a server
  let responseFromServer = false;
    
  if(responseFromServer) {
    resolve("We got the data");
  } else {  
    reject("Data not received");
  }
});

makeServerRequest.then(result => {
  console.log(result);
});
makeServerRequest.catch(error => {
  console.log(error);
});

总结,可以看出来,promise主要还是个true为主,毕竟catch是reject运作才跑,没事抛出什么error?设计上应该是都是尽量走true,这样写起来也更墨守成规(褒义)。

完结

虽然FCC还有以下大章节

这么多大章节没搞,但是这篇博客我还是决定完结,因为REGEX完全值得单独开一篇记录…..

别的其实都是个大项目,再照抄FCC我感觉用处不大,不如之后单独再开。

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy