JavaScript - day2学习笔记
面向对象编程
构造函数与原型对象
使用构造函数创建对象,通过原型共享方法节约内存
// 构造函数 - 存在内存浪费问题
function Person(name) {
this.name = name
this.sayHi = function() {
console.log('Hi ' + this.name)
}
}
// 原型对象 - 共享方法节约内存
function Person(name) {
this.name = name
}
Person.prototype.sayHi = function() {
console.log('Hi~' + this.name)
}
const p1 = new Person('小明')
const p2 = new Person('小红')
p1.sayHi() // Hi~小明
p2.sayHi() // Hi~小红 - 共享同一个方法
原型链机制
基于原型对象的继承使得不同构造函数的原型对象关联在一起,并且这种关联的关系是一种链状的结构,我们将原型对
象的链状结构关系称为原型链(对象属性查找的链式结构)

function Star() { }
Star.prototype.name = '原型上的名字'
const ldh = new Star()
console.log(ldh.name) // 查找顺序:ldh自身 → Star原型 → Object原型 → null
// instanceof 检测原型链
console.log(ldh instanceof Star) // true
console.log(ldh instanceof Object) // true
原型继承
通过原型实现对象间的继承关系
// 父类
function Person() {
this.eyes = 2
this.head = 1
}
// 子类继承
function Woman() {}
Woman.prototype = new Person()
Woman.prototype.constructor = Woman
Woman.prototype.baby = function() {
console.log('生孩子')
}
function Man() {}
Man.prototype = new Person()
Man.prototype.constructor = Man
const red = new Woman()
console.log(red.eyes) // 2 - 继承自Person
深浅拷贝
浅拷贝
拷贝对象的第一层属性,引用类型共享地址
const obj = {
name: '小明',
hobby: ['篮球', '游泳'],
info: {age: 18}
}
// 对象浅拷贝
const obj2 = Object.assign({}, obj)
const obj3 = {...obj}
// 数组浅拷贝
const arr = [1, 2, [3, 4]]
const arr2 = arr.concat()
const arr3 = [...arr]
obj2.hobby[0] = '足球'
console.log(obj.hobby[0]) // 足球 - 被影响,因为共享地址
深拷贝
完全拷贝对象,包括嵌套的引用类型
const obj = {
name: '小明',
hobby: ['篮球', '游泳'],
info: {age: 18}
}
// 1. 递归实现深拷贝
function deepCopy(newObj, oldObj) {
for (let k in oldObj) {
if (oldObj[k] instanceof Array) {
newObj[k] = []
deepCopy(newObj[k], oldObj[k])
} else if (oldObj[k] instanceof Object) {
newObj[k] = {}
deepCopy(newObj[k], oldObj[k])
} else {
newObj[k] = oldObj[k]
}
}
}
const o = {}
deepCopy(o, obj)
// 2. JSON序列化方式
const o2 = JSON.parse(JSON.stringify(obj))
// 3. 使用lodash库
const o3 = _.cloneDeep(obj)
o.hobby[0] = '足球'
console.log(obj.hobby[0]) // 篮球 - 不受影响
异常处理
throw抛出异常
主动抛出错误信息,终止程序执行
function counter(x, y) {
if(!x || !y) {
throw new Error('参数不能为空!')
}
return x + y
}
counter() // 抛出错误:参数不能为空!
try…catch捕获异常
捕获并处理代码执行中的错误
function foo() {
try {
// 可能出错的代码
const p = document.querySelector('.p')
p.style.color = 'red'
} catch (error) {
// 错误处理
console.log('错误信息:', error.message)
return // 终止执行
} finally {
console.log('无论是否出错都会执行')
}
console.log('没出错时执行')
}
foo()
debugger调试
在代码中设置断点进行调试
function calculate() {
const a = 10
debugger // 执行到此会暂停
const b = 20
return a + b
}
calculate()
this处理
普通函数this
this指向调用该函数的对象
function sayHi() {
console.log(this)
}
const user = {
name: '小明',
sayHi: sayHi
}
sayHi() // window - 无明确调用者
user.sayHi() // user对象 - 调用者是user
箭头函数this
继承外层作用域的this,自身不绑定this
const user = {
name: '小明',
sayHi: function() {
// 普通函数 - this指向调用者
console.log('普通函数:', this.name)
const arrowFn = () => {
// 箭头函数 - 继承外层this
console.log('箭头函数:', this.name)
}
arrowFn()
}
}
user.sayHi()
// 普通函数: 小明
// 箭头函数: 小明
改变this指向(call,apply,bind)
动态控制函数中this的值
function introduce(age, hobby) {
console.log(`我是${this.name}, ${age}岁, 喜欢${hobby}`)
}
const user = {name: '小明'}
const student = {name: '小红'}
// 1. call - 立即执行,参数逐个传递
introduce.call(user, 18, '篮球')
// 2. apply - 立即执行,参数数组传递
introduce.apply(student, [16, '唱歌'])
// 3. bind - 返回新函数,不立即执行
const boundFn = introduce.bind(user, 20, '游泳')
boundFn()
性能优化
防抖(debounce)
连续触发时只执行最后一次
function debounce(fn, delay) {
let timer
return function() {
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(this, arguments)
}, delay)
}
}
// 使用示例
const searchInput = document.querySelector('.search')
searchInput.addEventListener('input', debounce(function(e) {
console.log('搜索:', e.target.value)
}, 500))
节流(throttle)
连续触发时按固定频率执行
function throttle(fn, delay) {
let flag = true
return function() {
if (!flag) return
flag = false
setTimeout(() => {
fn.apply(this, arguments)
flag = true
}, delay)
}
}
// 使用示例
window.addEventListener('scroll', throttle(function() {
console.log('滚动位置:', window.scrollY)
}, 200))
视频播放进度保存(节流应用)
使用节流技术优化视频播放进度的实时保存,避免频繁操作
// 获取视频元素
const video = document.querySelector('video')
// 使用节流保存播放进度 - 每秒保存一次
video.ontimeupdate = _.throttle(() => {
// 获取当前视频时间
console.log('当前播放时间:', video.currentTime)
// 把当前时间存储到本地存储
localStorage.setItem('currentTime', video.currentTime)
}, 1000)
// 页面加载时恢复播放进度
video.onloadeddata = () => {
// 从本地存储获取记录的时间,如果没有则从0开始
const savedTime = localStorage.getItem('currentTime')
video.currentTime = savedTime ? parseFloat(savedTime) : 0
console.log('恢复播放位置:', video.currentTime)
}
1046

被折叠的 条评论
为什么被折叠?



