I am a front-end development engineer who likes to develop and design web interfaces.
F2E : HTML / CSS / SASS / JQUERY / JAVASCRIPT / PHP / SQL / LODASH / VUE.JS / REACT.JS
UI : RWD / AWD / PWA
UX : WIREFRAME / FUNCTIONAL MAP / FLOWCHART&UI
Professional receiving company website development project, UI interface design, computer and mobile interface conversion, online SEO ranking promotion.
1. Data Type
首先,在javascript裡面,有許多種資料型別(data type),但主要分兩大類,一種是原始型別(primitive type),另一種是物件(Object)。
--------------------------------------------------------
2. Primitive type
--------------------------------------------------------
3. Object
Primitive type以外的,例如array, function, map …
var x = 1;
var y = "test";
var a = x;
var b = y;
a = 2;
b = "xyz";
console.log(x, y, a, b) // 1, "test", 2, "xyz"
var ref1 = [1];
var ref2 = ref1;
ref1.push(2);
console.log(ref1, ref2); // [1, 2], [1, 2]
-------------------------------------------------------- 以上
var personObj1 = {
name: 'Alex',
age: 30
};
var person = personObj1;
person.age = 25; // 將age 賦值 25
person = { // 這邊person 又從新賦值了,所以 personObj2 才會和 personObj1 不一樣
name_1: 'John_1',
age_2: 502
};
var personObj2 = person;
console.log(personObj1);
console.log(personObj2);
-------------------------------------------------------- 以上
1. 當ref1被宣告時,javascript會在記憶體的某處建立一個object,並將ref1指(reference)到這個object。
2. 接著var ref2 = ref1 這一行,就是讓ref1把相同的reference傳給ref2。
3. 此時兩個變數都是指向同個object了,因此對這個object操作都會同時影響到ref1 & ref2。
1. splice() => 切割陣列 返回 陣列
array.splcie(index, 切割個數, 替換變數)
array.splice(2, 1, "william")
2. slice() => 複製陣列 返回 陣列
整列 or 字串 都可使用
slice(start, end)
let a = ["a","b","c","d","f"]
a.slice(1, 3) // ["b","c"]
3. split() => 分割字串 返回陣列
string.split(參數, 分個數)
let a = "how are you ?"
a.split("") // ["h","o","w"," ","a","r","e"..."?"]
a.split(" ") // ["how","are","you","?"]
a.split(" ", 2) // ["how","are"]
1. push() => 將 "變數" 資加入到陣列的尾端 並 返回 陣列
array.push()
array.push("字串") // string
array.push(1) // number
array.push({ 對象 }) // object
array.push([ 陣列 ]) // array
2. pop() => 刪除 整列 最尾端的 "資料" 並 返回 陣列
array.pop()
3. shfit() => 刪除 整列 第一筆 "資料"
array.shfit()
let a = [1, 2, 3, 4, 5];
a.shfit() // [2, 3, 4, 5]
3. unshfit() => 將pop()刪除的"資料" 放到第一個
array.unshfit(array.pop())
let a = [1, 2, 3, 4, 5]
let b = a.pop("") // [1, 2, 3, 4]
a.unshfit(b) // [5, 1, 2, 3, 4]
1. target 是触发 事件的 DOM 物件
2. currentTarget 是触发 當時處理該事件的事件監聽器所註冊的 DOM 物件
3.
const listener = event=>{
console.log(event.type, event.target);
type / 触发事件 的 數據類型
target / 触发事件 的 可返回事件的目标节点
}
https://developer.mozilla.org/zh-TW/docs/Web/API/Event/currentTarget
1. 将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回该 "目标对象"
1-2. Object.assign(target, ...sources)
-> target 只能有一個,source 可以有多個
2. Object.assign(target, source);
-> target: 目标对象
-> source: 源对象
3. 範例-1:
var obj = {a: 1};
var copy = Object.assign({}, obj); // "{}" 是 目標對象
console.log(copy); // {a: 1};
4. 範例-2:
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target); // expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget); // expected output: Object { a: 1, b: 4, c: 5 }
Array / 數組方法複習
1. 會 改變 原始陣列
-> push()、pop()、shift()、unshift()、reverse()、splice()、sort()、copyWithin()、fill()
-> push() // 返回 原本Array
-> pop() // 返回 原本Array
-> shift() // 返回 原本Array
-> unshift() // 返回 原本Array
-> reverse() // 返回 原本Array / 反轉 / 陣列反轉
-> splice() // 返回 原本Array / 移除並新增 / splice(位置, 移除數量, 添加值)
-> sort() // 返回 原本Array / 順序排序 / 對陣列的元素 進行 順序排序
-> copyWithin() // 返回 原本Array / 複製 / copyWithin(位置, 複製頭, 複製尾)
-> fill() // 返回 原本Array / 替換 / fill(替換的內容, 位置頭, 位置尾)
2. 回傳 陣列元素資訊 或 索引值
-> length、indexOf()、lastIndexOf()、find()、findIndex()、filter()
-> indexOf() // 返回 索引 / 判斷陣列中 是否包含 某個值 / 由左而右
-> lastIndexOf() // 返回 索引 / 判斷陣列中 是否包含 某個值 / 由右而左
-> find() // 返回 元素 / 查找處理陣列 / 將陣列中的「每一個」元素帶入指定的函式內做判斷 / 回傳 第一個 找到元素 or undefined
-> findIndex() // 返回 索引 / 查找處理陣列 / 將陣列中的「每一個」元素帶入指定的函式內做判斷 / 回傳 第一個 找到元素 or undefined
** -> filter() // 返回 新的陣列 / 过滤處理陣列 / 將陣列中的「每一個」元素帶入指定的函式內做判斷 / 符合判斷則會回傳一個 新的陣列
3. 針對每個元素處理
-> forEach()、for in、for of
-> forEach() // 將陣列中每個元素套用到指定的函式裡進行運算 / forEach(整列的每一個值, 索引, 陣列本身)
4. 產生新的陣列或新的值
-> join()、concat()、slice()、map()、reduce()、reduceRight()、flat()、flatMap()、Array.from()、Array.of()、toString()
-> join() // 返回 字串 / 合併 / 將陣列中所有元素合併,沒有指定 字符 預設會用「逗號」合併
-> concat() // 返回 新陣列 / 合併 / 可以將兩個陣列合併在一起,如果是使用 ES6 使用擴展運算符...來代替
-> slice() // 返回 新陣列 / 切割部分 / 截取出陣列某部份的元素為一個新的陣列 / slice(位置頭, 位置尾)
-> map() // 返回 新陣列 / 遍历處理陣列 / 處理陣列中每個元素,最後回傳出一個新的陣列
-> map( function(){ this },data ) / 一個函式 ( 必填 ) 和 this參數 (選填)
-> this 指的就是 data
-> map( (元素的值/必填, 當前元素的索引值/選填, 當前的陣列/選填)=>{} )
-> reduce() // 返回 number / 計算處理陣列 / 將陣列中每個元素進行計算(从左至右)
-> reduceRight() // 返回 number / 計算處理陣列 / 將陣列中每個元素進行計算
-> flat() // 返回 新陣列 / 多維陣列转换 / 將一個多維陣列 转换 一维阵列 / Infinity 是全部展開成一維陣列
-> flatMap() // 返回 新陣列 / 遍历處理 + 多維陣列转换 / 等於map()和flat()的組合,在運算後直接將陣列扁平化處理
-> toString() // 返回 字串 / 陣列 轉 字串
5. 判斷並回傳布林值
-> every()、some()、includes()
-> every() // 返回 boolean / 是非處理陣列 / ”&&“ 条件都必须达成
-> some() // 返回 boolean / 是非處理陣列 / “||” 条件有一个达成就行
-> includes() // 返回 boolean / 是非處理陣列 / 判斷陣列中是否包含某個值
6. 其他用法
-> keys()、valueOf()、values()、entries()
-> keys() // 返回 回傳陣列的索引值 / 取得索引(keys)
-> valueOf() // 返回 陣列的原始值 / 修改
1. for in是ES5標準;for of是ES6標準。for of修復for in的不足
2. for in遍歷的是key,for of遍歷的是value
3. 用法 :
for(let index in arr){
console. log(index ); // 0, 1, 2, .....
}
for (let [key, value] of Object.entries(arr)) {
console.log(`${key}: ${value}`); // "0 : a", "1 : b", "2 : c", ....
}
4. Object.entries(obj)
參量 / obj -> 自身[key, value]具有字符串屬性對的對象
返回值 / -> 返回一個數組
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
5. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
1. append() => 可以同时传入多个节点或字符串,没有返回值
2. appendChild() => 只能传一个节点,且不直接支持传字符串
3. innerHTML => 添加的是纯字符串,不能获取内部元素的属性
*** 执行速度的比较上,使用 appendChild 比 innerHTML 要快 ***
append 可推入dom,number,string
-> v1.append(dom);
appendChild 只能推入 節點,不能直接推入string
-> v3.appendChild(dom); or v3.appendChild(document.createTextNode("apple"))
innerHtml 只能添加string,將string轉換成 text or dom
-> v3.innerText= (new Date()).getFullYear();
-> v3.innerText= "<h1>william</h1>"
1. charCodeAt 可返回指定位置的字符的 Unicode 编码
2. charAt 返回指定位置的字符
3. var str="Hello world!"
str.charAt(1) // e
str.charCodeAt(1) // 101
1. 数组的元素进行排序
2. 如果调用该方法时没有使用参数,将按字母或數字顺序对数组中的元素进行排序
3. function(a, b){return a - b}
sort()函數比較兩個值時,它將這些值發送到compare函數,並根據返回的值(負,零,正)對值進行排序
ture -> b則排序之前a
false -> a則在之前進行排序 b
比較40和100 :
sort()方法將調用compare函數(40,100)
函數計算40-100 (a - b),並且由於結果為負數(-60),因此sort函數會將40排序在100前面
var str="Visit Microsoft!"
document.write(str.replace("Microsoft","W3School"))
1. decodeURIComponent( ) 解码
2. encodeURIComponent( ) 加码
3.
var test1="台湾省"
document.write(encodeURIComponent(test1)+ "<br />") // %E5%8F%B0%E6%B9%BE%E7%9C%81
document.write(decodeURIComponent(test1)) // 台湾省
1. toString()可以將所有的的資料都轉換為字串,但是要排除null 和 undefined。
二進位制:.toString(2);
八進位制:.toString(8);
十進位制:.toString(10);
十六進位制:.toString(16);
var str = null.toString();
console.log(str, typeof str); // 報錯
var str = undefined.toString();
console.log(str, typeof str); // 報錯
2. String()可以將null和undefined轉換為字串,但是沒法轉進位制字串。
var str = String(null);
console.log(str, typeof str); // null,string
var str = String(undefined);
console.log(str, typeof str); // undefined,string
1. 創建一個數組,其中填充了所有通過測試的數組元素(作為函數提供)
2. 不會對沒有值的數組元素執行該函數
var aaa = [32, 33, 16, 40];
function aaaclick(data)
return data >= 18;
}
console.log( aaa.filter(aaaclick) ); // [ 32, 33, 40]
1. parseInt() 函数可解析一个字符串,并返回一个整数
-> parseInt(string, radix)
-> 注意: 只有字符串中的第一个数字会被返回。
注意: 开头和结尾的空格是允许的。
注意:如果字符串的第一个字符不能被转换为数字,那么 parseInt() 会返回 NaN。
注意:在字符串以"0"为开始时旧的浏览器默认使用八进制基数。ES 5,默认的是十进制的基数。
-> parseInt("10") // 10
-> parseInt("10.33") // 10
-> parseInt("34 45 66") // 34
-> parseInt("40 years") // 40
-> parseInt("He was 40") // NaN
2. parseFloat() 函数可解析一个字符串,并返回一个小數點
-> parseFloat(string)
-> 注意: 字符串中只返回第一个数字。
注意: 开头和结尾的空格是允许的。
注意: 如果字符串的第一个字符不能被转换为数字,那么 parseFloat() 会返回 NaN。
-> parseInt("10.33") // 10.33
3. Number() 函数把对象的值转换为数字
-> Number(object)
-> 注意:如果对象的值无法转换为数字,那么 Number() 函数返回 NaN。
-> Number( true ) // 1
-> Number( false ) // 0
-> Number( new Date() ) // 1970 年 1 月 1 日至今的毫秒数
-> Number( 999 ) // 999
-> Number( 999 888) // NaN
1. findOne( ) 尋找數據中的第一個
-> 在MongoDB中,我們使用find和findOne方法在集合中查找數據。 就像SELECT語句用於在MySQL數據庫的表中查找數據一樣。
-> 要從MongoDB中的集合中選擇數據,我們可以使用 findOne()方法
-> 該findOne()方法返回選擇中的第一個匹配項
->
2. find( ) 尋找符合函數的數據
-> 返回通过测试(函数内判断)的数组的第一个元素的值
-> 数组中的每个元素都调用一次函数执行
-> https://www.runoob.com/jsref/jsref-find.html
setInterval() 循環執行,自設定,每一秒執行一次
clearInterval() 取消 setInterval() 循環
同步任務會阻塞程序執行(alert、for...)
異步任務不會阻塞程序執行(settimeout、fs.readFile.....)
--------------------------------------
使用 promise( then、catch、finally )
promise.all & promise.race
promise.resolve & promise.reject
--------------------------------------
resolve :代表成功之後要做的事情
reject : 代表失敗之後要做的事情
then :可接受兩個函式作為參數,第一個函式用於成功(resolve)時要執行的任務,第二個函式用於失敗(reject)
--------------------------------------
1. json 是一種ajax傳輸格式。
2. JSON(JavaScript對象表示法)是一種輕量級的數據交換格式。
1. JSON.parse(jsonstr); // 可以将JSON 字符串 反序列化成 JSON 对象
2. JSON.stringify(jsonobj); // 可以将JSON 对象 序列化成 JSON 对符串
1. 對像以{ 左括號開頭,}以右括號結尾。
1. 數組以[ 左括號開頭,以] 右括號結尾。
1. JSON.parse(text[, reviver])
-> text 要解析成 JSON 的字串
-> reviver 為選擇性的參數,用來描述JSON字串中的值該如何被解析並回傳的函式
2. JSON.parse('{}'); // {}
JSON.parse('true'); // true
JSON.parse('"foo"'); // "foo"
JSON.parse('[1, 5, "false"]'); // [1, 5, "false"]
JSON.parse('null'); // null
1.JSON.stringify(value[, replacer[, space]])
2.JSON.stringify({}); // '{}'
JSON.stringify(true); // 'true'
JSON.stringify('foo'); // '"foo"'
JSON.stringify([1, 'false', false]); // '[1,"false",false]'
JSON.stringify({ x: 5 }); // '{"x":5}'
JSON.stringify(new Date(2006, 0, 2, 15, 4, 5))
// '"2006-01-02T15:04:05.000Z"'
JSON.stringify({ x: 5, y: 6 });
// '{"x":5,"y":6}'
JSON.stringify([new Number(3),new String('false'),new Boolean(false)]);
// '[3,"false",false]'
JSON.stringify({ x: [10, undefined, function(){}, Symbol('')] });
// '{"x":[10,null,null,null]}'
vue 是組件化開發,dom操作,自動調用 生命週期函數
react 是操作dom中的 數據
//生命周期函数
//只要 組件 在生成的時候,他就會自動調用生命週期函數
//-------------- 生成 --------------
beforeCreate(){
console.log("開始 : beforeCreate/生成前")
},
created(){
console.log("開始 : created/生成后")
},
//-------------- 成熟 --------------
beforeMount(){
console.log("開始 : beforeMount/成熟前")
},
mounted(){
console.log("開始 : mounted/成熟后") / 與後台請求時,ajax 基本上都在這裡操作 / dom操作也在這裡
},
//-------------- 銷毀 --------------
beforeDestory(){
console.log("開始 : beforeDestory/銷毀前")
},
destoryed(){
console.log("開始 : destoryed/銷毀后")
}
v-on: xxx = "bbb(傳入參數)" / 事件綁定 / 事件處理器
@: xxx = "bbb(傳入參數)" / 事件綁定縮寫
v-html = "bbb" / 將bbb變量變成 dom ( bbb:'<span>我是子元素111</span>' )
v-bind:class="bbb" / 動態化綁定 (class、style .....)
/ 綁定屬性 / bbb 是在data() { return { bbb: 'red active', } }
/ 這樣dom 結點中就會出現 class ="red active" 這兩個class
/ 可是使用 @click="xxx" + methods 來改變 class 中的屬性
data() { return{} } / 管理 變量
computed : { } / 操作 計算屬性 / 綁定函數
methods : { } / 方法 / 給事件使用 / 模板 綁定 事件 / 綁定函數
filters :{ } / 過濾器 / 將 filters 中函數所返回的數據對dom中變量進行過濾 / 2-7 muke
1. 在模板中放太多的邏輯會讓模板 難以維護
2. 所有關於計算函數都可以放在 computed 中
用法1: v-for="item in items" 數組
用法2: v-for="(item, index) in items" 數組
用法3: v-for="(value, key) in object" 對象
v-model 是綁定變量,並且常用於 表單控件
<input type="checkbox" value="jack" v-model="aaa">
<p>{{ aaa }}</p>
在input輸入文字的內容時,下面的變量aaa會同步出現內容
父組件 向 子組件 傳遞 數據
父組件 送出, 子組件 接受
父:<count-down col="red"></count-down>
子:props: {
col: {
type: String, // 定義 可 Boolean / Array / String / Number
default: 'orange', // 默認值
}
},
$emit => 觸發某事件
$emit => 觸發 子组件自定义事件,一般會由父组件的 v-on 去綁定觸發事件
**** 子組件在 mounted(){ } 生成事件,父組件接受並執行其他而外附加方法 ****
子组件(bb) => this.$emit("msg", "我是传递数据")
父组件(aa) => <.. @msg ="msgxx">
methods:{
msgxx(data) {
console.log(data) // 我是传递数据
}
},
<div ref="aaa"></div>
mounted() {
**** 在mounted中全部都属于真实dom ****
this.$refs.headaaaa.innerHTML = 'hello william';
}
<transition name="fadexx"></transition>
name="可隨便命名"
主要是由 css 去製作效果
/* 進入 */ .fadexx-enter-to, .fadexx-leave
/* 過渡 */ .fadexx-enter-active, .fadexx-leave-active
/* 離開 */ .fadexx-enter, .fadexx-leave-to
方法一:<router-link to="/Demo1">跳轉 demo1</router-link>
方法二:<router-link v-bind:to="{ name: 'Demo1', params: {userId:'123'} }">demo1</router-link>
:params 是傳參 userId 要和被跳轉的頁面相同(router/index.js)
:path: '/demo9/:userId' / “:” 代表是不固定參數 / 通配符
方法三:<router-link v-bind:to="{ name: 'Demo1', params: {userId: 123}, query: {plan: 'queryValue'} }"></router-link>
:query 是傳 建置對 / ip ?自定义=後面的數據
:http://localhost:8080/#/demo1/123 ? plan=queryValue
1. 只能在 function component 中、或者 custom hooks 中使用,不能在 class、一般 JS function中使用。
2. 由於內部是用一個 queue 去定位每一個 hooks 的,所以只能在 func 中的最外層使用,不能在if、while、for 中使用,
也就是說每個 hook 的上一層 {},只能是該 function 的,不能是其他人的。
用來代替 this.setState 。
首先他會返回一個長度為2的 array,array[0] 是 value, array[1] 是這個value的setter。
使用方法一:
const count = useState(0)
const countValue = count[0]
const setCount = count[1]
使用方法二:(推薦)
const [count, setCount] = useState(0)
這個方法是 async 的,它包含了 class 中的 componentDidMount、componentDidUpdate、componentWillUnmount(不完全一樣)
用法為:
useEffect(() => {
console.log('hello')
})
這樣代表每次 render 完後都會 log 一次(componentDidMount、componentDidUpdate)
---------------------------------
useEffect 有 第二個 參數,是一個 array。
這樣子就代表每次 render 時只有 array 中的任一個參數變更時,才執行這個effect,通常 array 中的參數會是 function 中依賴的變數,這樣就可以避免在每次 update 的時候,每個 effect 都重新呼叫一次,每個 effect 只關注它真正需要關心的事情。
useEffect(() => {
listen({
props.id,
handleInfoChange
})
return () => {
removelisten({
props.id,
handleInfoChange
})
}
}, [ props.id, handleInfoChange ])
---------------------------------
如果array為空,就代表只會在 didMount、willUnmount 執行。
useEffect(() => {
return () => {}
}, [] )
由於每個 effect 一定會在 didMount 先執行一次,如果不想在 mount 的時候執行,只想在後續 update 時執行,那麼需要用一個 useRef。
const isFirstRender = useRef(true)
useEffect(() => {
if(!isFirstRender.current){
xxx…
}else{
isFirstRender.current = false
}
}, [xxx])
這樣就可以避免第一次 render(mount) 時執行,接下來的 update 也都會正常執行。
基本上跟 useEffect 使用方法完全一樣。
最大差別在於:
useEffect: 異步,在畫面 render 結束後才執行,不會阻塞 UI。
useLayoutEffect: 同步,在 DOM 改變後馬上執行,會阻塞 UI。
useLayoutEffect 跟 class 的 componentDidMount、componentDidUpdate、componentWillUnmount 完全一樣。
useLayoutEffect 會在 function render 完,DOM 更新完,畫面 render 之前執行,也就是 DOM 更新完後,可以再更新一次 state,或者做其他事情,可以避免多一次 reflow、repaint(不訪問少數會造成 force reflow 的 DOM attribute: offsetTop、offsetWidth…等等)。
不過如果在 useLayoutEffect 做太多事情的話,會阻塞 UI render,所以官方推薦大多情況使用 useEffect 就好。
比較 useLayoutEffect vs useEffect
const App = () => {
const [c,setC] = useState(0)
useLayoutEffect(()=>{
alert()
if(c === 1){
setC(c + 1)
}
})
return (<button onClick={() => setC((pre)=> pre + 1)}>
click {c}
</button>)
}
開啟 F12,查看 button 的 DOM,在點擊 button,會依序發生幾件事情:
1. state 更新了 c = 1
2. DOM 的值從0變1 (畫面還沒 render)
3. DOM 改變後馬上執行 useLayoutEffect,第一行就遇到 alert 彈出
4. 由於c === 1 所以再更新一次 state => c = 2
5. DOM 改變, 1 => 2 (畫面還沒 render)
6. alert彈出
7. 畫面 render,button 的值變為2 (直接跳過1變成2)
const App = () => {
const [c,setC] = useState(0)
useEffect(()=>{
alert()
if(c === 1){
setC(c + 1)
}
})
return (<button onClick={() => setC((pre)=> pre + 1)}>
click {c}
</button>)
}
開啟 F12,查看 button 的 DOM,在點擊 button,會依序發生幾件事情:
1. state 更新了 c = 1
2. DOM 的值從0變1 (畫面還沒render)
3. 畫面 render (button 的值從 0變1)
4. 畫面render完後,執行 useEffect,遇到 alert 彈出
5. 由於c === 1 所以在更新一次 state => c = 2
6. DOM 的值從1變2 (畫面還沒 render)
7. 畫面render (button 的值從 1變2)
8. alert彈出 (useEffect 永遠在畫面 render 完後才執行)
-----------------------------------------
總結:useEffect 會先return,再alert,useLayoutEffect 會先彈出alert,再return
1. 使用 hooks 後,變成了 function component
2. function App(){
const handleOnChange = () => {} return <input onChange={handleOnChange} />
}
每次 render 時,handleOnChange 都是一個新的,對於底下的 Child component 來說,props 雖然看起來都相同,但是 child 總是會認為它不一樣。
3. useCallback 主要的用途在於 catch 住 function。
function App(){
const handleOnChange = useCallback(() => {}, [])
return <input onChange={handleOnChange } />
}
原本的 func 外面包一層 useCallback 之後,每次 render 時雖然被包住的那個func 仍然會重新建立一個,但是不會再 assign 新的,而是直接 assign 舊的給 handleOnChange,也就是說 handleOnChange 永遠是第一次 render 時產生的。
第二個參數一樣是 array,用來控制什麼時候要 assign 新的給 handleOnChange。
1. 用法跟 useCallback 一模一樣。是用來 catch 住某個 value 的。
function App(){
const v = useMemo(() => {
// 一堆業務邏輯操作,複雜計算後得到一個 Value
const value = a * b + c +… + 1234567
return value
}, [a, b, c] )
return …
}
2. 當第二個參數中依賴到的變數值沒變時, v 就不會在變動。
當 return 的那個 value 是一個 function 時,它就是跟 useCallback 一模一樣了。
由於不是 class,沒有了 this,跟畫面無關的變數就沒地方儲存(用 state 也可以,但是更改後就會引起 re-render,沒必要)。
useRef 就是用來放一些跟畫面無關的變數。
useRef 的參數是用來初始化用的,然後會返回一個 mutable object,object 有一個 key 叫 current,這個 current 的值就是 useRef 的參數。
例子一:
const divEl = useRef(null)
<div ref={divEl} />
然後 divEl.current 就會是 div 的 DOM 了
例子二:(常用)
const isMounted = useRef(false)
useEffect( () => {
if(isMounted.current){
...
}else{
isMounted.current = true
}
})
--------- useMemo vs useRef ---------
useMemo 只有在一個地方可以更改它的值,主要用來做昂貴計算的 catch。
useRef 可以在很多地方更改它的值,主要用來立 flag。
1. 主要是寫法上不一樣
原本是
------/ 例子一 /------
const A = React.createContext()
Parent:
<A.Provider value='999'>
<Child/>
</A.Provider>
Child:
<A.Consumer>
{v => <div>{v}</div>}
</A.Consumer>
------/ 例子二 /------
const A = React.createContext()
Parent:
<A.Provider value='999'>
<Child/>
</A.Provider>
Child:
const v = useContext(A)
return <div>{v}</div>
2. 自己也可以創造 custom hook,只是 function name 前綴最好是 use 開頭。
custom hook 都是一個有 state,沒有 render 的 func,可以把很多業務邏輯抽出來,由 custom hook 管理,然後 UI Component就不需要那些業務邏輯,可以更專注在render上。
1. React 引入新的 Hooks 系統後,有兩個 Hook 可以拿來做快取加速用途,分別是記住 return value 的 useMemo 跟記住 function instance 的 useCallback 。但是什麼時候該用到這兩組 Hook 來幫你的 React app 做加速呢?
2. useMemo → 遇到複雜耗時計算時使用
→ useMemo(() => fn, deps)
useCallback → 大部分不用,僅在搭配 PureComponent 等、或是提供多個 useEffect 時使用
→ useCallback(fn, deps)
+++ useCallback(fn, deps) 相等於 useMemo(() => fn, deps)。 +++
3. useMemo
首先複習一下 useMemo 是什麼。他的目的是用來「避免重複進行複雜耗時的計算」,所以把計算的結果存起來. 用。
用法:
const result = useMemo(() => `foo: ${foo}`, [foo]);
講解:
為了得到 result,每次都還要多宣告一個 function + 一個 array 傳給 useMemo 來用。useMemo 另外還要比對兩次 render 間的 foo 有沒有一樣,來確認需不需要重新跑一次計算。
使用最佳時機:
如果你傳給 useMemo 的 function 裡面運算很繁重,例如可能要 map 一組很大的陣列,這時候可能就 很值得用 useMemo 把運算結果暫記起來下次用。
例子:
const isfunction = useMemo(
() => moreArray.map(data => (
<listComponent name={data.name} />
)),
[moreArray]
);
4. useCallback
useCallback 是 useMemo 的一種變體,用來記住一個 function instance(功能實例)。useCallback 其實就等於回傳一個 function 的 useMemo。
用法:
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
講解:
useCallback 的主要目的是避免在 component 內部宣告的 function,因為隨著每次 render 不斷重新被宣告跟建立,每次拿到的都是不同的 instance。這樣的 function 如果被當成 prop 往下傳給其他 component,就可能導致下面的 component 無意義地被重新 render。
使用最佳時機:
如果你的 function 因為需要用到 props 或 state 而必須在 component scope 裡面宣告、但又同時會被超過一個 useEffect 使用時,就建議以 useCallback 包起來。,這樣可以確保當 props 或 state 改變時,useCallback 先跟著改變、進而觸發 useEffect 的行為
例子:
function SearchResults({ query }) {
const getFetchUrl = useCallback(() => {
return 'https://hn.algolia.com/api/v1/search?query=' + query;
}, [query]);
useEffect(() => {
const url = getFetchUrl('react');
// ... Fetch data and do something ...
}, [getFetchUrl]);
useEffect(() => {
const url = getFetchUrl('redux');
// ... Fetch data and do something ...
}, [getFetchUrl]);
}
5. useMemo 或 useCallback 的替代方案
有些情況下你可能沒辦法使用 Hooks、或是不需要用到這兩組 Hook 來做加速。下面簡單列出幾種可能的其他做法:
→ 可以用 memoize-one 代替,用於替代 useMemo
import memoize from 'memoize-one';
const renderMenuItemRows = memoize(allMenuItems =>
allMenuItems.map(menuItem => (
<MenuItemRow key={menuItem.uuid} name={menuItem.name} />
))
);function Foo() {
return (
<RecordReader>
{(menuItems) => renderMenuItemRows(menuItems)}
</RecordReader>
);
}
→ 直接把 function 宣告在 component 外就好
const handleClick = (event) => {
event.preventDefault();
};function Foo() {
return <div onClick={handleClick} />;
}
→ 直接把邏輯寫在 useEffect 裡面就好
1. 通過 redux 提供的 createStore() 方法
-> import { createStore } from 'redux'
2. 我們會得到一個 store 對象
-> const store = createStore(reducer);
3. 通過 store 對象對 getState() 方法 得到應用中當前的 狀態(state)
-> document.body.innerHTML = store.getState();
4. 使用 dispatch() 方法分發動作去改變應用的 狀態(state)
-> store.dispatch({ type: 'INCREASE' })
5. 使用 subscribe() 方法去訂閱 store 的變化,然後使用當前的狀態去重新渲染整個應用
-> store.subscribe(render);
it('null', () => {
const n = null;
expect(n).toBeDefined();
});
test('object assignment', () => {
const data = {one: 1};
data['two'] = 2;
expect(data).toEqual({one: 1, two: 2});
});
// toBe 使用 Object.is 來比對,若想要比對物件內容是否一樣需使用 toEqual
test('two plus two is four', () => {
expect(2 + 2).toBe(4);
});
Children.toArray( [1, [2, [3], [4]]] ) // [1, 2, 3, 4]
說明:會自動講多元數組打平,變成一維數組
1. node 是後端語言,建立在JavaScript之下,他能進行讀寫檔案/API/資料庫連線(mysql2)
1. 安裝 https://nodejs.org/en/
-> node --version
-> npm -v
2. 需使用cmd 終端機啟動 (node index.js)
3. 建立 package.json
-> npm init -y
-> package.json 是紀錄安裝套件的一個文件
-> npm install 可將全部的套件 安裝完畢(在package 有紀錄的情況下)
1. 全局安裝 nodemon
-> npm install -g nodemon (mac 需要在前面加sudo)
-> nodemon
-> 看到 server started 即可
(*** 解除安裝: npm uninstall -g nodemon ***)
2. nodemon 和 node 最大的差別就是 nodemon 會立即執行修改的內容
3.
1. es6 轉 es5
2. const Person = require('./person'); //es5
module.exports = Person; // es5
import Person from './person'; //es6
export default Person; // es6
3. 安裝 & 執行
-> npm install @babel/core @babel/node @babel/preset-env
4. 檢查
-> babel.config.json
-> { "presets": [ "@babel/preset-env" ] }
3. 执行 babel-node
-> 将以内写在package.json 中
-> "babel": "nodemon --exec babel-node src/http_server_babel_node.js"
-> npm run babel
-> "start": "nodemon --exec babel-node src/http_server_babel_node.js"
-> npm start
1. 安裝方法一 :npm install --save express
安裝方法二 :npm install express
2. 執行 nodemon src/index.js or nodemon (package.json 的"main"設定)
1. Express 是一個本身功能極簡的路由與中介軟體 Web 架構:本質上,Express 應用程式是一系列的中介軟體函數呼叫。
2. 中介軟體函數是一些有權存取要求物件 (req)、回應物件 (res) 和應用程式要求/回應循環中之下一個中介軟體函數的函數。下一個中介軟體函數通常以名為 next 的變數表示。
3. app.use()
+++ 沒有裝載路徑的中介軟體函數。
+++ 每當應用程式收到要求時,就會執行此函數。
-> var app = express();
app.use(function (req, res, next) {
console.log('Time:', Date.now());
next();
});
+++ 本例顯示裝載在 /user/:id 路徑的中介軟體函數。
+++ 會對 /user/:id 路徑上任何類型的 HTTP 要求,執行此函數。
-> var app = express();
app.use('/user/:id', function (req, res, next) {
console.log('Request Type:', req.method);
next();
});
4. app.method()
-> app.get() // 此函數會處理指向 /user/:id 路徑的 GET 要求
-> app.get('/user/:id', function (req, res, next) {
console.log('ID:', req.params.id);
next();
}, function (req, res, next) {
res.send(req.params.id);
});
-> app.psot() // 一般get 是render頁面,post 是 送出資料到後端並處理,最後將資料在返回給前端頁面
-> app.post('/try-post-forms', (req, res)=>{ // 送出資料
res.locals.pageTitle = 'william - posted';
res.render('try-post-form.ejs', req.body);
})
5. Router 使用注意事項
-> var app = express();
-> .use()
-> .next()
-> .get() -> req.params/ /:id? or req.query/&?
-> .post()
-> .json() 以json格式送出
-> .send() 將string 送出body
-> .end() 最後一步,結束一切
-> .render() 渲染 html files (ejs or html)
-> 这些只能其一,不能同时存在
1. static 静态方法 (内容不会修改的文件)
-> 使用說明
-> const express = require('express');
const app = express(); // 建立 web server 物件
-> app.use(express.static('public'));
-> 在public文件底下建立 img css img js.... 等, 引入public文件中時,就不需再用 _dirname+"../pubilc/xxx/xxx"
-> _dirname ===> /Applications/XAMPP/xamppfiles/htdocs/iidu-nodejs/src
-> 可直接使用 http://localhost:3001/test.html
1. 請利用 router.use() 和 router.METHOD() 函數來載入路由器層次的中介軟體。
2 var app = express();
var router = express.Router();
3. 先有 主級 app路由,其次才有 Router次級 路由。
4. app.use('/', router); / address_book.js 是一個好例子
1. 什麼是 EJS ?
-> 專門針對 node.js 渲染頁面的 樣板引擎
-> 文件 : index.ejs
2. EJS tages
-> ejs tages
=> <% %> / 執行 / <% if(sess.userwill){ %>
=> <%= %> / 輸出 / <%= name %>
=> <%- %> / 執行html 標籤 或 文件 / <%- include('parts/html_head') %>
=> <%# %> / 註解
3. EJS 使用
-> app.get('/', (req, res)=>{
res.render('main.ejx', {name: 'william'}); // render 是 使用样板 并传入对象
});
-> main.ejx
-> <%= name %>
1. 使用方法
-> app.use(express.urlencoded({ extended: false }));
app.use(express.json());
-> 解釋: 不使用內建 qs lib,而是使用內建的 quertstring lib 來解析傳入的資料
2. 課程中主要是解析以下2種格式
-> application/json
-> application/x-www-form-urlencoded
1. 在使用 response 一共有五種方法,但請記住,只能使用1種在router function中
response 是從 server 中返回結果給 客戶端
request 是從 客戶端 發請求 給 server 端
2. router.get('/add', (req, res)=>{
res.render('address-book/add');
})
3. res.json() // 發送 json
res.render() // 渲染 ejs 和 html w
res.send() // 傳送string 到前端頁面
res.end() // 最後到最後執行 (404)
res.redirect() // 定向跳轉到某位頁面
1. 主要功能是 Multer是用於處理的node.js中間件multipart/form-data,主要用於上傳文件。
注意:Multer將不處理非多部分(multipart/form-data)的任何形式。
+++ https://www.npmjs.com/package/multer
2. 安裝 : npm install multer
3. 建立 文件暫存區 及 文件存放區
暫存區 | tmp_uploads
存放區 | public/img
4. 用法:
-> const multer = require('multer');
-> var storage = multer.diskStorage({
// 當提供destination功能時,您負責創建目錄 。傳遞字符串時,multer將確保為您創建目錄
destination: function (req, file, cb) {
cb(null, '/tmp/tmp_uploads')
},
// 用於確定應在文件夾內命名的文件
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
var upload = multer({ storage: storage })
-> upload.none();
-> 回傳的是 表單欄位 每一個的值,并包裝成對象
-> 用來解析 multipart/form-data 格式的 middleware
HTTP 全名是 超文本傳輸協定(HyperText Transfer Protocol),內容只規範了客戶端請求與伺服器回應的標準,實際上是藉由 TCP 作為資料的傳輸方式。
例如:
使用者送出了一個請求,經過 TCP 的三次握手之後,資料便能透過 TCP 傳遞給伺服器,並等待伺服器回應;然而這個一來一往的傳輸過程,資料都是 明文;如果傳遞的過程中有惡意竊聽者,資料便有機會被窺探、盜用。
所以,傳遞的內容不加密,就有如在網路上裸奔一樣;為了避免這些事情,我們需要把資料加密。
公開金鑰加密,也有人之稱為「非對稱式加密」;在這個加密規則中,每個通訊者都會有成對的兩把鑰匙:一把「公鑰」,一把「私鑰」,顧名思義,公鑰是所有人都看得到的,而私鑰是只有通訊者自己才看得到的;每個資料被任意一把鑰匙加密後,必須要透過與之配對的另一把鑰匙才能解密;例如我用我的私鑰加密的密文,就只能被我的公鑰解密,反之亦同。
HTTP 全名是 超文本傳輸協定(HyperText Transfer Protocol)。
HTTPS 全名 超文本傳輸安全協定,那個 S 就是 Secure 的意思;HTTPS 透過 HTTP 進行通訊,但通訊過程使用 SSL/TLS 進行加密,藉由類似於前述的加密方式,在 HTTP 之上定義了相對安全的資料傳輸方法。
由於非對稱加密的運算量較高,傳遞回應較慢;實際的架構上,會透過公開金鑰加密傳遞出共用的金鑰,再透過共用金鑰加密進行後續的傳遞,兼顧了安全性及傳遞速度。
We are customer-oriented and welcome to visit us during business hours.
+886 0988 220 903 / taiwan
今日營業 | 上午09:00 – 下午05:00 |
Copyright © 2020 william — all rights reserved.
本項服務由 GoDaddy 建站神器 提供