css、js

81 阅读21分钟

1、BFC

  1. BFC称呼块级格式化上下文
  2. BFC的原理:就是一个独立的盒子,保证里面的子元素不会影响到外面的元素
  3. 如何触发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的属性,效果如下:

image.png 添加了以后:

image.png

2、 清楚浮动

  1. 使用BFC就是变相的清除浮动

  2. 在最后一个浮动元素的后面加一个子元素,添加样式: clear:both

  3. 给父盒子添加伪元素: ` div:after { content:''; display:block; clear:both }

    `

3、poabsolut

  1. static: 默认值,没有定位
  2. fixed: 固定定位,相对于浏览器窗口定位
  3. relative: 相对自身定位,不脱离文档流
  4. 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;
      }
}

image.png

如果.c中 用margin代码padding,是下面这种效果

image.png

5、css sprite 精灵图

将许多图片集合在一张大的图片上 优点: 减少http请求次数,提高性能 缺点:维护比较麻烦,比如进行图片位置的修改或者宽高发生变化

6、浏览器解析

image.png

7、延迟加载js的两种方法

defer 和 async

<script defer src='./a.js'></script> 
<script async src='./b.js'></script> 

  1. defer: 等html完全加载完,才会执行js代码,顺序执行js代码

  2. async: 和html同步加载,不会顺序执行js代码

8、sort排序

  1. 返回一个数组,没有参数的情况下, 默认是根据字符串unicode码进行排序

  2. 0--1-2...-a-b-... unicode码依次变大

image.png 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字体大小

  1. chrome默认字体是16;每个浏览器的默认字体是不一样的
  2. 设置12px 可以使用缩放: transform:scale(0.75)

12、rem、em区别

  1. rem和em都是相对单位
  2. 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系统中元素被触摸时产生的半透明灰色遮罩

  1. 比如页面上的 button input textarea
  2. 解决方法: button,input,textarea { -webkit-tap-hight-color: raba(0,0,0,0) }

14、webkit 修改表单的placeholder的颜色

input::-webkit-input-placeholder {
    color: red
}

15、自适应

  1. 本质:
  • 明白rem是相对于谁发生变化,rem是相对于根元素发生变化 即html标签
  • 当设置好根元素font-size大小后,就得到1rem的值,即1rem等于根元素的大小。
  • 如果html的根元素是固定的,则虽然文档的每一个标签的样式都设置了以rem为单位,也不会出现自适应
  • 如果想要自适应,则必须根元素的字体大小也要根据浏览器宽度的变化而变化
  • 想要动态的设置字体大小,则需要用到onresize事件,监听窗口宽度的变化
  1. 方案
    • 淘宝无限适配+ rem
    • flex + rem
    • 媒体查询 + rem
     // only: 排除不支持媒体查询的浏览器, 可以不加
    @media only screen and (min-width640px) {  
        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');

执行结果:

  1. script start
  2. async1 start
  3. async2
  4. promise1
  5. script end
  6. asnyc1 end
  7. promise2
  8. setTimeOut

promise、async/await

  1. 首先,new Promise是同步的任务,会被放到主进程中去立即执行。而.then()函数是异步任务会放到异步队列中去,那什么时候放到异步队列中去呢?当你的promise状态结束的时候,就会立即放进异步队列中去了。
  2. 带async关键字的函数会返回一个promise对象,如果里面没有await,执行起来等同于普通函数;如果没有await,async函数并没有很厉害是不是
  3. await 关键字要在 async 关键字函数的内部,await 写在外面会报错;await如同他的语意,就是在等待,等待右侧的表达式完成。此时的await会让出线程,阻塞async内后续的代码,先去执行async外的代码。等外面的同步代码执行完毕,才会执行里面的后续代码。就算await的不是promise对象,是一个同步函数,也会等这样操作

参考 : blog.csdn.net/yun_hou/art…

20、for 、for ... in 、for ... of、 forEach

  1. for 、for ... in 、for ... of 可以用return continue break;break是跳出整个循环
  2. 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。

而声明式函数在预编译阶段将会整体提升。

而在编译过程中,提升也是有顺序的:参数 > 函数 > 变量

因此函数与变量的预编译遵循以下规则

  1. 函数声明置顶;
  2. 变量声明置顶;
  3. 遇到同名时,变量声明比函数声明更优先(置顶);
  4. 变量不会重复声明;
  5. 直接变量声明时赋值,在预编译解析时,会拆成声明和赋值2个部分,声明会置顶,而赋值将保留在原来的位置;
  6. 声明的提升只会提升到当前作用域下的顶层,而不会提升到作用域之外。
  7. 预编译过程中形成的作用域链的查找顺序是由里向外,JS执行顺序是自上往下的。
  8. 当函数被声明在判断语句内部时,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/…

  1. Promise有三种状态: pending(等待中)、fullfied(成功)、rejected(失败)
  2. 从pending转换到 fullfied或者rejected都是不可逆的
  3. Promise有以下方法
  • reject、resolve
  • all、race、allSettled
  1. all,race、allSettled方法接受一个参数 ,该参数是数组,也可以不是数组,但必须是具有iterator接口的对象,数组中的每一个值是Promise实例

  2. 下面题目打印结果:-----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
 
 
 

原因:

  1. 第一步:Promise传递的函数是同步执行的,执行过程中遇到setTimeout,该任务是宏任务,而promise.then是微任务。所以先执行promise.then方法。
  2. 第二步:执行then方法, 发现this.state并没有改变仍然是pending,所以打印了 123,并执行typeof onRejected === 'function' && this.onRejected.push(onRejected)。
  3. 第三步:微任务执行后,开始执行宏任务,此时调用了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 与 === 的区别

image.png

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

原型,原型链

image.png

  • 每一个构造函数都有一个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

  1. set允许存任何类型的唯一值,即值是唯一的,key和valu值相等
  2. set的值是无序的,无法通过索引访问
  3. 通过add方法添加,delete删除,has查看,.values(),.keys()
  4. 可以通过size属性获取set中的数量
  5. set是迭代器,可以用.forEach,for ...of,

2、 Map

  1. map值的索引可以是任何类型,也是唯一的
  2. map的键值是有序的
  3. set设置键值,delete删除键值对,has查看是否有该键,get获取对应键的值
  4. 通过size获取键值对的数量
  5. map是迭代器,可以用.forEach,.for ... of

3、WeakSet(弱引用集合)

  1. weakSet是存储对象的弱引用,而不是实际对象的引用
  2. weakSet值是无序的,所以无法通过索引获取值
  3. 由于是弱引用,当没有其他引用指向该对象时,垃圾回收机制自动会删除WebSet的对象
  4. 没有提供遍历的方法

4、WeakMap ### (弱引用映射)

  1. weakmap是键值对的集合,与map不同的是键值必须是对象
  2. weakmap的键值对是无序的
  3. 由于是弱引用,当没有其他引用指向该对象时,垃圾回收机制自动会删除WeakMap的对象
  4. WeakMap没有提供遍历方法

总结

  1. set,map都是集合,set,weakSet是值的集合,值是唯一的,map,weakmap是键值对的集合,键是唯一的,但是weakMap的键必须是对象
  2. map,set都是迭代器,能够被遍历,weakMap没有。只有map是有序的,其他三个都不是
  3. 由于weakSet,weakMap是弱引用,所以如果没有其他对象指向该对象的键的时候 ,他们的键值就会被垃圾机制回收

url改变页面不刷新的方法

  1. 参考链接:blog.csdn.net/weixin_4566…
  2. 通过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函数的第一个参数