去重
const arr = [1,1,1,1,1,1,3,3,3,3,32,2,2,2,2,3,3,4,-1,-10,-10,-1,4,4,5,5,9]
// set方式去重
// 不改变源数组的数据
console.log([...new Set(arr)])
// includes方式去重, 时间复杂度 O(n)
function uniq(arr) {
let _result = []
for(let i=0; i < arr.length; i++) {
if (!_result.includes(arr[i])) {
_result.push(arr[i])
}
}
return _result
}
console.log(uniq(arr))
冒泡排序
let arr = [1,2,5,3,1,6,7,3,4,10,12,3,21]
function bubbleSort(arr) {
// 浅克隆, 对外部传入的参数不进行更改, 保证函数是一个纯函数
let _arr = [].concat(arr)
// 核心逻辑
for(let i=0; i<_arr.length -1; i++) {
for(let j=0; j<_arr.length-i-1; j++) {
if (_arr[j] > _arr[j+1]) {
let temp = _arr[j]
_arr[j] = _arr[j + 1]
_arr[j + 1] = temp
}
}
}
return _arr
}
console.log(bubbleSort(arr))
快速排序(二分法)
let arr = [300,432,1342,543,23,656,45,6465,4345,232,87,97,754,345]
function quickSort(arr) {
if(arr.length <= 1) {
return arr
}
const pivot = arr[0]
let bigger = []
let smaller = []
for(let i=1; i<arr.length; i++) {
if (arr[i] > pivot) {
bigger.push(arr[i])
}
}
for(let i=1; i<arr.length; i++) {
if (arr[i] < pivot) {
smaller.push(arr[i])
}
}
return quickSort(smaller).concat(pivot, quickSort(bigger))
}
console.log(quickSort(arr))
函数柯里化
案例一:
function curry(fn) {
return function() {
let arg = arguments
return function() {
return fn(...arg, ...arguments)
}
}
}
function fn(a,b,c,d) {
return a+b+c+d
}
let fun = curry(fn)
let fun2 = fun(1,2,3)
console.log(fun2(5))
案例二:
let fn = a => b => c => a+b+c
console.log(fn(1)(2)(3))
数组扁平化
let arr = [0,[3,4,5],[[[[12,5,6,7,54,34],43,34],33]], {a:1}]
function flatten(arr) {
let _arr = []
for(let i=0; i<arr.length; i++) {
const leixing = Object.prototype.toString.call(arr[i])
if (leixing !== '[object Array]') {
_arr.push(arr[i])
} else {
_arr = _arr.concat(flatten(arr[i]))
}
}
return _arr
}
console.log(flatten(arr))
原型链上扩展方法
Array.prototype.max = function max() {
console.log(this)
return Math.max.apply(Math, this)
}
let array = [1,2,3,4]
console.log(array.max())
深克隆
let arr = [1,2,3,[4,5,6], {a:1}]
function deepClone(o) {
if (
typeof o == 'number'
||
typeof o == 'string'
||
typeof o == 'boolean'
||
typeof o == 'undefined'
) {
return o
} else if(Array.isArray(o)) {
let _arr = []
for(let i=0; i<o.length; i++) {
_arr.push(deepClone(o[i]))
}
return _arr
} else if(typeof o == 'object') {
let _o = {}
for(let k in o) {
_o[k] = deepClone(o[k])
}
return _o
}
}
let deep = deepClone(arr)
console.log(arr[3] == deep[3]) // false
样本筛选函数
// 功能: 传入一个数值, 随机生成指定范围内的样本数据
// 参数: 样本个数
// start: 样本起始数值
// end: 样本结束数值
function sample(num, start, end) {
end -= 1
let _arr = []
while(num != _arr.length){
let data = parseInt(Math.random() * end) + start
if (!_arr.includes(data)) {
_arr.push(data)
}
}
return _arr
}
console.log(sample(30, 2, 32))
// 输出结果
// [
// 9, 27, 18, 28, 24, 13, 31, 11, 6,
// 19, 7, 17, 21, 26, 30, 22, 8, 25,
// 10, 3, 2, 5, 4, 12, 20, 14, 29,
// 15, 32, 23
// ]
字符串反转函数
let str = 'abcde'
function myReverse(str) {
return str.split('').reverse().join('')
}
let res = myReverse(str)
console.log(res)
偏函数
偏函数的作用: 调用之后能够获得一个特定功能的函数
// 需求: 实现一个检查类型的偏函数
function checkType(type) {
return function(o) {
return Object.prototype.toString.call(o) == `[object ${type}]`
}
}
let checkIsArray = checkType('Array')
console.log(checkIsArray([1,2,3]))
// 输出结果
// true
闭包
闭包的特点: 调用永久记住当前作用域的变量
案例一:
var a = 2
function foo() {
var a = 1
function bar() {
console.log(a)
}
bar()
}
foo()
//输出结果
//1
案例二:
var a = 1
function bar() {
console.log(a)
}
(function(fn) {
var a = 2
fn()
})(bar)
// 输出结果
// 1
箭头函数
// 箭头函数this跟定义时上下文永远绑定
// 普通函数的this, 视运行环境而改变
function fun() {
return () => {
console.log(this)
}
}
let laowang = {name: 'laowang'}
let xiaoliu = {name: 'xiaoliu'}
let arrowFun = fun.call(laowang)
arrowFun() // { name: 'laowang' }
arrowFun.call(xiaoliu) // { name: 'laowang' }
arrowFun = arrowFun.bind(xiaoliu)
arrowFun() // { name: 'laowang' }
函数新特征
// 函数非严格模式下实参与实参列表的关系
function fun(a, b) {
a = (typeof a !== 'undefined') ? a : 10
b = (typeof b !== 'undefined') ? b : 20
console.log(a == arguments[0])
console.log(b == arguments[1])
a = 123
b = 456
console.log(a == arguments[0])
console.log(b == arguments[1])
}
fun(1, 2)
// 输出结果
// true
// true
// true
// true
// 函数严格模式下实参与实参列表的关系
function fun(a, b) {
'use strict'
a = (typeof a !== 'undefined') ? a : 10
b = (typeof b !== 'undefined') ? b : 20
console.log(a == arguments[0])
console.log(b == arguments[1])
a = 123
b = 456
console.log(a == arguments[0])
console.log(b == arguments[1])
}
fun(1, 2)
// true
// true
// false
// false
// 函数改良
// 这种方式跟非严格模式下的执行结果是一致的
function fun(a=10, b=20) {
console.log(a == arguments[0])
console.log(b == arguments[1])
a = 123
b = 456
console.log(a == arguments[0])
console.log(b == arguments[1])
}
fun(1, 2)
// true
// true
// false
// false
暂时性死区
解释: 变量在定义之后, 但没有声明的情况下, 是暂时不能访问的
// 案例一: 函数后面的默认参数可以访问前面的参数
// 实参其实相当于使用 let来声明一个变量
function foo(a) {
return a + 5
}
function fun(a, b = foo(a)) {
console.log(a + b)
}
fun(1) // 7
fun(1, 2) // 3
// 案例二: 函数后面的参数无法访问前面参数的值
function add(a = b, b) {
return a + b
}
console.log(add(1, 2)) // 3
console.log(add(undefined, 2)) // ReferenceError: Cannot access 'b' before initialization
展开运算符
// 不使用展开运算符
let arr = [1,2,3,4]
let max = Math.max.apply(null,arr)
console.log(max)
// 改进
let arr = [1,2,3,4]
let max = Math.max(...arr)
console.log(max)
为什么使用严格模式
参考资料: https://www.runoob.com/js/js-strict.html
use strict解释: 为什么使用严格模式:
消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
消除代码运行的一些不安全之处,保证代码运行的安全;
提高编译器效率,增加运行速度;
为未来新版本的Javascript做好铺垫。
"严格模式"体现了Javascript更合理、更安全、更严谨的发展方向,包括IE 10在内的主流浏览器,都已经支持它,许多大项目已经开始全面拥抱它。
另一方面,同样的代码,在"严格模式"中,可能会有不一样的运行结果;一些在"正常模式"下可以运行的语句,在"严格模式"下将不能运行。掌握这些内容,有助于更细致深入地理解Javascript,让你变成一个更好的程序员。
迭代器
// 需求: 封装一个迭代器
function arrIterator(arr) {
let i = 0
return {
next: function() {
let done = i > arr.length - 1 ? true : false
let value = !done ? arr[i++] : 'undefined'
return {
done,
value
}
}
}
}
let arr = [1,2,3,4,5]
let iterator = arrIterator(arr)
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
// 输出结果
// { done: false, value: 1 }
// { done: false, value: 2 }
// { done: false, value: 3 }
// { done: false, value: 4 }
// { done: false, value: 5 }
// { done: true, value: 'undefined' }
生成器
// 生成器
// 作用: 用于生成迭代器
function *generator(arr) {
for(let i=0; i<arr.length; i++) {
yield arr[i]
}
}
let arr = [1,2,3,4,5]
const arrIterator = generator(arr)
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
// 生成器
// 作用: 用于生成迭代器
// 案例一
function *generator(arr) {
for(let i=0; i<arr.length; i++) {
yield arr[i]
}
}
let arr = [1,2,3,4,5]
const arrIterator = generator(arr)
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
console.log(arrIterator.next())
// 输出结果
// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: 4, done: false }
// { value: 5, done: false }
// { value: undefined, done: true }
// 案例二
// 生成器可以yield 一个Promise实例对象
function *generator() {
yield sumAfter1000ms(1,2).then(res => console.log(res))
yield sumAfter1000ms(2,2).then(res => console.log(res))
}
function sumAfter1000ms(a,b) {
return new Promise((resolve, reject) => {
setTimeout(function(){
resolve(a+b)
}, 2000)
})
}
const iterator = generator()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
// 输出结果
// { value: Promise { <pending> }, done: false }
// { value: Promise { <pending> }, done: false }
// { value: undefined, done: true }
// 3
// 4
Promise
promise作用:
- 解决毁掉地狱的问题
- 使代码调用更加清晰易懂
promise的三种状态:
- pending
- resolve
- reject.
promise特点:
- 使用resolve和reject封装结果回调函数
- Promise的实例会调用.then方法
// 案例一
// 不使用promise的情况
function fun(a, b, cb) {
setTimeout(function(){
return cb(a + b)
}, 2000)
}
fun(1,2, res => {
console.log(res)
fun(3,4, res => {
console.log(res)
fun(4, 5, res => {
console.log(res)
})
})
})
// 案例二: 使用promise的写法
function sum(a,b) {
return new Promise((resolve, reject) => {
setTimeout(function() {
resolve(a + b)
}, 2000)
})
}
sum(1,2)
.then(res => {
console.log(res)
})
// 案例三: 使用promise写法封装一个读文件操作函数
const fs = require('fs')
function readFile(filename) {
return new Promise((resolve, reject) => {
fs.readFile(filename, (err, res) => {
if (err) {
reject(new Error('所读的文件不存在'))
return
}
resolve(res.toString())
})
})
}
readFile('./1.txt').then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
async await
await后面紧跟的是一个Promise对象
function bar() {
setTimeout(() => {
console.log('hello')
}, 2000);
}
async function fun(){
let res = await bar()
return res
}
console.log(fun())
// 输出结果
// Promise { <pending> }
// hello
// 变形
function bar(a,b) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(a+b)
}, 2000);
})
}
async function fun(){
let res = await bar(1,2)
let res2 = await bar(3,4)
return {res, res2}
}
fun().then(res => {
console.log(res)
})
// 输出结果
// { res: 3, res2: 7 }