1、BFC
- BFC称呼块级格式化上下文
- BFC的原理:就是一个独立的盒子,保证里面的子元素不会影响到外面的元素
- 如何触发BFC:
-
float的值非none
-
position: absolute或者fixed
-
overflow的值非visible
-
display的值为 inline-block,inline-flex,flex,table-cell等
-
根元素
-
<div className={style.box}>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
<h1>
box,我是你兄弟
</h1>
.box {
border: 5px solid red;
display: flex;
ul {
li {
float: left;
width: 100px;
height: 100px;
border: 2px solid blue;
}
}
}
如果不添加触发BFC的属性,效果如下:
添加了以后:
2、 清楚浮动
-
使用BFC就是变相的清除浮动
-
在最后一个浮动元素的后面加一个子元素,添加样式: clear:both
-
给父盒子添加伪元素: ` div:after { content:''; display:block; clear:both }
`
3、poabsolut
- static: 默认值,没有定位
- fixed: 固定定位,相对于浏览器窗口定位
- relative: 相对自身定位,不脱离文档流
- absolute: 相对于第一个具有 relative定位的父盒子
4.双飞翼
即左右固定,中间自适应,且中间先加载
<div className={style.container}>
<div className={style.c}>中</div>
<div className={style.l}>左</div>
<div className={style.r}>右</div>
</div>
.container {
margin-top: 100px;
>div {
float: left;
// 三个盒子:都设置浮动
}
.c {
width: 100%;
height: 100px;
background-color: pink;
padding: 0 200px
// margin: 0 200px; 不能用margin代替padding,如下图所示
}
.l,
.r {
width: 200px;
height: 100px;
}
.l{
background-color: red;
margin-left: -100%;
// 盒子是200px,所以只有当margin-left:200px,才会跑到第二行,我们才能在页面上看到,移动页面的百分之百,正好跑到第一行的第一个位置
}
.r {
background-color: blue;
margin-left: -200px;
}
}
如果.c中 用margin代码padding,是下面这种效果
5、css sprite 精灵图
将许多图片集合在一张大的图片上 优点: 减少http请求次数,提高性能 缺点:维护比较麻烦,比如进行图片位置的修改或者宽高发生变化
6、浏览器解析
7、延迟加载js的两种方法
defer 和 async
<script defer src='./a.js'></script>
<script async src='./b.js'></script>
-
defer: 等html完全加载完,才会执行js代码,顺序执行js代码
-
async: 和html同步加载,不会顺序执行js代码
8、sort排序
-
返回一个数组,没有参数的情况下, 默认是根据字符串unicode码进行排序
-
0--1-2...-a-b-... unicode码依次变大
3. 上图调用sort结果是 1,11,12,21,23,34,45,a,ab,b,bc;两个数相比,从左到右,如果第一位的数相同,那就继续比较第二位
4. .sort(()=> a-b) 从小到大排序;sort(()=>b-a) 从大到小排序;也可以自定义属性进行排序
9、 css : 一个:和两个:区别,前者代表伪类,后者代表伪元素
10、如何管理ios键盘首字母大写
<input type="text" autocapitalize="off" />
11、怎么样chrome支持12px字体大小
- chrome默认字体是16;每个浏览器的默认字体是不一样的
- 设置12px 可以使用缩放: transform:scale(0.75)
12、rem、em区别
- rem和em都是相对单位
- rem相对html根元素,em是相对于父元素
html {
font-size: 16px;
}
h1 {
font-size: 2rem; /* h1 element's font size will be 32px */
}
p {
font-size: 1.5rem; /* p element's font size will be 24px */
}
13、怎么去掉ios系统中元素被触摸时产生的半透明灰色遮罩
- 比如页面上的 button input textarea
- 解决方法: button,input,textarea { -webkit-tap-hight-color: raba(0,0,0,0) }
14、webkit 修改表单的placeholder的颜色
input::-webkit-input-placeholder {
color: red
}
15、自适应
- 本质:
- 明白rem是相对于谁发生变化,rem是相对于根元素发生变化 即html标签
- 当设置好根元素font-size大小后,就得到1rem的值,即1rem等于根元素的大小。
- 如果html的根元素是固定的,则虽然文档的每一个标签的样式都设置了以rem为单位,也不会出现自适应
- 如果想要自适应,则必须根元素的字体大小也要根据浏览器宽度的变化而变化
- 想要动态的设置字体大小,则需要用到onresize事件,监听窗口宽度的变化
- 方案
- 淘宝无限适配+ rem
- flex + rem
- 媒体查询 + rem
// only: 排除不支持媒体查询的浏览器, 可以不加 @media only screen and (min-width: 640px) { html{ font-size: 100px }
} ```
16、响应式: 在不同的宽度下和设备 样式调整
17、setTimeout、Promise、Async/Await (此题必看)
async function async1() {
console.log('async1 start');
await async2();
console.log('asnyc1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(() => {
console.log('setTimeOut');
}, 0);
async1();
new Promise(function (reslove) {
console.log('promise1');
reslove();
}).then(function () {
console.log('promise2');
})
console.log('script end');
执行结果:
- script start
- async1 start
- async2
- promise1
- script end
- asnyc1 end
- promise2
- setTimeOut
promise、async/await
- 首先,new Promise是同步的任务,会被放到主进程中去立即执行。而.then()函数是异步任务会放到异步队列中去,那什么时候放到异步队列中去呢?当你的promise状态结束的时候,就会立即放进异步队列中去了。
- 带async关键字的函数会返回一个promise对象,如果里面没有await,执行起来等同于普通函数;如果没有await,async函数并没有很厉害是不是
- await 关键字要在 async 关键字函数的内部,await 写在外面会报错;await如同他的语意,就是在等待,等待右侧的表达式完成。此时的await会让出线程,阻塞async内后续的代码,先去执行async外的代码。等外面的同步代码执行完毕,才会执行里面的后续代码。就算await的不是promise对象,是一个同步函数,也会等这样操作
参考 : blog.csdn.net/yun_hou/art…
20、for 、for ... in 、for ... of、 forEach
- for 、for ... in 、for ... of 可以用return continue break;break是跳出整个循环
- forEach 可以用return、throw配合try catch使用,try catch 包裹住这个forEach循环,可以跳出整个循环
21、
for(var i = 0; i<10; i++){
setTimeout(() => {
console.log(i);
}, 0);
}
// 输出10个10
问题:为什么输出的是10个10? ** 解题思路:js的代码虽然是由上至下,但是遵循自己的运行机制。
**在for循环中,由于定时器是延时任务,会等到主线程的for循环执行完成后执行,而for循环执行完是i为10 的时候,所以这时候打印出来的是10 个 10。
解决方法:
// 三种方式输出的都是0-9
// 方式一 (把var改成let即可)
for(let i = 0; i<10; i++){
setTimeout(() => {
console.log(i);
}, 0);
}
// 方式二
for(var i = 0; i<10; i++){
(function (j){
setTimeout(() => {
console.log(j);
}, 0);
})(i)
}
// 方式三 (就是把匿名函数包裹的括号变成了~,和方式二是一样的)
for(var i = 0; i<10; i++){
~function(j){
setTimeout(() => {
console.log(j);
}, 0);
}(i)
}
22、JS函数名与变量名重名的问题
函数有块级作用域,和let const 相同 都有作用域
由于JavaScript的预编译会导致变量声明提升,声明式函数整体提升,因此当函数名与变量名重名的时候将会产生问题。
变量以及变量表达式(包括函数的表达式声明)在预编译阶段都只是声明提升,而没有赋值,值都为undefined。
而声明式函数在预编译阶段将会整体提升。
而在编译过程中,提升也是有顺序的:参数 > 函数 > 变量
因此函数与变量的预编译遵循以下规则:
- 函数声明置顶;
- 变量声明置顶;
- 遇到同名时,变量声明比函数声明更优先(置顶);
- 变量不会重复声明;
- 直接变量声明时赋值,在预编译解析时,会拆成声明和赋值2个部分,声明会置顶,而赋值将保留在原来的位置;
- 声明的提升只会提升到当前作用域下的顶层,而不会提升到作用域之外。
- 预编译过程中形成的作用域链的查找顺序是由里向外,JS执行顺序是自上往下的。
- 当函数被声明在判断语句内部时,JS会将函数声明当成表达式(赋值声明),即不会提升
//声明式函数整体提升
var a = 10;
function fun(){
var b = 11;
}
//这相当于
function fun(){
var b;
b = 11;
}
var a;
a = 10;
1、第一题
由于函数声明是整体提升的,因此下面代码中,a函数声明在前,而变量a赋值在后,因此a是一个变量,而不是一个函数了,a执行出错
var a = 10;
function a(){
console.log(a);
}
a();
//相当于
var a = function(){
console.log(a);
};
a = 10;
a(); //将报错,此时a是一个变量了
2、第二题
var a = 0;
if(true){
a = 1; //作用域中不存在a变量,因此会通过作用域链向外查找,找到全局中的a变量,并将1赋值
function a(){} //这是函数声明,相当于定义了一个函数a,并给其分配了内存
a = 21; //此时作用域中已经存在了a变量(a函数),因此该赋值将直接赋值给作用域中的a而不是全局的a
console.log('里面', a); //21,由于作用域中存在a变量了,因此直接打印作用域中的a
}
console.log('外面', a); //1,全局作用域中存在a变量,并赋值为1,因此打印1
//相当于
var a;
a = 0;
if(true){
function a(){} //由于函数是定义在判断语句中,所以没有声明提升
a = 1;
a = 21;
console.log('里面', a) //21
}
console.log('外面', a); //0
3、第三题
var a = 1;
function b(){
a = 10;
return;
function a(){
console.log(a);
}
}
b();
console.log(a);
//相当于
function b(){ //整体提升
function a(){ //整体提升
console.log(a);
}
a = 10;
return;
}
var a;
a = 1;
b(); //执行b函数后,内部函数a会声明,因此作用域内存在一个a变量(函数),a = 10会赋值给a函数,而不是全局中的a变量了
console.log(a); //1 打印的是全局的a变量,内部的a变量无法获取到
4、 JS延迟加载的⽅式有哪些?
JS的延迟加载有助与提⾼⻚⾯的加载速度。
defer和async、动态创建DOM⽅式(⽤得最多)、按需异步载⼊JS
defer:延迟脚本。⽴即下载,但延迟执⾏(延迟到整个⻚⾯都解析完毕后再运⾏),按照脚本出现的先 后顺序执⾏。
async:异步脚本。下载完⽴即执⾏,但不保证按照脚本出现的先后顺序执⾏。
zhuanlan.zhihu.com/p/637269351
5、 转换题
const data =[
{ value: '吴中区', parent: '1.1', id: '1.1.1' },
{ value: '江苏', parent: null, id: '1' },
{ value: '苏州', parent: '1', id: '1.1' },
{ value: '杭州', parent: '2', id: '2.1' },
{ value: '浙江', parent: null, id: '2' },
{ value: '余杭区', parent: '2.1', id: '2.1.1' }
]
const transformData =[
{ value: '江苏', id: '1', children: [
{ value: '苏州', id: '1.1', children: [
{ value: '吴中区', id: '1.1.1' }
]}
]},
{ value: '浙江', id: '2', children: [
{ value: '杭州', id: '2.1', children: [
{ value: '余杭区', id: '2.1.1' }
]}
]}
]
const topArray = data.filter(item => item.parent === null)
const restArray = data.filter(item => item.parent !== null)
const result = []
const deepQuery = (topArray)=> {
topArray.forEach(top => {
const id = top.id
const res = restArray.filter(rest => rest.parent === id)
top.children = res
if(res.length) {
deepQuery(top.children)
}
})
}
deepQuery(topArray)
6、手写Promise 以及其对应的方法
一定要看写的很好:www.cnblogs.com/grow-up-up/…
- Promise有三种状态: pending(等待中)、fullfied(成功)、rejected(失败)
- 从pending转换到 fullfied或者rejected都是不可逆的
- Promise有以下方法
- reject、resolve
- all、race、allSettled
-
all,race、allSettled方法接受一个参数 ,该参数是数组,也可以不是数组,但必须是具有iterator接口的对象,数组中的每一个值是Promise实例
-
下面题目打印结果:-----reject',value
原因: promise状态是不可逆的,所以虽然被resolve包装了,但仍走的catch方法
const promise1 = new Promise((resolve,reject)=> {
reject(1)
})
Promise.resolve(promise1).catch((value)=>{
console.log('-----reject',value);
})
Promise.resolve(promise1).then((value)=>{
console.log('-----resolve',value);
})
6.手写一个Promise
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
// promise接受一个函数 有三种 状态 俩个回调
// 写一个构造函数接收一个参数 有三种状态,此外还有:成功结果 失败结果 成功回调 失败回调
// 构造函数的原型有一个.then 方法 接收俩个参数 判断状态 如果成功调用 成功函数 ;失败 调用失败函数 pending 就存起来
function Promise (executor) {
var _this = this
this.state = PENDING // 状态
this.value = undefined // 成功结果
this.reason = undefined; // 失败原因
this.onFulfilled = [];//成功的回调
this.onRejected = []; //失败的回调
function resolve (value) {
if (_this.state === PENDING) {
console.log('----value',value);
_this.state = FULFILLED
_this.value = value
// 等Promise异步任务执行后 获取更新后的所有值状态,然后再执行then回调方法
_this.onFulfilled.forEach(fn => fn(value))
}
}
function reject (reason) {
if (_this.state === PENDING) {
l
_this.state = REJECTED
_this.reason = reason
// 等Promise异步任务执行后 获取更新后的所有值状态,然后再执行then回调方法
_this.onRejected.forEach(fn => fn(reason))
}
}
try {
executor(resolve, reject)
} catch (e) {}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
if (this.state === FULFILLED) {
typeof onFulfilled === 'function' && onFulfilled(_this.value)
}
if (this.state === REJECTED) {
typeof onRejected === 'function' && onRejected(_this.reason)
}
if(this.state === PENDING){
console.log(123);
typeof onFulfilled === 'function' && this.onFulfilled.push(onFulfilled)
typeof onRejected === 'function' && this.onRejected.push(onRejected)
}
}
var p = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve(4)
}, 0)
})
p.then((res)=>{
console.log(res, 'res')
})
执行结果
123
----value,4
4,res
原因:
- 第一步:Promise传递的函数是同步执行的,执行过程中遇到setTimeout,该任务是宏任务,而promise.then是微任务。所以先执行promise.then方法。
- 第二步:执行then方法, 发现this.state并没有改变仍然是pending,所以打印了 123,并执行typeof onRejected === 'function' && this.onRejected.push(onRejected)。
- 第三步:微任务执行后,开始执行宏任务,此时调用了resolve方法,这时this.state 变成了'fulfilled‘,所以打印了 ----value,4,最后又执行了then中传递的第一个方法,打印了 4,res
7、跨标签⻚的通信 ⻚⾯上新增的时候新开⼀个标签⻚新增数据 新增完成之后 ⽤户要能看下原来标签的列表⻚看到结果(工作中遇到的问题)
参考答案:blog.csdn.net/AdminGuan/a…
1、localStorage或者sessionStorage 配合 window的storage事件
localStorage.setItem('shartData','分享的数据')
window.addEventListener('storage', function(event) {
判断是否是 shartData 发生变化
if(event.key === 'shareData'){
}
})
2、BroadCastChannel 配合postMessage,onmessage事件
在发消息的标签页:
/* 创建一个广播通道 */
const channelObj = new BroadcastChannel('televiseChannel');
// 发送消息
channelObj.postMessage('标签页111');
在接收消息的标签页中L:
/* 创建一个广播通道 */
const channelObj = new BroadcastChannel('televiseChannel');
// 监听消息事件
channelObj.onmessage = function(event) {
const newData = event.data;
console.log('收到的更新数据:', newData);
};
在发送消息的标签页中创建一个 Broadcast Channel,并指定一个唯一的通道名称(这里使用'televiseChannel')。通过 channelObj.postMessage() 方法发送消息到该通道。
在接收消息的标签页中,同样创建一个具有相同通道名称的 Broadcast Channel。然后通过为 channelObj.onmessage 赋值一个函数来监听消息事件。当接收到消息时,事件对象 event 中的 data 属性将包含发送的消息内容,我们可以在监听函数中获取并处理该消息。
8、Object.is 与 === 的区别
9、如何理解js异步
js是⼀⻔单线程的语⾔,这是因为它运⾏在浏览器的渲染主线程中,⽽渲染主线程只有⼀个。并且渲染主线程承担着很多的⼯作, 渲染⻚⾯ 执⾏js等,如果使⽤同步的⽅式就极有可能导致主线程阻塞,从⽽使消息队列中的其他任务⽆法执⾏。⼀⽅⾯会导致繁忙的主线程⽩⽩浪费时间,另⼀⽅⾯会导致⻚⾯⽆法及 时更新给⽤户造成卡死的现象。所以浏览器采⽤异步的⽅式避免。具体的做法是当某些任务发⽣时,⽐如计时器,⽹络、事件监听。主线程将任务先交给其他线程去处理,⾃身结束后立即执⾏任务队列的其他任务,当其他线程完成时间再将回调函数加⼊到消息队列中去,等待主线程的调度。再这种异步的模式下,保证浏览器不阻塞,保证单线程的流畅运⾏。
10、js的事件循环
事件循环又叫消息循环,是浏览器渲染主线程的工作方式 在浏览器中会开启一个不停的for循环,每次循环都是从任务队列中取出一个任务去执行,而其他线程只需要在合适的时机把任务添加到任务队列末尾。在过去将消息队列分为宏任务队列和微任务队列。但是现在这种已经⽆法满⾜复杂的浏览器环境了 现在变成了⼀种更加灵活的处理⽅式根据w3c官⽅的解释 每个任务有不同的类型, 同类型的任务必须在同⼀个队列,不同的任务可以属于不同的队列,不同的队列有不同的优先级,再⼀次事件循环中 由浏览器⾃⾏决定取哪⼀个任务的队列,但是浏览器必须有个微队列,微队列⾥的任务⼀定具有最⾼的优先级,优先调度执⾏。
11、js取消请求的集中方法
1、取消 XMLHttpRequest 请求
const xhr = new XMLHttpRequest()
xhr.open('get', '/sth', true)
xhr.send()
setTimeout(() => {
xhr.abort()
}, 3000)
2、取消 Fetch 请求
const controller = new AbortController()
fetch('/sth', {
signal: controller.signal
})
setTimeout(() => {
controller.abort()
}, 3000)
3、取消 aixos 请求
const controller = new AbortController()
axios.get('/sth', {
signal: controller.signal
})
setTimeout(() => {
controller.abort()
}, 3000)
注意:axios 之前用于取消请求的 CancelToken 方法已经被弃用,更多请见文档 axios;
[1,2,3].map(parseInt)
parseInt : 将参数(通常为字符串)强制转换为整数。
有两个参数,第二个参数可以省略,如果省略,默认是10进制
转换规则:依次将字符串中从左到右的数字部分转为整数,一旦转换失败,返回NaN。
- (1) 参数是字符串类型:
```
var a = parseInt(‘10’); //将字符串转成整数类型
console.log(a); // 10
var b = parrseInt(‘10true’); //将有效数字部分转为整数,提取开头数字部分
console.log(b); // 10
var c = parseInt(‘10true20’); //只将开头有效部分转为整数
console.log(c); //10
var d = parseInt(‘045zoo’); //开头部分转为整数,数字前面的0省略
console.log(d); //45
var f = parseInt(‘34.5’); //整数部分,小数点非数字部分,舍去
console.log(f); //34
var g = parseInt(‘a3’); //若不是以数字开头,转为NaN(Not a Number 不是数字)的特殊数值
console.log(g); //NaN
```
- (2) 参数是数字类型:
```
var a = parseInt(3.4); //依然转为数字,但是取整
console.log(a); //3
```
- (3)其它数据类型:只要开头不包含有效数字,结果都转为NaN
```
var a = parseInt(true);
console.log(a); //NaN
var b = parseInt(null);
console.log(b); //NaN
var c = parseInt(undefined);
console.log(c); //NaN
var d = parseInt([]);
console.log(d); //NaN
var e = parseInt({});
console.log(e); //NaN
```
接下来,我们看第二个参数的用法
第二个参数:表示进制,范围2-36(用来说明第一个参数的进制规则)
```
如果二进制,第一个参数 每个位的值范围是0-1
如果十进制,第一个参数 每个位的值范围是0-9
超出这个范围的: 提前前面的有效范围
var a = parseInt(‘99’,10); // 如果字符串为十进制内容,该参数可省略
console.log(a); // 99
var a = parseInt(‘1001’,2); // ‘1001’ 符合二进制规则, 转为十进制整数
console.log(a); // 9
var a = parseInt(‘1001’,10); // ‘1001’同样符合十进制, 转为十进制整数
console.log(a); // 1001
var b = parseInt(‘234’,2); //‘234’不符合二进制的规则
console.log(b); // NaN
var b = parseInt(‘abcde’,2); //‘abcde’不符合二进制的规则
console.log(b); // NaN
var c = parseInt(‘1022’,2); //‘10’部分属于二进制,但‘22’不是,将开头有效的部分提取并转成十进制
console.log(c); //2
```
了解这两个函数后,我们可以模拟一下运行情况
parseInt('1', 0) //radix 为 0 时,且 string 参数不以“0x”和“0”开头时,
按照 10 为基数处理。这个时候返回 1parseInt('2', 1) //基数为 1(1 进制)表示的数中,最大值小于 2,所以无法解析,返回 NaNparseInt('3', 2) //基数
为 2(2 进制)表示的数中,最大值小于 3,所以无法解析,返回 NaN
原型,原型链
- 每一个构造函数都有一个protoType属性, protoType属性是一个对象,该独享有一个constructor属性,这属性指向的就是该构造函数
- 通过构造函数实例化的对象,都有有一个隐式__proto__属性,这个属性和构造函数的原型对象地址是一个
- 而原型对象也是一个对象,所以它也有一个__proto__对象,该原型对象通过__proto__也指向它的原型对象
- 比如现在有Teacher对象,它继承Person,person 最终继承也是Object,所有对象最终都是继承Object。如果我们使用了tacher的一个方法,但是找不到,就会往它原型对象找,一直找到Object.proto,Object._proto_的原型独享就是null,这个查找过程就是原型链
- 如果需要判断该属性是不是自身定义的,可以通过hasOwenProperty,如果想获取对象的原型对象 可以通过getPrototypeof,如果想要设置原型对象,则通过setPrototypeType。
通过Object.defineProperty 监听一个值的改变
// 定义一个简单的对象
let myObject = {};
// 定义一个属性,初始值为0
let myValue = 0;
// 使用Object.defineProperty来定义属性
Object.defineProperty(myObject, 'value', {
get() {
return myValue;
},
set(newValue) {
console.log(`值从 ${myValue} 变为 ${newValue}`);
myValue = newValue;
}
});
// 设置值,触发setter,将会打印出变化的信息
myObject.value = 1; // 输出: 值从 0 变为 1
// 再次设置值,再次触发setter
myObject.value = 2; // 输出: 值从 1 变为 2
定义一个对象,该对象有一个value属性,get的时候返回的myValue,改变的时候 将新的值符给my Value,这样就能随时监听这个对象
介绍下 Set、Map、WeakSet 和 WeakMap 的区别?
1、set
- set允许存任何类型的唯一值,即值是唯一的,key和valu值相等
- set的值是无序的,无法通过索引访问
- 通过add方法添加,delete删除,has查看,.values(),.keys()
- 可以通过size属性获取set中的数量
- set是迭代器,可以用.forEach,for ...of,
2、 Map
- map值的索引可以是任何类型,也是唯一的
- map的键值是有序的
- set设置键值,delete删除键值对,has查看是否有该键,get获取对应键的值
- 通过size获取键值对的数量
- map是迭代器,可以用.forEach,.for ... of
3、WeakSet(弱引用集合)
- weakSet是存储对象的弱引用,而不是实际对象的引用
- weakSet值是无序的,所以无法通过索引获取值
- 由于是弱引用,当没有其他引用指向该对象时,垃圾回收机制自动会删除WebSet的对象
- 没有提供遍历的方法
4、WeakMap ### (弱引用映射)
- weakmap是键值对的集合,与map不同的是键值必须是对象
- weakmap的键值对是无序的
- 由于是弱引用,当没有其他引用指向该对象时,垃圾回收机制自动会删除WeakMap的对象
- WeakMap没有提供遍历方法
总结
- set,map都是集合,set,weakSet是值的集合,值是唯一的,map,weakmap是键值对的集合,键是唯一的,但是weakMap的键必须是对象
- map,set都是迭代器,能够被遍历,weakMap没有。只有map是有序的,其他三个都不是
- 由于weakSet,weakMap是弱引用,所以如果没有其他对象指向该对象的键的时候 ,他们的键值就会被垃圾机制回收
url改变页面不刷新的方法
- 参考链接:blog.csdn.net/weixin_4566…
- 通过hash或者history模式
this指向
this指向调用该函数的对象,与函数地址没有任何关系 this的值取决于函数如何被调用,而不是它如何被定义
1、普通函数
this取决于函数如何被调用
第一种: 函数的调用方式 obj.F(),则this指向obj
function getThis() {
return this;
}
const obj1 = { name: "obj1" };
const obj2 = { name: "obj2" };
obj1.getThis = getThis;
obj2.getThis = getThis;
console.log(obj1.getThis()); // { name: 'obj1', getThis: [Function: getThis] }
console.log(obj2.getThis()); // { name: 'obj2', getThis: [Function: getThis] }
第二种: 函数直接被调用;严格模式: this将是undefined ,非严格模式:this将是window对象
function getThis() {
return this;
}
function a () {
console.log('------a',this); //undefined
function b () {
console.log('------b',this); //undefined
}
b()
}
a()
// 仅用于演示——你不应该修改内置的原型对象
Number.prototype.getThis = getThis;
console.log(typeof (1).getThis()); // globalThis (全局对象)
console.log(getThis() === globalThis); // true
第三种: 以回调函数的方式被调用,非严格模式:this值为全局对象,严格模式:this值为undefined
2、箭头函数
1、this取决于外层函数的this;在全局代码中,无论是否是在严格模式下下,this值都是glabalThis;在其他函数内部,this指向的是外层函数的this
2、call、apply、bind 无法改变箭头函数this指向
3、构造函数
当一个函数被用作构造函数(使用new关键词)时,无论构造函数是在哪一个对象上被访问,其this都会被绑定到正在构造的新对象,除非构造函数返回另外一个非原始值。
function C() {
this.a = 37;
}
let o = new C();
console.log(o.a); // 37
function C2() {
this.a = 37;
return { a: 38 };
}
o = new C2();
console.log(o.a); // 38
4、apply、call、bind
1、apply、call、bind可以改变this指向 2、this的值就是apply、call、bind函数的第一个参数