推荐书籍: javascript高级程序设计 和犀牛书
版本1
<ul id="user-list">
<li>001</li>
<li>002</li>
<li>003</li>
<li>004</li>
</ul>
body {
background-color: white;
font-size: 24px;
}
#user-list {
line-height: 1.5em;
}
#user-list>li:hover {
background-color: rgba(0, 0, 0, .3);
}
let list = document.querySelector('#user-list')
let items = list.querySelectorAll('#user-list > li');
list.addEventListener('click', function(e) {
if (e.target.tagName === 'LI') {
let item = e.target;
items.forEach(function(item) {
item.style.background = 'inherit';
item.style.color = 'inherit'
});
item.style.background = 'black';
item.style.color = 'white';
console.log(item.innerHTML);
}
})
版本2
<ul id="user-list">
<li>001</li>
<li>002</li>
<li>003</li>
<li>004</li>
</ul>
body {
background-color: white;
font-size: 24px;
}
#user-list {
line-height: 1.5em;
}
#user-list>li:hover {
background-color: rgba(0, 0, 0, .3);
}
#user-list>li.active {
background-color: black;
color: white;
}
let list = document.querySelector('#user-list')
let items = list.querySelectorAll('#user-list > li');
list.addEventListener('click', function(e) {
if (e.target.tagName === 'LI') {
let item = e.target;
items.forEach(function(item) {
item.className = '';
});
item.className = "active";
console.log(item.innerHTML);
}
})
版本3
<ul id="user-list">
<li>
<input type="radio" name="item" id="item0" value="001">
<label for="item0">001 </label>
</li>
<li>
<input type="radio" name="item" id="item1" value="002">
<label for="item1">002</label>
</li>
<li>
<input type="radio" name="item" id="item2" value="003">
<label for="item2">003</label>
</li>
<li>
<input type="radio" name="item" id="item3" value="004">
<label for="item3">004</label>
</li>
</ul>
* {
margin: 0;
padding: 0;
}
body {
background-color: white;
font-size: 24px;
}
#user-list {
line-height: 1.5em;
}
#user-list input {
display: none;
}
#user-list label {
display: block;
}
#user-list>li:hover {
background-color: rgba(0, 0, 0, .3);
}
#user-list input:checked+label {
background-color: black;
color: white;
}
let list = document.querySelector('#user-list')
list.addEventListener('click', function(e) {
if (e.target.tagName === 'INPUT') {
let chedkedItem = list.querySelector('input:checked');
console.log(chedkedItem.value);
}
})
思考 ?
写javaScript 操作DOM 要注意什么?
javaScript 与HTML CSS 的指责如何分离?
在复杂性放在那一头 ,为什么?
问题2:API的设计
三个状态红(stop)绿(pass) 黄(wait)表示
要求用javaScript 让三个状态轮流切换
每个状态停留时间2秒
版本1
<ul id="traffic" class="wait">
<li> <span></span> </li>
<li> <span></span> </li>
<li> <span></span> </li>
</ul>
#ttraffic>li {
display: block;
}
#traffic span {
display: inline-block;
width: 50px;
height: 50px;
background-color: gray;
margin: 5px;
border-radius: 50%;
}
#traffic.stop li:nth-child(1) span {
background-color: #a00;
}
#traffic.wait li:nth-child(2) span {
background-color: #aa0;
}
#traffic.pass li:nth-child(3) span {
background-color: #0a0;
}
const traffic =document.getElementById("roundness");
(function reset() {
traffic.className = "wait";
setTimeout(function(){
traffic.className="stop";
setTimeout(function(){
traffic.className="pass";
setTimeout(reset,2000);
},2000)
},2000)
})()
版本1 的问题?
如果需求增加到5盏,10盏灯?
过程耦合 + Callback Hell 。。。差评 !!!
版本2
const traffic = document.getElementById('traffic');
var stateList = ['wait', 'stop', 'pass'];
var currentStateIndex = 0;
setInterval(function() {
var state = stateList[currentStateIndex]
traffic.className = state;
currentStateIndex = (currentStateIndex + 1) % stateList.length;
}, 2000)
依赖外部变量 stateList currentStateIndex
封装行不好。。。差评!!
版本3
const traffic = document.getElementById('traffic');
function start(traffic, stateList) {
var currentStateIndex = 0;
setInterval(function () {
var state = stateList[currentStateIndex]
traffic.className = state;
currentStateIndex = (currentStateIndex + 1 ) % stateList.length
},2000)
}
start(traffic, ['wait','stop', 'pass']);
虽然中规中矩
但其实可复用性差!
版本4
const traffic = document.getElementById('traffic');
function poll(...fnList) {
let stateIndex = 0;
return function(...args) {
let fn = fnList[stateIndex++ % fnList.length];
return fn.apply(this, args);
}
}
function setState(state) {
traffic.className = state;
}
let trafficStatePoll = poll(setState.bind(null, 'wait'),
setState.bind(null, 'stop'),
setState.bind(null, 'pass'))
setInterval(trafficStatePoll, 2000);
function a() { return 1;}
function b() { return 0;}
var toggle = poll(a,b);
console.log([toggle(),toggle(),toggle()]) //[1,0,1]
版本4 函数式 变成 抽象出poll 方法
需求更改
wait stop pass 状态时间不想等 风别改成 1秒 2秒 3秒
版本5 Promise 解决问题 抽象wait 方法
const traffic = document.getElementById('traffic');
function wait(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
function setState(state) {
traffic.className = state;
}
function reset() {
Promise.resolve()
.then(setState.bind(null, 'wait'))
.then(wait.bind(null, 1000))
.then(setState.bind(null, 'stop'))
.then(wait.bind(null, 2000))
.then(setState.bind(null, 'pass'))
.then(wait.bind(null, 3000))
.then(reset)
}
reset()
版本6
const trafficEl = document.getElementById('traffic');
function TrafficProtocol(el, reset) {
this.subject = el;
this.autoReset = reset;
this.stateList = []
}
TrafficProtocol.prototype.putState = function(fn) {
this.stateList.push(fn);
}
TrafficProtocol.prototype.reset = function() {
let subject = this.subject;
this.setStatePromise = Promise.resolve();
this.stateList.forEach((stateFn) => {
this.setStatePromise = this.setStatePromise.then(() => {
return new Promise(resolve => {
stateFn(subject, resolve)
})
})
})
if (this.autoReset) {
this.setStatePromise.then(this.reset.bind(this));
}
}
TrafficProtocol.prototype.start = function() {
this.reset();
}
var traffic = new TrafficProtocol(trafficEl, true);
traffic.putState(function(subject, next) {
subject.className = 'wait';
setTimeout(next, 1000)
})
traffic.putState(function(subject, next) {
subject.className = 'stop';
setTimeout(next, 2000)
})
traffic.putState(function(subject, next) {
subject.className = 'pass';
setTimeout(next, 3000)
})
traffic.start();
优点:面向对象 函数式 Promise 灵活可扩展
缺点 :复杂度 实现难度 是否过度设计
设计是把双刃剑
写代码简单
程序设计不易
且行且珍惜
问题3 javaScript 的’效率问题’?
给你一个很大的数组 ,数组里面有许多整数,用javaScript实现一个函数 要求
将数组之和为10的每一对数配对并找出,返回这些数配合对后的数组
例如 :[11,3,8,9,7,-1,1,2,4,…]
得到 : [[11,-1],[3,7],[8,2],[9,1]]
版本1
var list = [11,4,9,3,-1,6,7,9,13]
function map (list) {
let ret = [] ,len = list.length;
for(let i = 0 ;i <len;i++ ){
for(let j=i+1;j<len;j++ ){
if (list[i]+ list[j] ==10) {
ret.push([list[i], list[j]])
}
}
}
return ret;
}
console.log(JSON.stringify(map(list)))
版本2
var list = [11, 4, 9, 3, -1, 6, 7, 9, 13]
function map(list) {
let ret = [];
list = list.sort((a, b) => a - b);
for (let i = 0, j = list.length - 1; i < j;) {
let a = list[i],
b = list[j];
if (a + b === 10) {
ret.push([a, b]);
i++;
j--
} else if (a + b < 10) {
i++
} else {
j--
}
}
return ret;
}
console.log(JSON.stringify(map(list)))
为什么版本2 比版本1 快很多
还有没有别的解发?
总结
这一课 我们学习了什么?
怎么写好的代码
1:代码职责
2:花时间思考问题API
3:好的算法
补充
在动态脚本语言中 函数是javaScript最核心的内容精髓
function setColor(color, el) {
el.style.color = color;
}
正常情况下是这样调用
setColor('red', content)
现在我们想这样调用
setColor(content,'red')
方案一 重新写一个
function setColor2(el, color) {
el.style.color = color;
}
方案2 调用
function setColor2(el, color) {
setColor(color, el);
}
方案3 抽象过程
function reverseArgs(fn) {
return function(...args) {
args = args.reverse();
return fn.apply(this, args)
}
}
setColor = reverseArgs(setColor);
100 毫秒延时执行的组合函数
function delay(fn, time) {
return function (...args) {
setTimeout(fn.bind(this, ...args), time);
}
}
setColor = delay(reverseArgs(setColor),1000)
var wait500 = reverseArgs(setTimeout).bind(null, 500)
wait500(()=> console.log('message'));
数据抽象 用函数来解决数据问题
过程抽象 用函数来解决函数计算问题