Fe-7-1
數(shù)據(jù)類型
在 js 中, 每一個(gè)變量(也就是每一個(gè)值)都有一個(gè)類型
- 內(nèi)置的基本數(shù)據(jù)有以下幾種類型
number 數(shù)字
string 字符串
boolean 布爾變量(只有兩個(gè)值 true 或 false)
object 對(duì)象, 是高級(jí)一點(diǎn)的內(nèi)容
null 和 undefined
這兩個(gè)東西很相似, 有這么兩個(gè)東西主要是歷史原因造成的
具體細(xì)節(jié)可看這個(gè)鏈接, 不過不需要關(guān)心
http://www.ruanyifeng.com/blog/2014/03/undefined-vs-null.html
函數(shù)也是一個(gè)變量, 稍微特殊點(diǎn), 但在 js 中沒什么本質(zhì)不同
它的類型是函數(shù)
// 為一個(gè)變量賦值就創(chuàng)建了一個(gè)變量
// JavaScript 中, 變量只是對(duì)值的一個(gè)引用
// 比如下面, 分別把 3 個(gè)不同類型的值賦值給變量 a
var a
a = 1 // a 是 number
a = 1.1 // number
a = 'good' // string
// 可以用 typeof 語句得到一個(gè)變量的類型
a = 10
b = true
c = 'I am good'
log('type a', typeof a)
log('type b', typeof b)
log('type c', typeof c)
運(yùn)行, 輸出如下
type a number
type b boolean
type c string
前提定義log函數(shù)
// 定義 log 函數(shù)
var log = function() {
console.log.apply(console, arguments)
}
- 單行字符串變多行字符串用轉(zhuǎn)意符號(hào)
- 多行字符串
多行字符串又稱模板字符串
使用反引號(hào), 鍵盤左上角波浪線
var a = `多
行
字符串`
log('多行字符串', a)
a = `
i
am
good
`
log('多行字符串 2', a)
不同的數(shù)據(jù)類型是不能混用的
比如 float 就不能當(dāng)下標(biāo)
- 轉(zhuǎn)義符
在代碼中表示字符串的時(shí)候, 很多東西不方便表示, 因此我們使用轉(zhuǎn)義符的方式來表示
轉(zhuǎn)義符是字符串中的特殊符號(hào)翠忠,由反斜杠(backslash)開始
接另一個(gè)字符結(jié)束
常用的轉(zhuǎn)義符有
還有一些別的轉(zhuǎn)義符充择,但極少使用,對(duì)于這種東西色乾,不必記憶辕坝,知道有這么回事就好了窍奋。
// \n // 表示一個(gè)換行符
// \t // 表示一個(gè) TAB(制表符)
// \\ // 表示一個(gè)反斜杠 \
// \' // 表示一個(gè)單引號(hào)
// \" // 表示一個(gè)雙引號(hào)
//
// 例子:
log('I\'a\tm \n\ngood\n')
高階函數(shù) 就是函數(shù)當(dāng)參數(shù)傳遞
// =====
// 高階函數(shù)
// =====
//
// 高階函數(shù)這個(gè)名字很唬人, 實(shí)際上概念很簡(jiǎn)單——函數(shù)可以作為參數(shù)傳遞
//
// 有什么用呢?靈活性高酱畅,舒適度佳
// 請(qǐng)看例子
//
// String 函數(shù)是用來把數(shù)據(jù)轉(zhuǎn)換成 string 類型的一個(gè)函數(shù)
log('string ', String(6.3))
var process = function(array, processor) {
/*
array 是一個(gè)數(shù)組
processor 是一個(gè)函數(shù), 注意, 這是一個(gè)函數(shù), 所以可以調(diào)用
把 array 中的每個(gè)元素都用 processor 函數(shù)處理并返回一個(gè)
新的 array
*/
var l = []
for (var i = 0; i < array.length; i++) {
var a = array[i]
// processor 必須能調(diào)用成功, 否則這里就跪了
var element = processor(a)
l.push(element)
}
return l
}
// 創(chuàng)建一個(gè) array, 包含 3 個(gè) number
var array = [1.1, -2.2, 3.3]
// String 內(nèi)置函數(shù)
var stringList = process(array, String)
log('stringList', stringList)
// Math.floor 函數(shù)可以把小數(shù)轉(zhuǎn)成整數(shù), 可以自行試試
process(array, Math.floor)
// 輸出結(jié)果如下
// 我們可以看到, process 函數(shù)通過 參數(shù)傳進(jìn)來的函數(shù) 對(duì)數(shù)據(jù)進(jìn)行了處理
// stringList ['1.1', '-2.2', '3.3']
// =====
// 匿名函數(shù)
// =====
//
// 有時(shí)候要傳遞高階函數(shù)的時(shí)候, 函數(shù)很短, 可能就一行
// 如果去定義一個(gè)新函數(shù)有人覺得劃不來, 就想了一個(gè)偷懶的辦法
// 那就是匿名函數(shù)
// 匿名函數(shù)的意思是沒有函數(shù)名, 一般定義了就用
// 實(shí)際上我們之前寫的函數(shù)都是匿名函數(shù), 只不過把它賦值給了一個(gè)變量而已
// 例子
// 定義一個(gè) square 函數(shù)求平方
var square = function(n) {
return n * n
}
// 用上面的 process 函數(shù)處理試試
var array = [1, 2, 3]
var squareList = process(array, square)
log('square list', squareList)
var addList = process(array, function(n){
// 我們定義一個(gè)接受一個(gè)參數(shù)的函數(shù)并且直接使用, 它沒有名字
return n + 1
})
log('add list', addList)
// 輸出結(jié)果如下
// square list [1, 4, 9]
// add list [2, 3, 4]
Fe-7-2 Todo
-
添加琳袄,刪除,完成纺酸,還有本地存儲(chǔ)
todo.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Todo</title>
<style>
.done {
color: gray;
text-decoration: line-through;
background: lightblue;
}
</style>
</head>
<body><div class="todo-form">
<input id="id-input-todo" type="text">
<button id="id-button-add" name="button">Add</button>
</div>
<div id="id-div-container">
<div class="todo-cell">
<!-- <button class='todo-done'>完成</button>
<button class='todo-delete'>刪除</button>
<span class='todo-content' contenteditable='true'>上課</span>
-->
</div>
</div>
<script src="todo.js" charset="utf-8"></script>
</body>
</html>
todo.js
// 2016/12/06
//
// 此為第 7 課的上課內(nèi)容 2
//
// 這部分的主要內(nèi)容有
//
// 通過一個(gè) Todo 應(yīng)用, 學(xué)習(xí)下面這個(gè)概念
// 1, 什么是事件委托
// 2, 為什么需要事件委托
// 3, 如何實(shí)現(xiàn)事件委托
//
// 時(shí)間操作
// content editable (標(biāo)簽的可編輯屬性)
// localStorage (本地存儲(chǔ)) 和 JSON 數(shù)據(jù)格式
//
//
// 應(yīng)該都能看懂, 不懂的稍微做個(gè)筆記, 等上課講解
// 自己定義一個(gè) log 函數(shù)
var log = function() {
console.log.apply(console, arguments)
}
// 用自己實(shí)現(xiàn)的 e 替代 document.querySelector
// 因?yàn)檫@個(gè)東西太長(zhǎng)了
var e = function(selector) {
return document.querySelector(selector)
}
// 給 add button 綁定添加 todo 事件
var addButton = e('#id-button-add')
addButton.addEventListener('click', function(){
// 獲得 input.value
var todoInput = e('#id-input-todo')
var todo = todoInput.value
// 添加到 container 中
insertTodo(todo, false)
// 添加之后 保存 todos
saveTodos()
})
var insertTodo = function(todo, done) {
// 添加到 container 中
var todoContainer = e('#id-div-container')
var t = templateTodo(todo, done)
// 這個(gè)方法用來添加元素
// 第一個(gè)參數(shù) 'beforeend' 意思是放在最后
todoContainer.insertAdjacentHTML('beforeend', t);
}
var templateTodo = function(todo, done) {
var status = ''
if(done) {
status = 'done'
}
var t = `
<div class='todo-cell ${status}'>
<button class='todo-done'>完成</button>
<button class='todo-delete'>刪除</button>
<span class='todo-content' contenteditable='true'>${todo}</span>
</div>
`
return t
}
// 事件委托相關(guān)概念
// ===
//
// 問題在于, todo 都是運(yùn)行的時(shí)候才添加的元素
// 對(duì)于這樣的元素, 我們沒辦法實(shí)現(xiàn)綁定事件
// 我們可以把 click 事件綁定在事先存在的父元素上
// 然后在運(yùn)行的時(shí)候檢查被點(diǎn)擊的對(duì)象(通過 event.target 屬性)
// 是否是我們需要的對(duì)象, 這個(gè)概念就是事件委托
var todoContainer = e('#id-div-container')
// 通過 event.target 的 class 來檢查點(diǎn)擊的是什么
todoContainer.addEventListener('click', function(event){
log('container click', event, event.target)
var target = event.target
// classList.contains 可以檢查元素是否有一個(gè) class
if(target.classList.contains('todo-done')) {
log('done')
// target.parentElement 用來獲取按鈕的父節(jié)點(diǎn)
// 給 todo div 開關(guān)一個(gè)狀態(tài) class
var todoDiv = target.parentElement
toggleClass(todoDiv, 'done')
// 改變 todo 完成狀態(tài)之后窖逗,保存 todos
saveTodos()
} else if (target.classList.contains('todo-delete')) {
log('delete')
// 找到按鈕的父節(jié)點(diǎn)并且刪除
var todoDiv = target.parentElement
todoDiv.remove()
// 刪除之后 保存 todos
saveTodos()
}
})
// 這個(gè)函數(shù)用來開關(guān)一個(gè)元素的某個(gè) class
var toggleClass = function(element, className) {
// 檢查元素是否擁有某個(gè) classs
if (element.classList.contains(className)) {
// 擁有則刪除之
element.classList.remove(className)
} else {
// 沒有則加上
element.classList.add(className)
}
}
// localStorage(本地存儲(chǔ)) 是瀏覽器自帶的功能
// localStorage 可以用來存儲(chǔ)字符串?dāng)?shù)據(jù), 在瀏覽器關(guān)閉后依然存在
// 但是不同頁面擁有各自獨(dú)立的 localStorage
// 存儲(chǔ)方法如下
localStorage.name = 'gua'
// 關(guān)閉瀏覽器, 再次打開, 仍然能獲取到這個(gè)值
// log('關(guān)閉瀏覽器后', localStorage.name)
//
// 利用 localStorage 就可以存儲(chǔ) todo
// 但是 todo 存在 array 中
// 而 localStorage 只能存儲(chǔ) string 數(shù)據(jù)
// 所以沒辦法直接存儲(chǔ)
//
// 可行的辦法如下
// 存儲(chǔ)的時(shí)候把 array 轉(zhuǎn)換為字符串
// 讀取的時(shí)候把字符串轉(zhuǎn)成 array
// 這個(gè)過程通常被稱之為 序列化 和 反序列化
//
// 在 js 中, 序列化使用 JSON 數(shù)據(jù)格式
// 全稱 JavaScript Object Notation (js對(duì)象標(biāo)記)
// 這個(gè)格式已經(jīng)是現(xiàn)在用于互聯(lián)網(wǎng)數(shù)據(jù)交換的事實(shí)標(biāo)準(zhǔn)格式了
// ISO 是國(guó)際標(biāo)準(zhǔn)
// IEEE 國(guó)際電子電氣工程師協(xié)會(huì)
// GB 中國(guó)國(guó)標(biāo)
var s = JSON.stringify([1, 2, 3, 4])
log('序列化后的字符串', typeof s, s)
var a = JSON.parse(s)
log('反序列化后的數(shù)組', typeof a, a)
// 使用 JSON 序列化后, 就可以把 todo 存入瀏覽器的 localStorage 了
// 定義一個(gè)函數(shù), 用于把 數(shù)組 寫入 localStorage
var save = function(array) {
var s = JSON.stringify(array)
localStorage.todos = s
}
// 定義一個(gè)函數(shù)餐蔬, 讀取 localStorage 中的數(shù)據(jù)并解析返回
var load = function() {
var s = localStorage.todos
return JSON.parse(s)
}
// 定義一個(gè)函數(shù)碎紊, 把頁面上所有的 todo 用 save 保存
var saveTodos = function() {
// 1 先選出所有的 content 標(biāo)簽
// 2 取出 todo
// 3 添加到一個(gè) 數(shù)組中
// 4 保存數(shù)組
log('save todos')
var contents = document.querySelectorAll('.todo-content')
var todos = []
for (var i = 0; i < contents.length; i++) {
var c = contents[i]
var done = c.parentElement.classList.contains('done')
var todo = {
done: done,
content: c.innerHTML,
}
// 添加到數(shù)組中
todos.push(todo)
}
// 保存數(shù)組
save(todos)
}
var loadTodos = function() {
var todos = load()
log('load todos', todos)
// 添加到頁面中
for (var i = 0; i < todos.length; i++) {
var todo = todos[i]
insertTodo(todo.content, todo.done)
}
}
loadTodos()
// 時(shí)間標(biāo)準(zhǔn)庫
// 常用用法如下
// var d = new Date()
// d.getFullYear()
// 年份, 2016
// d.getMonth()
// 月份, 0-11
// d.getDate()
// 日期, 1-31
// d.getHours()
// 小時(shí), 0-23
// d.getMinutes()
// 分鐘, 0-59
// d.getSeconds()
// 秒數(shù), 0-59
// d.getMilliseconds()
// 毫秒, 0-999
// d.getDay()
// 星期幾, 0-6
var now = function() {
var d = new Date()
var nm = d.getFullYear()
var yt = d.getMonth() + 1
var ri = d.getDate()
var ui = d.getHours()
var ff = d.getMinutes()
var mc = d.getSeconds()
return `${nm}/${yt}/${ri} ${ui}:${ff}:${mc}`
// return nm + '/' + yt + '/' + ri + ' ' + ui + ':' + ff + ':' + mc
}