'JavaScript快速筆記'

JavaScript 泛函編程 編譯器 C語言 魏智勇 2019-09-03
"

1. 基本概念

"

1. 基本概念

JavaScript快速筆記

VAR CONST 和LET

在ES6出現之前,用var來聲明變量,如果不小心忘記了var而直接定義變量的話,變量會自動成為全局變量從而可能汙染整個項目。const 和let是在ES6之後出現的,const用來定義常量而let用來定義局部變量。有趣的是const定義的常量可能並不是一成不變的,如果定義的是複雜類型,可能只是表示const對象的不變,而不代表對象內容不可變(如果有c語言基礎,將複雜對象的定義看作指針應該更恰當一些)。比如說:

const n=5; //定義常量n=5
n=6; //編譯器報錯,因為const對象的不可變性
const result={}; //定義常量result
result.first='this'; //result並沒有變,變化的是其內容
result.last='that';
console.log('result'); //不會報錯,輸出result的內容
//Object { first: "this", last: "that" }

一元運算符

符號+和-除了表示加法和減法外,在JavaScript中還有座位一元運算符的作用,用法為+x,-x,如果x不是數字,則通過一元運算符會自動轉換為數字。但要注意的是,在JavaScript中++和—也是自增和自減法運算符,在連用時要和一元運算符區分。比如說:

const x=5;
const y=3- -x; //注意減號之間的空格,y=8
const s='5';
const t=3++s;//報錯,因為類型不匹配
const y=3+s;//‘35’轉換成字符串加法
const z=3+ +s;//z=8

嚴格相等與非嚴格相等

在JavaScript中,推薦使用===和!==的嚴格相等和嚴格不相等來進行判斷。而非嚴格相等和非嚴格不相等用的是==和!=。主要區別在於,嚴格相等要求對象內容相同,並且類型相同,或者是同一個對象,或者可以轉換成相同的值,而非嚴格相等則可能引起不必要的問題。因此,除非必要,儘量使用嚴格相等來判斷。舉例如下:

const n= 5;
const s='5';
n===s;//false
n==s;//true
n===Number(s);//true
const a={name:'something'};
const b={name:'something'};
a===b;//false,不是同一個對象
a==b;//也是false,但不推薦使用

求值與表達式

  • 自增自減和賦值的副作用
const skipIt=true;
let x=0;
const result=skipIt||x++;//result=true,x=0,跳過了x++的步驟
  • 條件運算符
const doIt=false;
const result=doIt?"did it":"Didn't do it";
  • 結構賦值
