<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 观察者模式
let Observer = (function() {
// 消息管道
let _msg = {};
return {
// 绑定事件
on(type, callback) {
if (_msg[type]) {
// 直接存储
_msg[type].push(callback)
} else {
// 创建新的数组
_msg[type] = [callback]
}
},
// 发布事件
trigger(type, ...args) {
// 找到该类型的数组,逐一执行
_msg[type] && _msg[type].forEach(fn => fn(...args))
},
// 移除事件
off(type, callback) {
// 传递回调函数
if (callback) {
if (_msg[type]) {
// 获取位置
let index = _msg[type].indexOf(callback);
if (index >= 0) {
_msg[type].splice(index, 1)
}
}
} else if (type) {
_msg[type] = []
} else {
// 全部清空
_msg = {};
}
},
// 单次绑定
once(type, callback) {
// 缓存this
let me = this;
// 包装函数
function cb(...args) {
// 移除cb
me.off(type, cb);
callback(...args)
}
// 订阅cb
me.on(type, cb);
}
}
})();
// 测试
function demo(...args) {
console.log('demo', args);
// 发布了
// Observer.trigger('ickt', 200)
}
// 单次订阅
Observer.once('ickt', demo);
Observer.trigger('ickt', 100, 200)
// Observer.trigger('ickt', 100, 200)
// Observer.trigger('ickt', 100, 200)
// Observer.on('ickt', demo);
// Observer.on('ickt', function(...args) {
// console.log('test', args);
// })
// Observer.on('abc', function(...args) {
// console.log('abc', args);
// })
// 移除
// Observer.off('ickt', demo)
// Observer.off('ickt')
// Observer.off()
// Observer.off('ickt', function(...args) {
// console.log('test', args);
// })
// 发布
// Observer.trigger('ickt', 100, 200)
// Observer.trigger('abc', 100, 200)
</script>
</body>
</html>
节流和防抖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>1-1-1</h1>
<h1>2-2-2</h1>
<h1>3-3-3</h1>
<h1>4-4-4</h1>
<h1>5-5-5</h1>
<h1>6-6-6</h1>
<h1>7-7-7</h1>
<h1>8-8-8</h1>
<h1>9-9-9</h1>
<h1>10-10-10</h1>
<h1>11-11-11</h1>
<h1>12-12-12</h1>
<h1>13-13-13</h1>
<h1>14-14-14</h1>
<h1>15-15-15</h1>
<h1>16-16-16</h1>
<h1>17-17-17</h1>
<h1>18-18-18</h1>
<h1>19-19-19</h1>
<h1>20-20-20</h1>
<h1>21-21-21</h1>
<h1>22-22-22</h1>
<h1>23-23-23</h1>
<h1>24-24-24</h1>
<h1>25-25-25</h1>
<h1>26-26-26</h1>
<h1>27-27-27</h1>
<h1>28-28-28</h1>
<h1>29-29-29</h1>
<h1>30-30-30</h1>
<script>
// 事件回调函数
function demo(e) {
console.log('demo', e);
}
// 监听滚动条事件
window.onscroll = demo;
// 防抖: 执行最后一次
function ickt(fn, time = 200) {
// 定时器句柄
let timebar = null;
return function(...args) {
// 清除定时器
clearTimeout(timebar);
// 执行
timebar = setTimeout(function() {
fn(...args)
}, time)
}
}
window.onscroll = ickt(demo);
// 节流: 固定时间内,函数执行一次
function throttle(fn, time = 1000) {
// 订阅开关
let lock = false;
return function(...args) {
// 一旦上锁,无法执行
if (lock) {
return;
}
// 执行
fn(...args);
// 上锁
lock = true;
// 解锁
setTimeout(function() {
lock = false;
}, time)
}
}
window.onscroll = throttle(demo)
</script>
</body>
</html>
Promise的实现
// 实现Promise
function IcktPromise(callback) {
// 状态: 进入fulfilled, 进入rejected
this.state = 'padding';
// 存储成功的回调函数
this.successArray = [];
// 存储失败的回调函数
this.failArray = [];
// 执行结果
this.result = null;
// 成功时候的回调函数
let resolve = value => {
// 改变状态
this.state = 'fulfilled';
// 存储结果
this.result = value;
// 遍历数组,执行回调函数
this.successArray.forEach(fn => this.result = fn(this.result))
// 清空回调函数
this.successArray = [];
}
// 失败时候的回调函数
let reject = value => {
// 改变状态
this.state = 'rejected';
// 存储结果
this.result = value;
// 遍历数组,执行回调函数
this.failArray.forEach(fn => this.result = fn(this.result))
// 清空回调函数
this.failArray = [];
}
// 执行回调函数
try {
callback(resolve, reject);
} catch (e) {
reject(e);
}
}
// 监听结果
IcktPromise.prototype.then = function(success, fail) {
// 如果是padding
if (this.state === 'padding') {
success && this.successArray.push(success);
fail && this.failArray.push(fail);
} else if (this.state === 'fulfilled') {
success && success(this.result);
} else {
// 失败
fail && fail(this.result);
}
// 链式调用
return this;
}
// 使用Promise
let p = new IcktPromise((resolve, reject) => {
// 做异步
setTimeout(function() {
reject('scucess')
}, 1000)
})
// 监听结果
p.then(
data => {
console.log(data)
return 100;
},
err => console.log('err', err)
).then(data => console.log('第二个', data))
console.log(111, p);
jQuery
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div></div>
<div></div>
<div></div>
<script src="./jquery.js"></script>
<script>
// 创建实例的工厂方法
var A = function() {}
// 对象对应的类
var B = function() {}
// 减少变量个数
var A = function() {}
// A上存储B
// A.B = function() {}
// 不希望外界可以直接修改它
// A.B = 123;
A.prototype = {
num: 100,
version: '1.0'
}
// 放在原型上
A.prototype.B = function() {}
// 换个名字
var jQuery = function() {}
// 存储数据
jQuery.prototype = {
num: 100,
version: '1.0'
}
// 放在原型上
jQuery.prototype.init = function() {}
// 工厂方法:创建init实例
var jQuery = function(selector) {
// 返回init类的实例
return new jQuery.fn.init(selector)
}
// 给prototype起个名字,访问方便
jQuery.fn = jQuery.prototype = {
num: 100,
// 版本号
jquery: '1.0',
// 添加数组方法,让其看起来更像数组
push: Array.prototype.push,
splice: Array.prototype.splice
}
// 放在原型上
jQuery.fn.init = function(selector) {
// 长度
this.length = 0;
// 存储选择器
this.selector = selector;
// 获取元素
var doms = document.querySelectorAll(selector);
// 存储
for (var i = 0; i < doms.length; i++) {
// 存储元素
this[i] = doms[i];
// 更新长度
this.length++;
}
}
// 为了让init类的实例具有jQuery工厂原型上的数据,可以通过修改原型来实现.
jQuery.fn.init.prototype = jQuery.fn;
// 拓展jQuery.fn就是拓展init类的原型了
// jQuery.fn.demo = function() {}
// jQuery.fn.color = 'red';
// 拓展方法的方法
jQuery.extend = jQuery.fn.extend = function(target) {
// this指向调用者
// 将target属性复制给调用者
for (var key in target) {
this[key] = target[key];
}
}
// 拓展静态属性
jQuery.extend({
each: function() {},
ajax: function() {}
})
jQuery.fn.extend({
// 设置内容
html: function(html) {
// 给每个元素设置内容
for (var i = 0; i < this.length; i++) {
this[i].innerHTML = html;
}
// 链式调用
return this;
},
// 设置样式
css: function(key, value) {
// 判断
if (typeof key === 'string') {
// 遍历元素,设置样式
for (var i = 0; i < this.length; i++) {
this[i].style[key] = value;
}
return this;
}
// 如果是对象
for (var k in key) {
// 递归调用
this.css(k, key[k])
}
// 链式调用
return this;
}
})
// 使用简单
var $ = jQuery;
</script>
<script>
// console.log($('div'));
$('div')
.html('爱创乐育')
.css({ color: 'red', fontSize: '50px' })
.css('background', 'green')
</script>
</body>
</html>
程序控制权
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// 异步:setTimeout
// 伪异步:Promise, async/await 微任务
// 2 6 7 b 3 8 9 4 a 5 1
// 先找同步,再处理异步(微任务和宏任务)
// 定时器
// setTimeout(function() {
// console.log(111);
// }, 0);
// // promise
// let p = new Promise((resolve, reject) => {
// resolve('success')
// console.log(222);
// })
// // 监听结果
// p
// .then(data => console.log(333))
// .then(data => console.log(444))
// .then(data => console.log(555))
// // 异步函数
// async function demo() {
// console.log(666);
// await console.log(777);
// console.log(888)
// await console.log(999);
// console.log('aaa');
// }
// demo();
// console.log('bbb');
// 2 4 5 9 3 6 1
// 面试题
// setTimeout(() => {
// console.log(111);
// }, 0)
// async function demo() {
// console.log(222);
// await 100;
// console.log(333);
// }
// demo();
// var p = new Promise(resolve => {
// console.log(444);
// resolve();
// console.log(555);
// })
// p.then(
// res => console.log(666)
// )
// function *test() {
// console.log(777);
// yield 100;
// console.log(888);
// }
// let t = test()
// t.next()
// t.next()
// t.next()
// console.log(999);
// setTimeout(() => {
// console.log(111);
// }, 0)
// async function demo() {
// console.log(222);
// await 100;
// console.log(333);
// await 200;
// console.log('aaa');
// await 300;
// console.log('bbb');
// await 400;
// console.log('ccc');
// }
// demo();
// var p = new Promise(resolve => {
// console.log(444);
// resolve();
// console.log(555);
// })
// p
// .then(
// res => console.log(666)
// )
// .then(
// res => console.log('ddd')
// )
// .then(
// res => console.log('eee')
// )
// function *test() {
// console.log(777);
// yield 100;
// console.log(888);
// }
// let t = test()
// t.next();
// t.next();
// console.log(999);
// 2 4 5 7 8 9 3 6 a d b e c 1
// 3 1 7 9 4 2 8 5 6 123
// setTimeout(() => {
// console.log(123123123);
// }, 0)
// function testSometing() {
// console.log(111, "执行testSometing");
// return "testSometing";
// }
// async function testAsync() {
// console.log(222, "执行testAsync");
// return Promise.resolve("hello async");
// }
// async function test() {
// console.log(333, "test start...");
// const v1 = await testSometing();
// console.log(444, v1);
// const v2 = await testAsync();
// console.log(555, v2);
// console.log(666, v1, v2);
// }
// test();
// var promise = new Promise((resolve)=> {
// console.log(777, "promise start..");
// resolve("promise");
// });
// promise.then((val)=> console.log(888, val));
// console.log(999, "test end...")
// 3 1 7 9 4 2 8 100 200 300 400 5 6 500 123
setTimeout(() => {
console.log(123123123);
}, 0)
async function testSometing() {
console.log(111, "执行testSometing");
return "testSometing";
}
async function testAsync() {
console.log(222, "执行testAsync");
await 100;
console.log(100, 'bbb');
return Promise.resolve("hello async");
// return 200;
}
async function test() {
console.log(333, "test start...");
const v1 = await testSometing();
console.log(444, v1);
const v2 = await testAsync();
console.log(555, v2);
console.log(666, v1, v2);
}
test();
var promise = new Promise((resolve)=> {
console.log(777, "promise start..");
resolve("promise");
});
promise
.then((val)=> console.log(888, val))
.then((val)=> console.log(200, 'aaa', val))
.then((val)=> console.log(300, 'bbb', val))
.then((val)=> console.log(400, 'bbb', val))
.then((val)=> console.log(500, 'bbb', val));
console.log(999, "test end...")
</script>
</body>
</html>