值类型的赋值就是深拷贝:变量赋值时,拷贝的不是内存地址,而是将数据完整的在内存中复制了一份
const a = 10
const b = a
console.log(b);
引用类型(null 对象 数组)的赋值操作都不是深拷贝:拷贝的是内存地址,最终两个变量指向的是同一个地址
const a = {
name: 'jj',
age: 20
}
const b = a
b.age = 18
console.log(a.age); // 18
const p1 = {
name: 'jj',
age: 20
}
const deepClone = (obj) => {
let result = {}
for (let i in obj) {
// console.log(obj[i]);
result[i] = obj[i]
}
return result
}
const p2 = deepClone(p1)
p2.age = 12
console.log(p1, p2);
const p1 = {
name: 'ss',
age: 20,
address: {
province: '河北省',
city: '保定市',
area: '莲池区',
info: '河北软件职业技术学院'
}
}
const deepClone = (obj) => {
let result = {}
for (let i in obj) {
result[i] = obj[i]
}
return result
}
const p2 = deepClone(p1)
p2.age = 2
p2.address.city = '衡水'
console.log(p1, p2);
输出结果
对于name和age属性手机深拷贝
对于address属性不是深拷贝
深拷贝的核心是我没找到对象或数值中的值类型(age 和 name属性的值),然后进行赋值操作,就是深拷贝,而address属性是一个对象自然采用内存地址拷贝
解决方案:加入递归,一致递归到值类型为止
在deepClone函数中的循环改写为:
result[i]=deepclone(obj[i])
const deepClone = (obj) => {
// 如果不是对象或者等于null的时候无需进行深拷贝
if (typeof obj !== 'object' || obj == null) {
return obj
}
//声明变量,用于存储拷贝的数据
let result
if (obj instanceof Array) {
result = []
} else {
result = {}
}
for (let i in obj) {
// console.log(deepClone(obj[i]));
result[i] = deepClone(obj[i])
}
return result
}
const p1 = {
name: 'ss',
age: 20,
address: {
province: '河北省',
city: '保定市',
area: '莲池区',
info: '河北软件职业技术学院'
}
}
const p2 = deepClone(p1)
p2.age = 2
p2.address.city = '衡水'
console.log(p1, p2);
class People {
constructor(name) {
this.name = name
}
eat() {
console.log('eat');
}
}
class Student extends People {
constructor(name, number) {
super(name)
this.number = number
}
sayHi() {
console.log(`姓名:${this.name},学号:${this.number}`);
}
}
const xialuo = new Student('夏洛特', '110')
console.log(xialuo.__proto__ === Student.prototype);//true
console.log(xialuo.__proto__);//对象的对象原型,也是隐式原型
console.log(Student.prototype);//类的原型对象,也是显示原型
原型关系
const xialuo = new Student('夏洛特', '110')
console.log(xialuo.name);//夏洛特
xialuo.sayHi()
xialuo.eat()
hasownProperty 方法判断某个属性或者方法是否在当前隐式原型中
在 JavaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接(proto)。这个原型对象又有自己的原型,直到某个对象的原型为 null 为止(也就是不再有原型指向)。这种一级一级的链结构就称为原型链(prototype chain)。 当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止;到查找到达原型链的顶部(Object.prototype),仍然没有找到指定的属性,就会返回 undefined。
所有 class 都是从 Object 继承的,也就是说 Object 是其他类的原型
script标签的开始和结束标记之间,叫全局作用域
函数内部的是函数作用域
花括号之间的是块级作用域
自由变量:在当前作用域中没有,在上级找到的变量就是自由变量如果全局没有找到就回报 is not defiend
自由变量的查找就是在函数定义的地方,向上级作用域查找
在函数调用完之后作用域和变量都被清除
闭包在函数调用之后不会清除作用域和变量,只有调用内部函数的时候才会清除
闭包是一种现象 闭包可以访问其他作用域的变量 有两种情况:1.函数作为返回值 2.函数作为参数
this 是在函数执行时(调用时)确定的,而不是定义时,
在全局作用域中this是指 window
作为普通函数调用this值是window
apply、bind 和 call 方法可以改变普通函数中 this 的指向,传递的第一个参数是什么,则函数中的 this 就是什么
function fn () {
console.log(this);
}
fn.call({ x: 100 }) // {x:100}
const fn_res = fn.bind({ x: 100 })
fn_res() // {x:100}
定义在对象里面的函数this指向的是这个对象
const person = {
name: 'onlifes',
sayHi () {
console.log(this);
},
wait () {
setTimeout(function () {
console.log(this);
}, 0)
}
}
person.sayHi()
person.wait()
结果
{name: "onlifes", sayHi: ƒ, wait: ƒ}
Window
原因:因为 wait 方法中使用了 setTimeOut 函数,其中的函数永远被当作一个普通函数,所以 this=window
箭头函数没有自己的this指向,箭头函数的this指向是父级作用域的this指向决定的
class类中方法的this指向的是声明的对象实例
JS 是单线程语言,只能同时做一件事,这时候就需要异步解决单线程的问题 异步是解决JS语言单线程瓶颈的一个解决方案
异步是基于 JS 单线程特点而产生的
1.异步不会阻塞代码执行
同步会阻塞代码执行
2.同步就相当于是 当客户端发送请求给服务端,在等待服务端响应的请求时,客户端不做其他的事情。当服务端做完了才返回到客户端。这样的话客户端需要一直等待。用户使用起来会有不友好。
异步就是,当客户端发送给服务端请求时,在等待服务端响应的时候,客户端可以做其他的事情,这样节约了时间,提高了效率。
存在就有其道理 异步虽然好 但是有些问题是要用同步用来解决,比如有些东西我们需要的是拿到返回的数据在进行操作的。这些是异步所无法解决的。
使用Promise方法
Document
用 await方法改造
Document
dom的本质是什么
我们都知道,DOM 是一棵树。梨树还是桃树?
首先要明白,通过 VS Code 编辑的 HTML 源代码,最终会被浏览器拿到 浏览器拿到源代码经过解析,构建成DOM树,浏览器可以识别并通过JS可以操作的这个DOM树 所以,要将源代码与 DOM 区别开来
// property 方式:
element.style.color='red'
element.className='blue'
// atribute 方式
element.setAttribute('class','blue')
element.getAttribute('href')
结论:尽量使用 property 的方式,万不得已,再使用 attribute 方式
新增节点
document.createElement('p')
插入节点
父节点.appendChild('p')
获取子元素列表
父元素.childNodes
获取父元素列表
子元素.parentNode
删除子元素
父元素.removeChild(子元素)
用代码片段进行一次性的操作
body
//js
const listNode = document.getElementById("list")
// 创建一个文档片段,此时还没有插入到DOM树中
const frag = document.createDocumentFragment()
// 执行插入
for (let x = 0; x < 10; x++) {
const li = document.createElement('li')
li.innerHTML = "list item " + x
frag.appendChild(li)
}
// 完成之后,再插入到DOM树中
listNode.appendChild(frag)
BOM:浏览器对象模型
1.如何识别浏览器类型
用Navigator对象的
属性 | 说明 |
---|---|
appCodeName | 返回浏览器的代码名 |
appName | 返回浏览器的名称 |
appVersion | 返回浏览器的平台和版本信息 |
cookieEnabled | 返回指明浏览器中是否启用 cookie 的布尔值 |
platform | 返回运行浏览器的操作系统平台 |
userAgent | 返回由客户机发送服务器的user-agent 头部的值 |
分析拆解 URI 各个部分
Screen 对象包含有关客户端显示屏幕的信息。
属性 | 描述 |
---|---|
availHeight | 返回显示屏幕的高度 (除 Windows 任务栏之外)。 |
availWidth | 返回显示屏幕的宽度 (除 Windows 任务栏之外)。 |
bufferDepth | 设置或返回调色板的比特深度。 |
colorDepth | 返回目标设备或缓冲器上的调色板的比特深度。 |
deviceXDPI | 返回显示屏幕的每英寸水平点数。 |
deviceYDPI | 返回显示屏幕的每英寸垂直点数。 |
fontSmoothingEnabled | 返回用户是否在显示控制面板中启用了字体平滑。 |
height | 返回显示屏幕的高度。 |
logicalXDPI | 返回显示屏幕每英寸的水平方向的常规点数。 |
logicalYDPI | 返回显示屏幕每英寸的垂直方向的常规点数。 |
pixelDepth | 返回显示屏幕的颜色分辨率(比特每像素)。 |
updateInterval | 设置或返回屏幕的刷新率。 |
width | 返回显示器屏幕的宽度。 |
History 对象包含用户(在浏览器窗口中)访问过的 URL
History 对象属性
属性 | 描述 |
---|---|
length | 返回浏览器历史列表中的 URL 数量。 |
History 对象方法
方法 | 描述 |
---|---|
back() | 加载 history 列表中的前一个 URL。 |
forward() | 加载 history 列表中的下一个 URL。 |
go() | 加载 history 列表中的某个具体页面。 |
1.嵌入式
2.事件监听
3.直接绑定
on:如果事件相同就会覆盖前一个但是有时我们又需要执行多个相同的事件 on就完成不了我们想要的效果
addEventListener:可以多次绑定同一个事件并且不会覆盖上一个事件。
**事件代理:**将事件代理到父容器上,这样修改子元素,父容器都会监听到,从而执行对应的操作,若是将事件绑定到子元素上,假设新增了子元素,又得重新给子元素绑定事件,是非常繁琐的。
元素
事件捕获
当你使用事件捕获时,父级元素先触发,子级元素后触发,即div先触发,p后触发。
事件冒泡
当你使用事件冒泡时,子级元素先触发,父级元素后触发,即p先触发,div后触发。
组织冒泡的方法
第一种:event.stopPropagation();
第二种:return false;
第三种:event.preventDefault();
是一个打包工具,模块化减少http请求,使新标准能够兼容旧版本
随便找个终端
ssh root@IP地址
回车后输入密码,就可以登录了
命令:mkdir 目录
mkdir aaa 在当前目录下创建一个名为aaa的目录
mkdir /usr/aaa 在指定目录下创建一个名为aaa的目录
命令:rm [-rf] 目录
删除文件:
rm 文件 删除当前目录下的文件
rm -f 文件 删除当前目录的的文件(不询问)
删除目录:
rm -r aaa 递归删除当前目录下的aaa目录
rm -rf aaa 递归删除当前目录下的aaa目录(不询问)
全部删除:
rm -rf * 将当前目录下的所有目录和文件全部删除
rm -rf /* 【自杀命令!慎用!慎用!慎用!】将根目录下的所有文件全部删除
注意:rm不仅可以删除目录,也可以删除其他文件或压缩包,为了方便大家的记忆,无论删除任何目录或文件,都直接使用 rm -rf 目录/文件/压缩包
一、重命名目录
命令:mv 当前目录 新目录
例如:mv aaa bbb 将目录aaa改为bbb
注意:mv的语法不仅可以对目录进行重命名而且也可以对各种文件,压缩包等进行 重命名的操作
二、剪切目录
命令:mv 目录名称 目录的新位置
示例:将/usr/tmp目录下的aaa目录剪切到 /usr目录下面 mv /usr/tmp/aaa /usr
注意:mv语法不仅可以对目录进行剪切操作,对文件和压缩包等都可执行剪切操作
三、拷贝目录
命令:cp -r 目录名称 目录拷贝的目标位置 -r代表递归
示例:将/usr/tmp目录下的aaa目录复制到 /usr目录下面 cp /usr/tmp/aaa /usr
注意:cp命令不仅可以拷贝目录还可以拷贝文件,压缩包等,拷贝文件和压缩包时不 用写-r递归
命令:find 目录 参数 文件名称
示例:find /usr/tmp -name ‘a*’ 查找/usr/tmp目录下的所有以a开头的目录或文件
2.移动文件夹(目录)以及文件夹下的内容
如果要移动文件夹的内容以及文件夹本身:mv <目录地址1 > <目录地址2/>,即文件夹目录地址后面加上/即可!
原则
方法
提升加载速度:
提升渲染速度
对DOM查询进行缓存
拼单DOM操作,合并到一起插入DOM结构 片段:
document.createDocumentFragment()
节流throttle和防抖debounce
防抖(debounce):触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算
节流(thorttle):高频事件触发,但在n秒内只会执行一次,所以节流会西施函数的执行频率
区别:防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。