const obj={a:2,b:3,c:4};
const {a,b,c}=obj;//同時給a,b,c賦值
let a=5,b=10;
[a,b]=[b,a]//交換a和b的值
  • 模板字符串(注意不是單引號`)
let temp=21.5;
const tempString=`Current Temperature is ${temp}`
//Current Temperature is 21.5

2.函數與數組

引用調用

JavaScript裡可以允許像調用值一樣通過引用調用函數。

function getGreeting(guestName){
return 'Hello '+guestName;
}
const f=getGreeting;
f('Joanna'); //"Hello Joanna"
const o={};
o.f=getGreeting;
o.f('Henry') //"Hello Henry"
console.log(o);
const arr=[1,2,3];
arr[1]=getGreeting;
arr[1]('John');//"Hello John"
arr //Array(3) [ 1, getGreeting(), 3 ]

函數傳值和傳引用

變量為基本類型的函數,是傳值引用的,函數不會修改外部變量的值。但變量為對象類型參數的函數,是傳引用調用的,函數對參數的修改會影響變量。從函數式編程的原則來說,應該儘量避免函數修改參數造成的函數不純粹現象。

展開操作符…

展開操作符…可以用來接受任意多的參數,例如(本函數可以用foreach和箭頭函數簡單實現,此處僅供說明)

function addPrefix(prefix,...words){
const prefixedWords=[];
for(let i=0;i<=words.length;i++){
prefixedWords[i]=prefix+words[i];
}
return prefixedWords;
}
addPrefix('Mr.','John','Henry','Alex','Ken');
//Array(5) [ "Mr.John", "Mr.Henry", "Mr.Alex", "Mr.Ken", "Mr.undefined" ]

THIS的使用陷阱

在函數中的this往往可能帶來隱含的問題,在ES6中,通過箭頭函數可以避免大部分這樣的問題。在箭頭函數出現之前,針對這一問題常見的解決辦法是定義一個self(約定俗成)的變量來指向this。

this帶來的問題示例如下,在下面這個例子中,第一次調用speak時,有明確綁定,因此功能正常,但在第二次調用時由於指代不明會出現問題。因此,雖然可以使用self來解決一部分問題,但最好還是設法避開this陷阱。比如利用ES6的箭頭函數功能。

const o={
name:'Henry',
speak(){return `my name is ${this.name}`;},
}
o.speak(); //"my name is Henry"
const speak=o.speak; //定義一個speak對象
speak===o.speak; //true 同一個對象
speak(); //"my name is " this沒有被綁定的對象

函數表達式、匿名函數和箭頭函數

const f=function(){
\treturn 'hello!';
}; //匿名函數
const g=function f(){
\treturn 'hello!';
} //函數表達式,一般用來將g傳入到其他函數中
const f1=()=>'hello!'; //箭頭函數

調用,請求和綁定

可以用來指定this的三種方法。調用 call, 請求 apply ,綁定 bind。區別在於call像一般函數那樣獲取參數,apply以數組的方式獲取參數,在ES6中展開運算符…可以實現apply的功能。

作用域、閉包和即時調用函數

為了減少對全局變量的汙染,程序中應該儘量僅在必要的時候使用全局變量。並借鑑函數式編程的思維,使函數的調用不依賴於外部參數。保證函數的純淨性。

閉包指將函數定義在一個指定的作用域中,明確指出其對作用域具有訪問權限。例如:

let globalFunc;
{
let blockVar='a';
globalFunc=function(){
console.log('this is '+blockVar);
}
}
globalFunc(); //this is a

又比如,指定一個能記錄自己被調用次數的函數。

const g=(()=>{
let count=0;
return ()=>{
return `I have been called ${++count} times`;
}
})();
g();//"I have been called 1 times"
g();//"I have been called 2 times"

數組的內容操作說明

基礎操作:

  • push ,pop, 入棧、出棧,在結尾位置LIFO,修改數組
  • unshift, shift, 入隊列,出隊列,在隊首FIFO,修改數組
  • concat, 在數組末尾添加元素,返回拷貝
  • slice(起始位置,終止位置), 獲取子數組,返回拷貝
  • splice(起始位置,要刪除的個數不刪除為0,…要添加的元素),從任意位置添加或刪除元素,修改數組
  • copyWithin(複製的目標位置,複製的起始位置,[可選]複製到哪裡結束),剪切並替換元素,修改數組
  • fill(填充值,起始位置,終止位置),填充數組,修改數組
  • reverse,反轉數組,修改數組
  • sort((alb)=>a.name>b.name),排序,可以設置排序條件修改數組

高級操作:

  • map,轉化數組中所有元素,返回拷貝
  • filter,根據條件排除元素,返回拷貝
  • reduce,整個轉換,返回拷貝
  • join,轉化成字符串併合並,返回拷貝

迭代與生成器

通過數組的.values方法可以獲得其可迭代對象,通過通配符*定義可以使函數成為生成器,在生成器中使用yield可以將控制權返回調用方。使用next可以調用迭代器的下一個值。迭代結束中其 ‘done’參數返回值為true。通過[Symbol.iterator]可以為生成迭代對象。例如。

class Logs{
\tconstructor(){
\t\tthis.messages=[];
\t}
\taddMessage(message){
\t\tthis.messages.push({message,timestamp:Date.now()});
\t}
\t[Symbol.iterator](){
\t\treturn this.messages.values();
\t}
}
const log=new Logs();
log.addMessage('first day at sea');
log.addMessage('spotted fishes');
log.addMessage('new adventure to see');
for (let msgs of log){
\tconsole.log(`${msgs.message} @ ${msgs.timestamp}`);
}
"

相關推薦

推薦中...