📚 JavaScript 語法基礎

📚 JavaScript 語法基礎
Photo by Claudio Schwarz / Unsplash

Variables

  • let name; // undefined
  • let name = 'Jamie';
  • 盡量一行一個變數宣告,這是 best practice

Constant

  • const interestRate = 0.2;
  • 如果不會改變,盡量用 const 而不是 let

Primitives/Value types

  • number
  • string
  • boolean
  • symbol
  • undefined
  • null
let name = "jamie"; // string
let age = 30; // number
let isApproved = false; // boolean
let firstName = undefined; // undefined
let lastName = null; // clear a variable

typeof age; // "number"
typeof firstName; // "undefined". undefined 既是 type 也是 value
typeof lastName; // "object"

Reference types

  • object
  • array
  • function
// --- object
let person = {
  // object
  name: "jamei", // property
  age: 30,
};

person.name = "john"; // dot notation
person["age"] = 20; // bracket notation

let selection = "name";
person[selection] = "Jenny";

//--- array is also a 'object' type 💡
let selectedColors = ["red", "blue"]; // array
selectedColors[2] = "green"; // length is dynamic
console.log(selectedColors[0]);
console.log(selectedColors.length);

Functions

// 1. performing a task
function greet(name, lastName) {
  // name is the parameter
  console.log("hello world " + name + " " + lastName);
}

greet("jamie"); // jamie is the argument, actual value is applied

// 2. calculating a value
function square(number) {
  return number * number;
}
let number = square(2);

Operators

  • arithmetic
  • assignment
  • comparison
  • equality (strict & lose equality)
  • ternary operator (? a : b)
  • logical operator (&&, ||, !)
    • 以下在 logical operator,會自動轉為 Falsy (false)
      • undefined
      • null
      • 0
      • false
      • ''
      • NaN
  • bit operator(|, &)
// arithmetic operator
console.log(x % 2); // remainder
console.log(x ** y); // exp
console.log(++x); // increment (++)
console.log(y--); // decrement (--)

// assignment operator
let x = 10;
x++; // x = x + 1
x += 5; // x = x + 5
x *= 3; // x = x * 3

// comparison operator
let x = 1;
console.log(x > 0); // true

// equality
console.log(x === 1);
console.log(x !== 1);

// strict equality (same type + value)
console.log(1 === 1); // true
console.log("1" === 1); // false
// lose equality (don't care type, automatically convert type)
console.log(1 == "1"); // true
console.log(true == 1); // true

// ternary operator
let poins = 110;
let type = points > 100 ? "gold" : "silver";

// logical
console.log(true && true); // logical AND (&&)
let highIncome = true;
let goodCreditScore = true;
let eligibleForLoan = highIncome && goodCreditScore; // true
let eligibleForLoan = highIncome || goodCreditScore; // logical OR (||)
let applicationRefused = !eligibleForLoan; // Not (!)

// automatically convert operand ->
false || "jamie"; // 'jamie'
false || 1; // 1

// 以下在 logical operator,會自動轉為 Falsy (false)
// undefined
// null
// 0
// false
// ''
// NaN

// short-circult
let userColor = "red";
let defaultColor = "blue";
let currentColor = userColor || defaultColor; // can provide default value if user not select

// bit operator application
// Read, Write, Execute
// 00000100
// 00000010
// 00000001
const readPermission = 4;
const writePermission = 2;
const executePremission = 1;

let myPermission = 0;
myPermission =
  myPermission | readPermission | writePermission | executePermission;
let message = myPermission & readPermission ? "yes" : "no"; // 可以用來判斷有無權限

Conditional statements

  • if else
if (condition) {
  // statement
} else if (anotherCondition) {
  // statement
} else {
  // statement
}
  • switch case
// switch case (can be string, number or boolean)
let role;
switch (role) {
  case "guest":
    console.log("Guest User");
    break; // need
  case "moderator":
    console.log("Moderator User");
    break;
  default:
    console.log("Unknow Role");
}

