一. 实现一个九九乘法表
实现: 用两层 for 循环就可实现
for(let i=1; i<10; i++) {
for(let j=1; j<i + 1; j++) {
document.write(`${j} * ${i} = ${i*j} `)
}
document.write(`</br>`)
}
结果
二. 找出1000以内的水仙花数
水仙花数: 水仙花数是指一个 n 位数 ( n≥3 ), 如果一个 n 位正整数等于其各位数字的 n 次方之和, 例如1^3 + 5^3 + 3^3 = 153
实现: 使用 % 取余, 使用 parseInt() 取整, 就可分别获取个、十、百位的数字, 然后做判断即可.
for(let i=100; i<1000; i++) {
let ones = parseInt(i%10)
let tens = parseInt((i/10)%10)
let hundreds = parseInt((i/100)%10)
if(ones*ones*ones + tens*tens*tens + hundreds*hundreds*hundreds == i) {
console.log(`水仙花数: ${i}`)
}
}
结果
三. 找出一串字符串/数组出现最多的字符
实现: 首先判断是字符串还是数组, 字符串就转成数组, 然后将数据以对象的key为数组的值, 对象的值为出现的次数的方式存储, 然后循环这个对象就可得到结果
function findCharacter(str) {
if(!str.length) return
// 判断是不是数组, 不是的话将字符串转成数组
let arr = Array.isArray(str) ? str : str.split('')
// 分别定义空对象, 最多出现值和最大次数
let data = {}
let maxNumber, maxTimes = 0
// 将数据和数据出现次数存放在对象中
arr.forEach(el => {
data[el] ? data[el]++ : data[el] = 1
})
// 最多出现值和出现最大次数
for(let num in data) {
if(data[num] > maxTimes) {
maxTimes = data[num]
maxNumber = num
}
}
return `重复次数最多的值是: ${maxNumber}, 一共出现了: ${maxTimes}次`
}
四. 模拟实现call,apply
- 模拟实现call 实现: 注意两点, 一是call改变了this的指向, 指向了data, 二是执行了test函数. 最后注意this可以为null.
Function.prototype.simulateCall = function(context, ...args) {
// 当context为null时
let ctx = context || window
ctx.fn = this
const result = ctx.fn(...args)
delete context
return result
}
// 测试
var name = '全局磊'
let data = {
name: '局部磊'
};
function test(age,job) {
let name = this.name
return { name, age, job }
}
test.simulateCall(data, '18', '前端小白') // {name: "局部磊", age: "18", job: "前端小白"}
test.simulateCall(null, '18', '前端小白') // {name: "全局磊", age: "18", job: "前端小白"}
test.call(data, '18', '前端小白') // {name: "局部磊", age: "18", job: "前端小白"}
test.call(null, '18', '前端小白') // {name: "全局磊", age: "18", job: "前端小白"}
- 模拟实现apply 实现: 原理和call一样, 传值不同而已
Function.prototype.simulateApply = function (context, ...args){
// 当context为null时
let ctx = context || window
ctx.fn = this
const result = ctx.fn(...args)
delete context
return result
}
五. 模拟实现bind
实现: 模拟实现bind和模拟实现call和apply是不一样的, 因为bind改变this指向之后, 需要再执行一下函数.
Function.prototype.simulateBind = function(context, ...args) {
let self = this;
let args = Array.prototype.slice.call(arguments, 1);
let blankFn = function () {};
let boundFn = function () {
let bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof blankFn ? this : context, args.concat(bindArgs));
}
blankFn.prototype = this.prototype;
boundFn.prototype = new blankFn();
return boundFn;
}
六. 手写防抖函数
实现: 防抖的原理是当持续触发事件时,一定时间内没有再触发事件,事件处理函数才会执行一次,在设定时间内,有一次触发事件,就重新计算时间.
function debounce(fn, time){
var timeout = null
return function () {
clearTimeout(timeout)
timeout = setTimeout(() => {
fn()
}, time)
}
}
七. 手写节流函数
实现: 节流的原理是当持续触发事件时,保证在一定时间内只调用一次事件处理函数,相当于定时器.
function throttle(fn, time){
var execute = true
return function () {
if(!execute) return
execute = false
setTimeout(() => {
fn()
execute = true
}, time)
}
}