首页 前端知识 【html、css、js三剑客踩坑点】(持续迭代)

【html、css、js三剑客踩坑点】(持续迭代)

2024-07-29 00:07:43 前端知识 前端哥 315 594 我要收藏

目录

  • html
  • css
    • 层叠上下文 z-index
  • js
    • js技巧
      • 深浅拷贝
        • 浅拷贝(拷贝的是地址,只能修改第1层)
          • 实战一下
          • 直接赋值和浅拷贝的区别?
          • 浅拷贝怎么理解?
        • 深拷贝
      • 异常处理
        • throw关键字
        • try...catch...
      • call、apply、bind
        • call(调用函数并可以传递参数)
        • apply(经常跟数组有关系)
        • ⭐️bind(不调用函数,还想改变this指向,就用bind)
          • 发送短信小案例(在不使用_that,箭头函数,全局变量的情况下,只用bind来实现功能)
      • 防抖和节流
        • 防抖函数
        • 节流函数
        • 小案例

html

css

层叠上下文 z-index

mdn官网对z-index层叠上下文的介绍

不设置z-index值,默认值为auto,啥也没有;
设置z-index值哪怕值为-1、0也会创建层叠上下文
例如:有3个子盒子,那这3个子盒子的z-index只在设置了层叠上下文的父盒子里面生效
在这里插入图片描述

js

js技巧

深浅拷贝

浅拷贝(拷贝的是地址,只能修改第1层)
实战一下

↓↓↓拷贝对象↓↓↓

const obj = {
	name: '张三',
	age: 18
};

// 1、展开运算符
const o = {
	...obj,
	age: 21
};
// 2、Object.assgin()
Object.assgin(o, obj);
o.age = 21;

↓↓↓拷贝数组↓↓↓

  1. 扩展运算符;
  2. slice()、map()等数组方法;
  3. forEach() + push()方法;
  4. 手动循环赋值。
直接赋值和浅拷贝的区别?
  • 直接赋值:只要是对象,都会互相影响,因为是直接拷贝对象栈里面的地址。
  • 浅拷贝:如果是一层对象,不互相影响,如果出现多层对象拷贝还会相互影响。
浅拷贝怎么理解?

拷贝对象之后,里面的属性值是简单数据类型直接拷贝值,如果是引用数据类型则拷贝的是地址

深拷贝
  1. 递归(函数内部自己调用自己;容易"栈溢出"错误(stack overflow),所以必须要加退出条件return);
// 1、普通拷贝没问题直接复制就行;2、如果遇到数组,再次调用递归函数;3、如果遇到对象,再次调用递归函数;4、先数组再对象。
function deepCopy(newObj, oldObj) {
    for (let key in oldObj) {
    	// 先写Array,在写Object。因为数组一定属于Object,Object不一定属于数组
        if (oldObj[key] instanceof Array) {
            newObj[key] = [];
            deepCopy(newObj[key], oldObj[key]);
        }
        else if (oldObj[key] instanceof Object) {
            newObj[key] = {};
            deepCopy(newObj[key], oldObj[key]);
        }
        else {
            newObj[key] = oldObj[key];
        }
    }
}

const obj1 = {
    name: '张三',
    age: 18,
    habit: ['王者荣耀', '吃鸡'],
    family: {
        baby: '小张三'
    },
    address: null,
    phone: undefined
}
const obj2 = {};
deepCopy(obj2, obj1);
// 这种也行,ai写的代码更简洁。总之代码初衷是可读性高,自己看哪种要好吧~
function deepCopy(newObj, oldObj) {
    for (let key in oldObj) {
        if (oldObj.hasOwnProperty(key)) {
            if (oldObj[key] && typeof oldObj[key] === 'object') {
                newObj[key] = oldObj[key].constructor === Array ? [] : {};
                deepCopy(newObj[key], oldObj[key]);
            } else {
                newObj[key] = oldObj[key];
            }
        }
    }
}
  1. lodash官网的cloneDeep方法;
    第三方JavaScript 实用工具库: lodash官网
    里面有_.cloneDeep 方法,直接按照文档引用就行。
  2. JSON.parse(JSON.stringify())
const obj2 = JSON.parse(JSON.stringify(obj1));

异常处理

throw关键字
  • 抛出异常时使用
  • 会终止程序
  • 经常和Error对象一起使用
throw '抛出错误';
throw new Error('抛出错误');
try…catch…
try {
    obj.name = '张三';
}
catch {
    throw new Error('try里面的代码不对,obj为undefined,找不到该name');
}
finally {
    console.log('不管try里面的代码对不对,都会走我这儿');
}

call、apply、bind

具体语法请去mdn官网查看

call(调用函数并可以传递参数)
const obj = {
    name: '张三'
}
function fn(x, y) {
    console.log(this);
    console.log(x + y);
}
fn(); // this指向window
fn.call(obj, 1, 2); // this指向obj
apply(经常跟数组有关系)

和call的第一个参数都是this指向,但是apply第二个参数传递必须得是数组

const obj = {
    name: '张三'
}
function fn(x, y) {
    console.log(this);
    console.log(x + y);
}
fn(); // this指向window
fn.call(obj, [1, 2]); // this指向obj
// 求数组最大值
console.log(Math.max.apply(null, arr));
⭐️bind(不调用函数,还想改变this指向,就用bind)
const obj = {
    name: '张三'
}
function fn(x, y) {
    console.log(this);
    console.log(x + y);
}
fn(); // this指向window
const fnBind = fn.bind(obj, 1, 2); // this指向obj
fnBind(); // bind会返回一个新的函数,参数跟apply一样

总结:
1、call和apply会调用函数,改变函数内部的this指向,只不过apply第二个参数传递必须得是数组
2、bind不会调用函数,可以改变函数内部this指向。call和bind参数一样,都是call/bind(thisArg, arg1, arg2, /* …, */ argN),只不过bind不修改原数组会return出一个新数组(我们就修改这个新数组里面的this指向咯)

发送短信小案例(在不使用_that,箭头函数,全局变量的情况下,只用bind来实现功能)
<button>发送短信</button>
document.querySelector('button').addEventListener('click', function() {
    this.disabled = true;
    setTimeout(function() {
        this.disabled = false;
    }.bind(this), 2000)
})

防抖和节流

防抖函数
function mydebounce(fn, t) {
    let timer;
    return function() {
        timer && clearTimeout(timer);
        timer = setTimeout(() => {
            fn();
        }, t);
    }
}
节流函数

注意事项:定时器里面不能清除定时器,因为定时器还在运作,可以手动赋空进行覆盖

function mythrottle(fn, t) {
    let timer;
    return function() {
        if (!timer) {
            timer = setTimeout(() => {
                fn();
                console.log(timer);
                timer = null;
                console.log(timer);
            }, t)
        }
    }
}
小案例
<button>点击</button>
let num = 0;
const btn = document.querySelector('button');
btn?.addEventListener('click', mydebounce(() => {
    btn.innerHTML = `${num++}`;
}, 500))
转载请注明出处或者链接地址:https://www.qianduange.cn//article/14462.html
标签
评论
发布的文章

Unity数据持久化之Json

2024-08-10 22:08:00

simdjson 高性能JSON解析C 库

2024-08-10 22:08:00

npm常用命令详解(一)

2024-08-10 22:08:34

大家推荐的文章
会员中心 联系我 留言建议 回顶部
复制成功!