Flow control

  • For loop

    for (let i = 0; i < 5; i++) {
      console.log("hello world");
    }
    
  • While Loop

    let i = 0;
    while (i < 5) {
      if (i % 2 !== 0) console.log(i);
      i++;
    }
    
  • Do-while Loop: execute at least once

    let i = 0;
    do {
      if (i % 2 !== 0) console.log(i);
      i++;
    } while (i <= 5);
    
  • For-in Loop: 用在 property

     const person = {
       name = 'jamie',
       age: 30
     };
    
    for (let key in person) {
      console.log(key, person[key]);
    }
    
    const colors = ['red', 'blue', 'green'];
    for (let inex in colors)
      console.log(index, colors[index]);
    
  • For-of Loop: 用在 array

    const colors = ["red", "blue", "green"];
    for (let color of colors) console.log(color);
    
  • break and continue

    let i = 0;
    while (i <= 10) {
      if (i == 5) break;
    
      if (i % 2 === 0) {
        i++;
        continue; // 盡量不要用
      }
    
      conosle.log(i);
      i++;
    }
    
  • exercise

    function max(a, b)
      return (a > b) ? a : b;
    
    function isLandscape(width, height) {
      return (width > height);
    }
    
    // Math.floor(1.3)
    // 12 points suspend
    function checkSpeed(speed) {
      const speedLimit = 70;
      const kmPerPoint = 5;
      if (speed < speedLimit + kmPerPoint) {
        console.log("ok");
      } else {
      	const points = Math.floor((speed - speedLimit) / knPerPoint);
      	if (points >= 12 )
          console.log("suspend");
      	else
        	console.log('points: ', points);
      }
    }
    
    const array = [0, null, undefined, '', 2, 3];
    function countTruthy(array) {
      let count = 0;
      for (let element of array) {
        if (element)
          count++;
      }
      return count;
    }
    
    const movie = {
      title: 'a',
      release: 2018,
      director: 'b'
    };
    function showProperties(obj) {
      for (let attr in obj)
        if (Typeof obj[attr] === 'string')
        console.log(attr, obj[attr]);
    }
    showProperties(movie);
    
    function showStars(row) {
      for (let i = 1; i <= row; i++) {
        let output = '';
        for (let j = 0; j < i; j++)
          output += '*';
        console.log(output);
      }
    }
    
    showStars(5);
    
    
    function showPrimes(limit) {
      for (let i = 2; i <= limit; i++) {
        let isPrime = true;
    		for (let f = 2; f < limit; f++) {
          if ((i % f) === 0) {
            isPrime = false;
            break;
          }
        }
        if (isPrime) console.log(i);
      }
    }
    
    showPrimes(20);
    

Object

  • object literal
// object literal
const circle = {
  radius: 1,
  location: {
    x: 1,
    y: 1,
  },
  isVisible: true,
  draw: function () {
    console.log("draw");
  },
};

circle.draw();
  • factory function
function createCircle(radius) {
  return {
    radius: radius,
    draw: function () {
      console.log("draw");
    },
  };
}

// modern
function createCircle(radius) {
  return {
    radius,
    draw() {
      console.log("draw");
    },
  };
}

const circle1 = createCircle(1);
console.log(circle1);
  • constructor function
// PASCAL notion
function Circle(radius) {
  this.radius = radius;
  this.draw = function () {
    console.log("draw");
  };
}

const circle = new Circle(1);

delete circle.color;
delete circle.draw;

primitives are copied by their value, objects are copied by their reference.

  • enumerate properties
const circle = {
  radius: 1,
  draw() {
    console.log("draw");
  },
};

for (let key in circle) {
  console.log(key);
}

// 🔥 circle is not iterable!!! ERROR
for (let prop of circle) {
  // WRONG!!
  console.log(prop);
}

for (let key of Object.keys(circle)) console.log(key);

for (let entry of Object.entries(circle)) console.log(entry);

if ("radius" in circle) console.log("yes");
  • Clone Object (Shallow Copy)
const circle = {
  radius: 1,
  draw() {
    console.log("draw");
  },
};

// old clone syntax
const another = {};
for (let key in circle) another[key] = circle[key];

// new clone syntax
const another = Object.assign({}, circle);

// spread operator to shallow copy 🔥
const another = { ...circle };
  • Math (MDN)
Math.random(); // 0~1
Math.round(1.9); // 2
Math.max(1, 2, 3, 4, 5); // 5
  • String object
// string primitive
const message = "this is my first string"; // typeof string
message.split(" ");

// string object
const another = new String("hi"); // typeof object
  • template literal
const another = `Hi ${name}, ${2 + 3},
Thank you`;
  • date
const now = new Date();
const date1 = new Date("May 11 2018 09:00");
now.toISOString();

Array

  • add element
const numbers = [3, 4];
// End
numbers.push(5, 6);
console.log(numbers); // 3,4,5,6
// beginning
numbers.unshift(1, 2); // 1,2,3,4
// middle
numbers.splice(2, 0, "a", "b");
  • find element (primitive)
const numbers = [1, 2, 3, 1, 4];
numbers.indexOf("a"); // -1 not found!
numbers.indexOf(1); // 0
numbers.lastIndexOf(1); // 3

console.log(numbers.indexOf(1) !== -1);
console.log(numbers.includes(1)); // new syntax 🔥
  • find element (object)
const courses = [
  { id: 1, name: "a" },
  { id: 2, name: "b" },
];

const course = courses.find(function (course) {
  return course.name === "a"; // criteria
});

console.log(course);

const course2 = courses.findIndex(function (course) {
  return course.name === "a"; // 0
});

console.log(course2);
  • arrow function
    • 當你要傳一個 function 進去當作 callback 時
const courses = [
  { id: 1, name: "a" },
  { id: 2, name: "b" },
];

const course = courses.find(function (course) {
  return course.name === "a";
});

// 只有一行 return 時
const course2 = courses.find((course) => course.name == "a");
console.log(course2);
  • remove elements
const numbers = [1, 2, 3, 4];

// end
// numbers.push();
const last = numbers.pop();
console.log(last); // 4

// beginning
//numbers.unshift();
const first = numbers.shift();
console.log(first); // 1

// middle
numbers.splice(2, 1);
console.log(numbers); // 1, 2, 4
  • empty array
const numbers = [1, 2, 3, 4];
let another = numbers;

// solution 1 💡
numbers = [];
console.log(numbers);

// solution 2 💡
numbers.length = 0;

// solution 3
numbers.splice(0, numbers.length);

// solution 4
while (numbers.length > 0) numbers.pop();
  • combine & slice
const first = [1, 2, 3];
const second = [4, 5, 6];

const combined = first.concat(second); // [1,2,3,4,5,6]

const slice = combined.slice(2, 4); // [3,4]
const slice = combined.slice(2); // [3,4,5,6]
const slice = combined.slice(); // [1,2,3,4,5,6]
  • spread operator (ES6)🔥
const combined = [...first, ...second];
const combined = [...first, "a", ...second, "b"]; // [1,2,3,'a',4,5,6,'b']
const copy = [...combined]; // copy
  • iterate array
const numbers = [1, 2, 3];
for (let number of numbers) console.log(number);

numbers.forEach(function (number) {
  console.log(number);
});

numbers.forEach((number) => console.log(number)); // arrow version

numbers.forEach((number, index) => console.log(index, number)); // also index 🔥
  • join array, split string
const numbers = [1, 2, 3];
const joined = numbers.join(","); // '1,2,3'

const message = "This is my first message";
const parts = message.split(" "); // ['This', 'is', ..];
  • sort array
const numbers = [2, 3, 1];
numbers.sort(); // [1,2,3]
numbers.reverse(); // [3,2,1]

const Courses = [
  { id: 1, name: "Node.js" },
  { id: 2, name: "JavaScript" },
];

Courses.sort(function (a, b) {
  // a < b => -1
  // a > b => 1
  // a == b => 0
  const nameA = a.name.toUpperCase();
  const nameB = b.name.toUpperCase();

  if (nameA < nameB) return -1;
  if (nameA > nameB) return 1;
  return 0;
});
  • testing elements
    • every()
    • some()
const numbers = [1, 2, 3];

// 只要一個失敗,就回傳 false
const allPositive = numbers.every(function (value) {
  return value >= 0;
});

// 只要有一個成立就回傳 true
const atLeastOnePositive = number.some(function (value) {
  return value >= 0;
});
  • Filter array
const number = [1, -1, 2, 3];
const filtered = numbers.filter(function (value) {
  // [1,2,3]
  return value >= 0;
});
const filtered = numbers.filter((n) => n >= 0); // arrow
  • mappin array
    • map 跟 filter return array, 可以 chain
const number = [1, -1, 2, 3];
const filtered = numbers.filter((n) => n >= 0);
const items = filtered.map((n) => "<li>" + n + "</li>");
console.log(items);
const html = "<ul>" + items.join("") + "</ul>";

const items = filtered.map((n) => {
  const obj = { value: n };
  return obj;
});

const items = filtered.map((n) => ({ value: n })); // 這邊用 () 將 obj 包起來,不然會出錯
  • reduce array
const numbers = [1, -1, 2, 3];
let sum = 0;
for (let n of numbers) sum += n;
console.log(sum);

// alternative
const sum = numbers.reduce((accumulator, currentValue) => {
  return accumulator + currentValue;
}, 0);

// arrow
const sum = numbers.reduct(
  (accumulator, currentValue) => accumulator + currentValue
);