前端面试题总结

题目:点击蓝色小标题即可跳转答案

【js部分】

跳到css 点我跳到vue 点我跳到程序题

1. js的运行机制:事件循环,宏任务微任务

!](https://img-blog.csdnimg.cn/35ea191dd3914966bb640a67d1a1a9c4.png)

js是单线程非阻塞的语言,只有一个调用栈。js的任务有同步任务和异步任务,异步任务需要耗费时间没有合适的机制会引起阻塞,所以优先执行同步任务,同步任务直接放入调用栈中开始执行。

遇到同步代码就放到调用栈中,遇到异步代码先交由webApi,等合适时机放到任务队列中,等调用栈中同步代码执行完毕被清空,开始事件循环机制执行异步代码,每次调用栈被清空时,都会去读取任务队列有没有任务,有就读取执行,一直循环读取-执行的操作,就形成了事件循环EventLoop

异步代码执行时优先执行微任务,后执行宏任务,微任务有setTimeout、ajax,宏任务有promise\async+await

事件循环开始时间调用栈中空了之后开启事件循环机制来管理任务队列中异步代码的执行。

事件循环:先清空调用栈中的同步代码,执行微任务队列中的微任务,尝试DOM渲染,触发事件循环反复询问回调队列中是否还有要执行的语句(轮询),有就push到调用栈执行。

定时器(setTomeout)是设置的那个毫秒数到了,才开始放入任务对列,而不是毫秒数到了就会执行。

2. js的原型和原型链

在这里插入图片描述

原型和原型链的概念是模拟传统面向对象语言中的类的概念,挂载在原型属性上的方法可以被所有实例化对象所共享,这样可以节省空间。原型链可以实现对象的继承。

原型:每一个构造函数也就是类,都有prototype属性,这个属性指向它的原型对象。
而每个实例化对象都有一个__proto__隐式原型属性,这个属性也指向它的构造函数的原型对象。Person.prototype = zs.__prpto__

原型链:原型链是通过__proto__连接起来的链条,每个对象都有自己的原型Object.prototype = null,最顶层的原型对象是null。当我们调用一个属性或方法时,会先在自身找,如果自身没有会去原型对象身上找,如果找不到会一直向上追溯到顶层,如果还找不到,则返回undefined。

hasOwnProperty():可以用来检查对象自身是否含有某个属性,返回值是布尔值,当属性不存在时不会向上查找对象原型链,hasOwnProperty是 JavaScript 中唯一一个处理属性但是不查找原型链的函数。

3. js的浅拷贝深拷贝

在这里插入图片描述

浅拷贝和深拷贝都是针对引用数据类型的,基本数据类型在内存中直接存在栈中,引用数据类型在内存中变量名和指针存在栈中,其他主体内容存在栈的指针指向的堆内存中。
浅拷贝:浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
深拷贝:深拷贝会另创造一个一模一样的对象,新对象会有新的内存空间,跟原对象不共享内存,修改新对象不会改到原对象。
深拷贝要通过递归来实现如果没有引用数据类型(如数组和Object)、undefined的情况下,还可以通过 JSON转换、Object.assign()、扩展运算符这些方法来实现深拷贝,这些共同的缺点是只能拷贝基本数据类型,不能拷贝引用数据类型。

 // 浅拷贝出现的前提是:引用类型的数据 
        // 浅拷贝:就是与原对象共用一套内存空间 --- 就是obj2指向与obj1一个内存空间
            const obj1 = {
                 a:1
            }
            const obj2 = obj1;
            obj2.a = 2;
            console.log(obj1,obj2);


        // 深拷贝:再开辟出一块内存空间来
        // 1.JSON转换方法----缺点:数据类型为function或数值为undefined情况下无法复制
             const obj1 = {
                 a: 1,
                 b: undefined,
                 arr: [1,2,4],
                 fun: () => {}
             }
             // 将引用类型,转为基本类型
             const obj2 = JSON.parse(JSON.stringify(obj1))  
             obj2.a = 2;
             obj2.arr[0] = 111;
             console.log(obj1,obj2);

        // 2.Object.assign()----缺点:只能深拷贝一级属性,二级以上属性(即数组中包含的元素)就是浅拷贝
             const obj1 = {
                 a: 1,
                 b: undefined,
                 arr: [1,2,4],
                 fun: () => {}
             }
             const obj2 = Object.assign({},obj1)  // 将引用类型,转为基本类型
             obj2.a = 2;
             obj2.arr[0] = 111;
             console.log(obj1,obj2);
        
        // 3.扩展运算符---缺点:只能深拷贝一级属性,二级以上属性(即数组中包含的元素)就是浅拷贝
             const obj1 = {
                 a: 1,
                 b: undefined,
                 arr: [1,2,4],
                 fun: () => {}
             }
             const obj2 = {...obj1}  
             obj2.a = 2;
             obj2.arr[0] = 111;
             console.log(obj1,obj2);

        // 4.递归 --- 可以完美解决深拷贝问题
            function CloneDeep(data){
                const newData = Array.isArray(data) ? [] : {}; // 初始化
                for(let key in data){
                    if(data[key] && typeof data[key] === "object"){ 
                    	// 如果是数组和对象类型
                        newData[key] = CloneDeep(data[key])
                    }else{ // 如果是基本数据类型
                        newData[key] = data[key]
                    }
                }
                return newData
            }

            const obj1 = {
                a: 1,
                b: undefined,
                arr: [1,2,4],
                fun: () => {}
            }

            const obj2 = CloneDeep(obj1) 
            obj2.a = 2;
            obj2.arr[0] = 111;
            console.log(obj1,obj2);

4. js闭包

闭包是函数内部的函数,是为了在外部读取外部函数内部的函数级作用域中的变量而存在的,闭包因为存在函数嵌套函数的关系,所以可以帮助保存for循环中的变量。但滥用闭包容易造成内存泄漏。因为js的垃圾回收机制检测不到,所以造成了内存泄漏。解决办法是给变量赋值为null。

5. js的垃圾回收机制

垃圾是没有被引用的对象或变量等,因为它占用内存空间,如果没有垃圾回收的话,会造成内存消耗,影响代码运行性能。
js的垃圾回收方式:标记清除 和 引用计数
标记清除:当变量进入执行环境时(函数中声明变量),就标记这个变量“进入环境” ,当变量离开环境时(函数执行结束),则删除"进入环境"标记,并将其标记为“离开环境”。当js检测到一个变量被标记取消标记又重新标记之后,就会收集起来,等待垃圾收集器处理后,这个变量将不再占有内存空间,使内存空间得到释放。
引用计数:当一个变量被赋值为引用类型时,就会使计数+1,当变量又取了其他数据时,计数-1。计数为0的就是需要被回收的垃圾。引用计数方法可能会导致循环引用,这时该机制检测到的计数一直是2,从而导致这个内存永远不会被垃圾回收检测到,从而造成了内存泄漏。

在这里插入图片描述

6. js的内存泄漏是什么?怎么防止内存泄漏

内存泄漏就是变量已使用,但未释放内存空间,一直占用着内存的情况。严重的话,无用的内存持续增加,会导致系统卡顿,甚至崩溃。

防止泄漏:不滥用闭包,定时器及时清除,减少全局变量等

7. 如何监听对象中一个属性的变化?

通过数据劫持
Object.defineProperty(对象,属性,{
	set: function() { }   // 设置属性
	get: function() { }  //  读取属性
})

8. js中继承的实现:

在这里插入图片描述

 // 原型链继承优化【es5】--- 寄生组合继承

        // 【Person类】----------------------------
        function Person(){
        	// 构造函数的属性和方法
            this.name = "people",
            this.say = function(){
                console.log("say");
            }
        }
        // 实例方法,也就是原型链上的
        Person.prototype.hello = function(){
            console.log("hello!!!");
        }

        // 【Student类】------------------------------
        function Student(){
            // 【 1. 继承实例属性和方法】****
            Person.call(this)// 拿到父类的属性和方法
        }

        // 【 2. 继承原型上的属性和方法】*****
        Student.prototype = Object.create(Person.prototype)
        // Student的构造函数
        Student.prototype.constructor = Student

        let s1 = new Student()
        let p1 = new Person()
        // 方法使用
        console.log(s1.name); // people
        s1.say(); // say
        s1.hello(); // hello!!!

        console.log(p1,"p1")
        console.log(s1,"s1");
   // ES6继承
        class Person{
            constructor(name){
                this.name = name;
            }
            say(){
                console.log("不同区域都有语言");
            }
        }

        class Country extends Person{
            // 父类中有构造函数,子类必须实现父类的构造函数
            constructor(name,lang){
            	// 构造函数中想继承,先super塑形,super必须放在第一行
                super(name);
                this.lang = lang;  // 扩展了专属于自己的lang属性
            }
            say(){
                console.log("中国话");
            }
        }

        let chinese = new Country("中国","各地方言");
        console.log(chinese.name); // 中国
        console.log(chinese.lang); // 各地方言
        chinese.say(); // 中国话

9. js中各种位置clientHeight/scrollHeight/offsetHeight/scrollTop/offsetTop/clientTop 的区别?

clientHeight:可视区域大小,只包含padding
offsetHeight:可视区域包含padding+border+滚动条
scrollHeight:包含了因为滚动被隐藏的部分的高度,即整个页面中某个元素距离顶部元素的高度
scrollTop:滚动条滚动的距离,即被卷上去的页面高度
offsetTop:到定位父级的上边界的间距
clientTop;获取元素上边框(border)宽度..px

10. bind /call /apply的区别?

这三个都是改变this指向的函数,call和apply的第一个参数都是要改变指向的对象,其中call的第二个参数是"参数1,参数2,…"这样的排列,apply的第二个参数必须是一个数组,bind返回的是一个函数,必须被调用才可以使用。

11. new关键字,及其执行过程

使用new关键字可以new出实例化对象。
明明只是一个函数,可是为什么new Person()执行后会突然返回一个对象呢?
因为new帮我们创建了一个空对象,例如:obj;
将空对象原型的内存地址__proto__指向函数的原型对象;
利用函数的call方法,将原本指向window的绑定对象this指向了obj。
(这样一来,当我们向函数中再传递实参时,对象的属性就会被挂载到obj上。)
利用函数返回对象obj。

12. 事件流

js中的数据交互是通过事件驱动实现的,鼠标点击事件onclick等。
ie的事件流是事件冒泡,网景的事件流是事件捕获,事件冒泡是由内向外的,由子级向父级传递的。
事件捕获是从父级传递到子级,事件捕获在点击完元素后不会立即触发事件,而是一层一层向下捕获,最终到达这个元素才触发事件。
DOM2级的addEventListener的第三个参数是true,也就是说当你点击目标元素后,不会立刻执行触发事件,而是先执行事件捕获阶段 ——> 然后处于目标阶段(触发事件) ——> 事件冒泡阶段。

13. 事件委托/事件代理

事件委托是利用事件冒泡的机制,通过给父级统一添加事件,点击子级会冒泡到父级,执行父级身上的事件,这样可以统一管理一系列标签的事件。比如ul和li标签,为了给每个li一个点击事件,可以统一给父级ul一个点击事件来管理。当动态添加li标签,也会有事件监听函数。

14. 一个页面从输入url到加载完成的整个过程

输入url ----> DNS服务器 —> tcp三次握手建立连接 —> 发送http/tsl+https请求 —> 服务器返回数据包 —> tcp四次挥手关闭连接

根据数据包 —> 解析HTML\CSS\JS资源 ----> 生成DOM树+CSS规则树 —> 合成渲染树 —> 对页面进行绘制和渲染

输入url后,浏览器发送请求到DNS域名解析服务器,获得到ip地址,建立tcp三次握手,形成tcp/ip连接,发送http请求(如果是https请求在发送前还需要进行tsl协商才能发送请求),服务器响应数据包,tcp四次挥手关闭与服务器的连接。
浏览器会根据拿到的数据包解析HTML文档,构建DOM树,构建CSS样式树,解析js脚本,下载资源。
页面渲染的过程:
浏览器通过HTML解析器,将HTML解析成DOM树。通过CSS解析器将CSS解析成CSS规则树,DOM树和CSS规则树合成一个渲染树。根据渲染树对页面进行渲染。

15. tcp三次握手和四次挥手,以及udp协议

tcp包括三次握手-传输确认-四次挥手
tcp的三次握手,客户端要询问服务器是否能够建立连接[发送一个SYN包],服务器端要应答客户端同意连接[发送一包SYN+ACK包],客户端收到之后应答确定是要建立连接[回复一个ACK包],连接建立。因为互相发送了三包数据,所以是三次握手。(SYN包就是要发送的数据包,ACK包是做应答的数据包
在这里插入图片描述

为什么一定要是三次握手?两次握手不行吗?
不行,因为三次握手才能建立一个可靠的连接,若是两次握手,客户端发送第一包数据过程中阻塞,由于客户端没有收到数据会再次发一次第一次握手的数据过去,此时服务器端收到这包数据给了一个应答,一个连接建立。而阻塞的那个包突然也传到了服务器端,那么服务器相当于建立了两个连接,而客户端却认为是一次连接,所以服务器端会一直在等待数据状态。如果是三次握手,服务器端在接收到这个阻塞的数据包后,应答客户端,客户端没有发送第三次握手的数据过来,服务器就会认为这次连接没有建立成功。三次握手就是为了解决网络信道不可靠的问题。为了在不可靠的信道上建立可靠连接。

tcp连接是在不可靠的信道上建立可靠连接,那如何解决一包数据被拆成多包发送时的丢包和乱序问题?
在这里插入图片描述

tcp是全双工通信,即客户端和服务器端都采用的这种机制发送和接收数据。机制如下:tcp协议为每一个连接建立了一个发送缓冲区,建立连接后的第一个字节号是0,后面每个字节的序列号增加1,发送数据时,从发送缓冲区取一部分数据组成发送报文,在tcp协议头中附带序列号和长度。
服务器端收到数据后,需要回复确认包ACK,确认报文中的ACK=接收序列号+长度,也就是下一包数据需要的起始序列号,这样能够使发送端确认发送的数据已经被对方收到,发送端也可以一次性发送连续的多包数据,接收端只需要回复一个确认包ACK即可。

tcp的四次挥手
客户端和服务器端,都可以发送“关闭连接”请求。客户端要关闭连接【发送一个FIN包】【自己进入FIN-WAIT-1终止等待1状态】;
服务器端自查数据【发送一个ACK包】【自己进入CLOSE-WAIT关闭等待状态】【客户端进入FIN-WAIT-2终止等待2状态】此时服务端还可以发送未发送的数据,客户端还可以接受数据;
服务端发送完数据后【发送一个FIN包】【自己进入LAST-ACK最后确认状态】;
客户端收到数据后【发送ACK包】【自己进入TIME-WAIT超时等待状态】,到达超时时间后关闭连接,而服务端收到ACK包后立即关闭连接;
在这里插入图片描述

为什么客户端需要设置超时时间呢?
如果没有超时时间,服务端没有收到客户端发送的ACK包的话,就会一直停留在最后确认状态。 超时时间是为了确定服务端已经收到ACK包,如果服务端没有收到ACK包会重发FIN包,再次等待客户端再次发送ACK包。也是为了保证在不可靠的传输信道进行可靠传输。

UDP协议
UDP协议是基于非连接的,发送数据是直接发数据包,正因为它发送没有状态确认等,所以占用cpu资源较少,性能损耗小,但是传输数据可能造成丢包,稳定性较弱,
TCP协议与UDP协议的不同适用场景:
tcp协议和udp协议都属于传输层协议,都是在程序之间传输数据。数据可以是文本视频文件等。tcp基于连接的可靠传输协议,udp是非连接的协议。
TCP协议传输数据稳定可靠,适用于对网络通讯质量要求较高的场景,需要准确无误的传输给对方。传输文件,发送邮件,浏览网页等。
UDP传输数据速度快,但是可能产生丢包,适用于对实时性要求较高,但是对数据丢包并没有太大要求的场景,比如:语音通话,视频直播等。

16. promise的理解及它解决了什么问题

promise是异步操作的同步解决方案,可以避免层层嵌套的回调地狱。它有几个状态:pedding(等待)/fufiled(成功)/rejected(失败),状态一旦改变,就不会再变了。promise的创建是构造函数new出来的对象,promise中有两个函数异步操作成功会调用resolve(),失败会调用reject()。通过.then()来执行下一步操作,一直返回Promise对象的话,可以一直.then下去。

补充;promise中代码的执行顺序,为什么是这样执行的?

promise中代码的执行是先主任务,再微任务,再宏任务。所以先打印同步代码的结果,其次执行promise.then(res=>{})中的结果,因为拿到数据res的步骤是微任务,然后才是执行定时器代码这种宏任务。

<script>
    setTimeout(() => {
        console.log("4")   // 宏任务
    },0)
    new Promise((resolve) => {
        resolve()
        console.log("1")  // 主任务
    }).then((res) => {
        console.log("3") // 微任务
    })
    console.log("2") // 主任务
</script>
>>>输出结果:1 2 3 4

17. await+async的理解

async是加在函数前,证明这个函数是异步函数,内部的await代表每一次的状态,每到一个await都会等待执行完,才会继续向下进行下一步的操作。await是基于generator中的yield状态东西,每到一个状态都会等待。也是可以将异步操作以同步的形式展示出来。更有利于理解代码。网络请求用这种配合也比较多。

18. 普通函数和构造函数的区别

构造函数在es5中是用于充当类的一个概念,需要new关键字创建实例化对象,而且书写方式上函数名是开头字母大写。普通函数直接调用即可,而且普通函数调用时不会创建出实例化对象来。
构造函数中的this指向实例,普通函数中的this指向调用函数的对象,没有对象调用指向window。
es6中构造函数的函数名与类名相同

19. 什么是面向对象?

面向对象是一种编程范式,一切皆对象,类是对一类事物的共同属性的一种抽象,可以通过new关键字创建出一系列的实例化对象。对象可以继承类的一些属性和方法,也可以扩展自己的属性和方法,具有封装、继承、多态的特点。

20. 数组方法有哪些?

push/pop: 从尾部插入和删除
unshift/shift: 从头部插入和删除
concat 可拼接数组,返回值为原数组
splice 可裁切数组
split 将字符串转换为数组
map 遍历数组

21. let var const区别

let const是es6新增的关键字,都是块级作用域,
var是全局作用域或函数级作用域,没有块级作用域的概念
var能重复声明和赋值,let const不能
var存在变量提升,let const没有
const声明的是一个常量,初始化时必须赋值,且一旦赋值不能改变

22. es6有什么新特性?

es6有模板字符串,用反引号包起来方便字符串拼接。
有数组和对象的解构赋值,符号是…
有set数据结构
有promise
有Symbol这种独一无二是数据类型
箭头函数
for…of for…in这种遍历方式
类的概念和继承有了新的实现方式
Module语法

23. cookie localStorage sessionStorage的区别

存储大小不同:cookie是4kb,其他两个是5M
读取方式不同:cookie是随着网络请求携带到服务器,其他两个是存储在本地的,需要通过getItem读取
存储时长不同:
cookie可以设置过期时间,cookie有一个注意点是cookie不能跨域,必须是同源的
sessionStorage是只在当前会话页面有效,刷新页面数据还存在,关闭页面数据将会清空
localStorage是存储在本地,且长期有效,除非在代码中做删除操作,或用户手动删除

24. 如何判断一个数据是不是NaN

常规方法无法识别NaN,如果要判断,需要用es6新增的Object.is(NaN === NaN),返回值为布尔值

25. Ajax是什么?Ajax的步骤

ajax是网络请求,可以让页面不需要刷新就能得到更新。它主要是基于xhr对象
第一步:创建xhr对象

var xhr = new XMLHttpReauest()

第二步:发送http请求

xhr.open('get','接口') // 准备数据
xhr.send() // 发送请求

第三步:接收数据
通过onreadyStateChange事件监听readyState的状态变化,=4就是请求完成得到响应数据了

第四步:通过读取status状态码,来判断拿到的数据,并更新页面

xhr.onreadystatechange = function(){
 if(xhr.readyState === 4){
               // status状态码:目前讲的分为2种:成功200 失败404等非200
               if(xhr.status === 200){
                   // 成功了,打印响应文本
                   console.log(xhr.responseText);
               }else{
                   // 打印失败时的状态信息
                   console.log(xhr.statusText);
               }
           }
}

26. 防抖 节流

防抖:用户触发事件特别频繁,只要最后一次事件的操作,
思路是:只要用户触发事件了,那我们就把之前的定时器清掉,再新建一次定时器。
节流:控制事件执行次数
思路是:用一个valid作为标志为,为真的时候就进入定时器执行业务,为假的时候就出来定时器

// 防抖,什么时候停,什么时候执行
        function debounce(fn,delay){
            var timer = null;
            return function(){
                if(timer){
                    clearTimeout(timer)
                }
                timer = setTimeout(fn,delay)
            }
        }


        function Print(){
            var scrollTop = document.documentElement.scrollTop;
            console.log(scrollTop);
        }

        window.onscroll = debounce(Print,300)
  // 节流:间隔时间内只执行一次
        function throttle(fn,delay){
            var valid = true;
            return function(){
                if(!valid){
                    return false;
                }
                valid = false
                setTimeout(()=>{
                    fn();
                    valid = true;
                },delay)
            }
        }
        function Print(){
            var scrollTop = document.documentElement.scrollTop;
            console.log(scrollTop);
        }
        window.onscroll = throttle(Print,300)

27. for…in… 和 for…of…的区别

for...in:
	适用于遍历对象而产生的,不适用于遍历数组,但可以遍历数组。
	获取对象的 键名 key;
	会遍历整个对象的原型链;
	返回数组中所有可枚举的属性
for...of:
	只能遍历数组
	会遍历获取对象的 键值 value;
	只遍历当前对象;
	返回数组下标对应的属性值
map:
    返回新数组,不改变原数组,按return后面的方式返回新数组
filter:
	用来过滤出符合条件的内容,返回新数组,若没有符合条件的,返回[ ]空数组
 // map    forEach    for...in    for...of    filter
        // map
        const arr = [1, 2, 3, 4]
        const newArr = arr.map((it) => { 
            return {num: it} 
        });
        console.log(newArr); // [{num: 1},{num: 2},{num: 3},{num: 4}]
        console.log(arr); // [1, 2, 3, 4]

        // forEach 不能用break和continue跳出当前的迭代,只能用return进入下一个迭代
        const arr1 = [1, 2, 3, 4]
        arr1.forEach((it, index, self) => {
            if (it == 2) {
                return;
            }
            console.log(it, index, self);
            // 第一行:1 0 [1, 2, 3, 4]  第二行:3 2 [1, 2, 3, 4]  第三行: 4 3 [1, 2, 3, 4]
        })

        // for..in可用于遍历对象和数组    
        const obj = {
            num1: 11,
            num2: 1
        }
        for (let key in obj) {
            console.log(key); // num1 num2
        }

        // for...in  
        const arr2 = [1, 3, 4]
        for (let value in arr2) {
            console.log(value); // 0 1 2
        }

        // for..of只能用于数组
        for (let value of arr2) {
            console.log(value); // 1 3 4
        }


        // for..of用于数组,遍历拿到的是键值,也就是每个索引中存放的value值
        // for..in用于对象和数组,遍历拿到的是数组的索引号,或对象的键值对中的键名

        // filter()过滤数组,返回过滤后的新数组
        var arr3 = [1, 2, 3, 4].filter((item) => {
            return item > 3
        })
        console.log(arr3); // [4]

28. 数组去重

   const arr = [1, 2, 2, 'abc', 'abc', true, true, false, false, undefined, undefined, NaN, NaN]

        // set --- set数据结构中的内容都不重复[ES6]
        const s = new Set(arr)
        console.log(s); // {1, 2, 'abc', true, false, undefined, NaN}
        console.log([...s]); // [1, 2, 'abc', true, false, undefined, NaN]

        // indexOf --- 没有找到值返回-1---不可检测NaN
        const newArr = []
        for(let i of arr){
            if(newArr.indexOf(i) == -1){
                newArr.push(i)
            }
        }
        console.log(newArr); // [1, 2, 'abc', true, false, undefined, NaN, NaN]

        // includes --- 返回true/false[ES7]---可以检测到NaN
        const newArr1 = []
        for(let i of arr){
            if(!newArr1.includes(i)){
                newArr1.push(i)
            }
        }
        console.log(newArr1); // [1, 2, 'abc', true, false, undefined, NaN]

        // 双层for循环 --- 不能检测NaN
        let len= arr.length;
        for(let i=0; i<len; i++){
            for(let j=i+1; j<len+1;j++){
                if(arr[i] === arr[j]){
                    arr.splice(j,1) // 把j索引的这个元素切掉
                }
            }
        }
        console.log(arr); // [1, 2, 'abc', true, false, undefined, NaN, NaN]

        // filter遍历数组
        function unique(arr) {
            return arr.filter(function(item, index, arr) {
            //当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
                return arr.indexOf(item) === index;
            });
        }
        console.log(unique(arr)) // [1, 2, 'abc', true, false, undefined]

29. 什么是跨域以及跨域的解决方案

因为浏览器有同源策略,即协议域名端口号必须相同,才能进行访问。目的是为了规避掉一些安全问题。
但公司产品可能需要关联,此时就需要跨域访问,解决跨域问题的方法有三种:
jsonp解决跨域(只能是get请求)cors(后端配置)proxy代理
jsonp解决跨域主要是后端要给的接口中必须将数据给到回调函数里,前端实现这个回调函数拿到数据。首先需要动态创建script标签,script标签的src属性为接口地址,将script标签添加到页面中,前端实现接口,拿到后台给我们的数据。

30. 数组的冒泡排序和快速排序,扩展了选择排序、插入排序

冒泡排序:
在这里插入图片描述

 冒泡排序思想:相邻两个数比较,每一趟冒出一个最小的数,下一趟内循环次数减1
              eg:3个数,因为每一趟都会冒出最小的数,这个数就不用参与比较了,
              所以第一趟比较2次,第二趟比较1次
              【3个数比较2趟,且内层循环每一趟比较次数-1】
     ------------------------------------------------------------------------------------
       const arr = [5,1,65,43,454,90,545,34,435,356,342,12]
        // 冒泡排序
        function bubbleSort(arr){
            for(let i=0; i< arr.length; i++){
                for(let j=0; j<arr.length-i;j++){
                    if(arr[j] > arr[j+1]){
                        const temp = arr[j];
                        arr[j] = arr[j+1];
                        arr[j+1] = temp;
                    }
                }
            }
            return arr;
        }
        console.log(bubbleSort(arr)); // (12) [1, 5, 12, 34, 43, 65, 90, 342, 356, 435, 454, 545]

快速排序(分治思想):

在这里插入图片描述

 快速排序:
            选择数组中任何一个数作为pivot基准数,比pivot小的数放在它左边,比它大或相等的放在它右边
            再对左右区间重复上述操作,直到各区间少于2个元素
   -------------------------------------------------------------------------------------------------------------
     const arr = [5,1,65,43,454,90,545,34,435,356,342,12]
     function quickSort(arr){
             if(arr.length <= 1){
                return arr;
            }
            let pivotIndex = Math.floor(arr.length / 2);
            let pivot = arr.splice(pivotIndex, 1)[0];
            let left = [];
            let right = [];
            for(let i=0; i < arr.length; i++){
                if(arr[i] < pivot){
                    left.push(arr[i])
                }else{
                    right.push(arr[i])
                }
            }
            return [...quickSort(left),pivot,...quickSort(right)]
        }
        console.log( quickSort(arr)); // (12) [1, 5, 12, 34, 43, 65, 90, 342, 356, 435, 454, 545]

选择排序:
在这里插入图片描述

    选择排序: 
            第一趟:第一个值,分别和后面每个值进行比较,若满足规则则交换位置,开始下一趟比较
            第二趟:第二个值,分别和后面每个值比较,直到遇到满足交换条件的,交换位置,开始下一趟
            第三趟:第三个值,分别和后面每个值比较,直到遇到满足交换条件的
            【5个数比较4趟】
    ------------------------------------------------------------------------------------------------------
      const arr = [5,1,65,43,454,90,545,34,435,356,342,12]
      function selectSort(arr){
            for(let i = 0;i<arr.length;i++){
                let minIndex = i;
                for(let j = i+1; j<arr.length; j++){
                    if(arr[j] < arr[minIndex]){
                        // 这个结束后,minIndex中就是数组中最小元素的索引
                        minIndex = j;
                    }
                }
                // 交换 --- ES6解构赋值来完成数据交换
                [arr[i],arr[minIndex]] = [arr[minIndex],arr[i]]
            }
            return arr;
        }
        console.log( selectSort(arr)); // (12) [1, 5, 12, 34, 43, 65, 90, 342, 356, 435, 454, 545]

插入排序:
在这里插入图片描述

 const arr = [5,1,65,43,454,90,545,34,435,356,342,12]
  function insertSort(arr) {
            let len = arr.length;
            for(let i=1; i<len; i++){
                let current  = arr[i];
                let j = i-1;
                while(j>=0 && current<arr[j]){
                    arr[j+1] = arr[j]
                    j--;
                }
                arr[j+1] = current;
            }
            return arr;
        }
   console.log(insertSort(arr)); // (12) [1, 5, 12, 34, 43, 65, 90, 342, 356, 435, 454, 545]

31. 详细说明HTTP和HTTPS的区别

客户端与服务器端进行交互时,需要ip地址作为标识来区分,所以输入url地址后,会先通过DNS域名解析服务器拿到ip地址。此时http协议会调用传输层的tcp协议,若是https协议会在tcp协议前先进行TSL握手(相当于一个安全层,用于给数据加密)。
http协议和https协议按五层网络结结构来分都是应用层的协议,https是需要加密传输的。
http传输过程是完全透明的,任何人都能在链路中截取、修改、伪造请求响应报文,数据不具有可信性。使用https时,所有的http请求和响应在发送到网络前,都会进行加密处理。
TSL的对称加密,使用异或算法(异或即相同为0,不同为1)。
非对称加密有两个密钥,一个公钥一个私钥,公钥私钥都是服务端保管,一般运维来部署,公钥分发给客户端,私钥服务端保管好进行解密
在这里插入图片描述

32. 输入框输入数据,请求后台接口,第一个接口返回的信息可能比较慢,到第二次调用后的信息已经返回了,前一条数据才出来,如何避免页面被第一个接口返回的信息覆盖?

这个答案不确定,目前搜到的是可以在网络请求的响应拦截器中过滤返回的数据,如果是第二次的就显示,如果是第一次的就过滤掉。

33. js延迟加载的方法有哪些?

defer属性:延迟脚本执行,等DOM加载生成后再执行script脚本
async属性:异步的形式,脚本下载的同时,浏览器继续渲染,但是若几个js资源有依赖关系不推荐这个,因为可能被依赖的那个文件后下载完的话会导致问题
动态创建script标签,给script标签一个src属性放要加载的资源,将script标签插入到页面代码中

	//这些代码应被放置在</body>标签前(接近HTML文件底部)
	<script type="text/javascript">  
	   function downloadJSAtOnload() {  
	       varelement = document.createElement("script");  
	       element.src = "defer.js";  
	       document.body.appendChild(element);  
	   }  
	   if (window.addEventListener)  
	      window.addEventListener("load",downloadJSAtOnload, false);  
	   else if (window.attachEvent)  
	      window.attachEvent("onload",downloadJSAtOnload);  
	   else 
	      window.onload =downloadJSAtOnload;  
	</script> 

设置计时器:设置一个定时器来延迟加载js脚本文件

	<script type="text/javascript" >
		  function A(){
		    $.post("/lord/login",{name:username,pwd:password},function(){
		      alert("Hello");
		    });
		  }
		  
		  $(function (){
		    setTimeout('A()', 1000); //延迟1秒
		  })
	</script>

放在所有js代码底部:

		<body> 
				xxxxx正常代码
				<script src="hello.js"></script>
		</body>

34. 简述get和post的区别

  1. get:一般用于请求获取数据 post:一般用于发送数据到后台
  2. get请求也可以传参,只是参数在url地址中可见,隐私性安全性较差,参数长度有限。
    post请求传递的参数在request.body中,不会在url中展示,比get要安全
  3. get:请求刷新你浏览器或回退时没有影响 post:请求回退时会重新提交数据请求
  4. get请求可以被缓存。 post请求不会被缓存
  5. get请求会保存在浏览器历史记录中 post请求不会保存在历史记录中
  6. get请求可以被收藏为书签。
  7. get请求通常通过直接输入url地址请求,post请求通常通过表单发送数据请求
  8. get请求只能进行url编码,而post支持多种编码方式。

  1. get和post的都是http的请求方式,底层都是tcp/ip协议。 get和post本质上就是tcp连接,并无差别。但是由于http的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
  2. 通常get产生一个tcp数据包,post产生两个数据包get会把http header和数据一起发送出去,服务端响应200. post请求先发送header,等服务器响应了100,再继续发送data,服务端在响应200(因为post请求不会直接发送数据,这样太虎了,post请求很谨慎,会先确定对方应答才会发送数据过去)
  3. 浏览器差异,并不是所有的post请求都会发送两个数据包,火狐浏览器post请求也是一个数据包
  4. post请求和get请求在网络条件好的情况下,传输速度无太大差别。但网络较差的情况下,get效率比post高

35. 如何阻止事件冒泡和默认事件?

1.event.stopPropagation()方法	
阻止事件的冒泡方法,不让事件向document上蔓延,但是默认事件会执行,当你掉用这个方法的时候,如果点击一个链接,这个链接仍会被打开,

2.event.preventDefault()方法
阻止默认事件的方法,调用此方法是,链接会被打开,但是会发生冒泡,冒泡会传递到上一层的父元素;

36. js的 typeof返回哪些数据类型

typeof操作符可返回的数据类型有:“undefined”、“object”、“boolean”、“number”、“string”、“symbol”、“function”等。

        // 在javascript中,typeof操作符可返回的数据类型有:“undefined”、“object”、“boolean”、“number”、“string”、“symbol”、“function”等。
        var a;
        console.log(typeof a); // undefined
        console.log(typeof {}); // Object
        var c = NaN;
        console.log(typeof c); // number
        console.log(typeof false); // boolean
        console.log(typeof 1); // number
        console.log(typeof 'hello world');// string
        var s = Symbol('独一无二');
        console.log(typeof s);// symbol
        var print = function(){
            console.log("我是一个打印函数");
        }
        console.log(typeof print); // function

37. 举出3 种强制类型转换和 2 种隐式类型转换 ?

强制类型转换:
parseInt() Number() String() Boolean()
parseInt("1234blue"); // 1234
Number("56") // 56
String(123) // "123"
Boolean(0); // false
隐式类型转换:
+号和字符串连接,任何类型都会被隐式转换为字符串1+'abc' = '1abc'
用==做判断时,会自动进行隐式类型转换,比如:1=='1'

38. js中split()与join()的区别

    // split将字符串分割成数组
   //  join将数组拼接成字符串
    var s = "hello*world*!!*today";
    var s1 = ['say', 'hi','hi'];
    console.log(s.split('*')); // ['hello', 'world', '!!', 'today'] 
    console.log(s1.join('*')); // say*hi*hi

39. ajax请求时如何解析json数据

通过JSON.parse()方法,将json格式的数据转化为js对象,拿到的json数据就可以正常使用了
console.log(JSON.parse('{ "name":"张三", "age":18, "email":"xxx.zs.com" }'));
>>> 输出结果:{name: '张三', age: 18, email: 'xxx.zs.com'}

40. 解释jsonp的原理,以及为什么不是真正的ajax

jsonp是一种跨域解决方案,只能解决get请求的跨域问题,不适用于post请求。
不是真正的ajax是因为jsonp中没有通过xhr对象来实现,而是通过script标签动态创建的方式来拿到后台给的数据的。而且jsonp不能进行post请求,所以本质上不是ajax。

41. document load 和 document ready 的区别

$(document).load是当页面所有资源全部加载完成后(包括DOM文档树,css文件,js文件,图片资源等),执行一个函数
$(document).ready是当DOM文档树加载完成后执行一个函数 (不包含图片,css等),会比load较早执行。
原生的js中不包括ready()这个方法,只有load方法也就是onload事件。

42. 数据类型检测的方法

typeof

	typeof 的返回类型为字符串,值有:number、boolean、string、object、function、undefined、symbol、bigint
	typeof 一般用来判断基本数据类型,除了判断null会输出"object",其它都是正确的
	typeof 判断引用数据类型时,除了判断函数会输出"function",其它都是输出"object"
	
注意:这里涉及两个经常考的面试题!
	 null 的数据类型是object (null是一个空的引用对象,是一个占位符)
	 console.log 的数据类型是function 
	 对于引用数据类型的判断,使用typeof并不准确,所以可以使用instanceof来判断引用数据类型
console.log(typeof 1);             //number
console.log(typeof true);          //boolean
console.log(typeof null);          //object!!!

instanceof

	instanceof 可以准确的判断引用数据类型,它的原理是检测构造函数的prototype属性是否在某个实例对象的原型链上
	instanceof用于判断实例是否是某个对象的实例,返回值是true/false
	
console.log([] instanceof Array);                    // true
console.log(function(){} instanceof Function);       // true
console.log({} instanceof Object);                   // true

constructor

能准确区分Array|Object 因为它没有instanceof那样会遍历整条原型链,只是在实例身上进行判断。
但也有个致命的缺陷,实例上的这一属性太容易被修改了,一旦修改,这个方法就没有意义了。

 不能检测出null和undefined
console.log([].constructor === Array);                 // true
console.log(function() {}.constructor === Function);   // true
console.log({}.constructor === Object);                // true

console.log((null).constructor === Null);   //  Cannot read property 'constructor' 

console.log((undefined).constructor === Undefined); // Cannot read property 'constructor' 

Object.prototype.toString.call()

 可以检测所有的数据类型,包括null和undefined
	bject.prototype.toString.call(true) ;            // [object Boolean]
	Object.prototype.toString.call(Symbol());         // [object Symbol]
	Object.prototype.toString.call(undefined) ;       // [object Undefined]
	Object.prototype.toString.call(null) ;            // [object Null]
	Object.prototype.toString.call(new Function()) ;  // [object Function]
	Object.prototype.toString.call(new Date()) ;      // [object Date]
	Object.prototype.toString.call([]) ;              // [object Array]

Array.isArray()

	判断数组:检测数组 --- 返回 true/false
	console.log(Array.isArray(arr));// true

Number.isNaN(NaN)

	如果是NaN则返回true,否则返回false

43. 箭头函数和普通函数的区别

  1. 箭头函数不能作为构造函数,而普通函数可以
  2. 箭头函数没有原型,而普通函数有
  3. 箭头函数的this指向上层函数作用域的this对象,call, apply, bind会改变普通函数的this,但不会改变箭头函数的this。在普通函数中this指向调用这个函数的对象。
  4. 普通函数中有arguments储存传给该函数的所有参数,箭头函数中没有该arguments参数。而是用rest参数。
	// rest参数 ...items
        function add1(...items){
            console.log(items);
        }
        add1(10,20,30); // [10, 20, 30]
  1. 普通函数表现为function关键字,箭头函数表现为=>

箭头函数中用…arg存储所有参数。

44. Map和Set的区别[ES6]

(1) Set执行时间最短,那么查找速度最快,当然了Set 和 Map的查找速度都很快想差不大,
所以说这两种方法具有极快的查找速度。

(2) 初始化需要的值不一样,Map需要的是一个二维数组,而Set 需要的是一维 Array 数组

(3) Map 和 Set 都不允许键重复

(4) Map的键是不能修改,但是键对应的值是可以修改的;Set不能通过迭代器来改变Set的值,
    因为Set的值就是键。

(5) Map 是键值对的存在,值也不作为健;而 Set 没有 value 只有 key,value 就是 key;

45. new Object() 和Object.create() 的区别[ES6]

Object.create(null) 创建的对象是一个空对象,在该对象上没有继承 Object.prototype 原型链上的属性或者方法。bject.create(o),如果o是一个字面量对象或实例对象,那么相当于是实现了对象的浅拷贝。
new Object()是使用构造方法创造对象,新建一个对象实例,继承原对象的prototype属性。

46. http常见的状态码

	100-199  提示信息 – 表示请求正在处理,除非在实验条件下,否则服务器不能发送100-199错误码给前端
	200-299  成功 – 表示请求正常处理完毕,一般表示请求成功
	300-399  重定向 – 要完成请求必须进行更进一步的处理
	400-499  客户端错误 – 请求有语法错误或请求无法实现
	500-599  服务器端错误 – 服务器处理请求出错。
	100 客户端应当继续发送请求。
	200 请求已成功,请求所希望的响应头或数据体将随此响应返回。
	202 服务器已接受请求,但尚未处理。
	300 被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。
	301 被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。
	400 语义有误,当前请求无法被服务器理解。请求参数有误。
	403 服务器已经理解请求,但是拒绝执行它。
	404 请求失败,请求所希望得到的资源未被在服务器上发现。

47. 浏览器的缓存机制,协商缓存

浏览器会将请求得到的资源储存为离线资源,下次需要该资源时,浏览器会根据缓存机制决定直接使用缓存还是再次向服务器发送请求
作用:减少了不必要的数据传输、降低了服务器的压力
加快了客户端访问速度,增强了用户体验

强制缓存:不向服务器端发送请求,强制使用缓存数据。强制缓存实现跟前端没关系,都是后端在处理,实现方式: 比如网页的图片,后端在返回数据时,在响应头中返回expires(指定资源到期具体时间)和cache-control。查看方式:查看源码点击网页图片,Network–img–Headers–ResponseHeaders中有expires和cache-control这些数据。
在这里插入图片描述
协商缓存到了过期时间后,是否是后台将过期时间提早了一个月之类的,(比如零食6月才真的过期,厂家为了容错性写的5月过期)。当强缓存失效后,会使用协商缓存(即问一下后台,我这个资源是真的过期了吗,后端说没有过期可以接着用,接着用强缓存读即可)。协商缓存由服务器决定是否还能继续使用缓存,向服务器发送请求资源,并携带过期资源标识Etag字段。 服务器会进行判断浏览器缓存的资源是否真的失效,真的失效,则服务端返回新的资源和缓存标识,返回状态码200。浏览器再次存入缓存,后续再次从强缓存读数据。
缓存时间到了,但是资源没有更新,那就继续使用本地数据,直接返回304
在这里插入图片描述

48. js中数组有哪些方法?讲讲reduce?

参考资料: reduce视频链接

 [将前面数组项遍历产生的结果与当前遍历项进行运算 --- 需要reduce来处理]
 reduce用法 --- 可以将前面每一次运行结果跟当前项进行运算比较
      prev:上一个值,第二个参数是初始值,有初始值就是初始值,没有初始值就是数组中的第一个值
      cur:当前值,有初始值的话,cur就是数组中的第一个值,没有的话,cur就是数组中的第二个值
      index:cur的索引号

       [1. 数组求和----------------------------------------------------------]
        const arr = [1,2,3];
        const sum = arr.reduce((prev,cur,index)=>{
            console.log(prev,index); // 00 11 32
            return prev + cur;
        },0)
        console.log(sum); // 6


        [2. 数组最大值----------------------------------------------------------]
        const max = arr.reduce((prev,cur,index)=>{
            return Math.max(prev,cur);
        })
        console.log(max); // 3

        [3. 数组去重----------------------------------------------------------]
        const arr1 = [1,2,3,5,4,4,3]
        const newArr = arr1.reduce((prev,cur,index) =>{
            console.log( prev);
            if(prev.indexOf(cur) === -1) {prev.push(cur);}
            return prev;
        },[])
        console.log(newArr); // (5) [1, 2, 3, 5, 4]

        [4. 数组扁平化----------------------------------------------------------]
        const arr2 = [[1,2],[3,5],[4,4],[1,2,3,[4,5,6,[7,8]]]]
        function getflatArr(a){
            return a.reduce((prev,cur)=>{
                console.log(prev);
                return prev.concat(Array.isArray(cur) ?  getflatArr(cur) : cur)
            },[])
        }
        console.log(getflatArr(arr2)); // (14) [1, 2, 3, 5, 4, 4, 1, 2, 3, 4, 5, 6, 7, 8]

49. xss攻击是什么?如何防范?

xss是一种发生在web前端的漏洞,其主要危害对象是前端用户,其攻击手段主要有诱惑用户点击钓鱼链接/获取用户cookie信息,甚至可以结合浏览器漏洞对用户主机远程操控。
xss攻击流程(跨站脚本漏洞):往web页面中插入恶意的script代码,用户请求页面时,该代码将会被执行(在普通用户不知情的情况下执行),从而获取用户信息,达到攻击用户的目的。
在这里插入图片描述
形成XSS漏洞的原因:程序对输入输出的控制不够严格,导致黑客脚本攻击服务器,服务器输出时会被浏览器当做正常代码执行,从而造成危害。

XSS攻击类型(危害由高到低):存储型 > 反射型 > DOM型
存储型:恶意代码存储在数据库中,永久存储,一般出现在留言板注册等页面
反射型:【恶意代码出现在了url链接地址中】恶意代码是一次性的,所见即所得,出现在查询页中。黑客需要诱导客户点击钓鱼链接。比如邮箱中的垃圾邮件,只要点了就触发了XSS攻击。
DOM型:不与后台服务器产生的数据交互,是一种通过修改页面DOM节点产生的问题。

测试流程:在目标站点找到输入点,查询接口,留言板等,输入特殊字符和唯一识别字符,点击提交查看返回源码,是否有做对应处理。通过搜索定位唯一字符,结合唯一字符前后语法,确认是都可以构造js代码(即代码是否可以构造闭合)
提交构造的脚本代码,绕过各种姿势,看是否可以成功执行,如果成功执行,则证明存在XSS漏洞。

XSS可以盗取cookie,钓鱼,获取键盘输入记录等。黑客通过img标签可以拿到正常用户的cookie,

防范: 防止 HTML 中出现注入。防止 JavaScript 执行时,执行恶意代码。
输入做过滤,输出做转义。 用token替代cookie
Vue等框架会默认屏蔽XSS攻击,Vue中使用v-html可能会造成XSS攻击
给cookie设置http-only

		 // 无法获取到设置 http-only 的cookie
			document.cookie
	    避免使用内联事件onLoad="onload('{{data}}')",在 js中通过addEventlistener() 事件绑定会更安全。
	    前端过滤不靠谱, 主要还是由后端去处理. 并且过滤恶意输入适用范围有限.

参考博客: 点我跳转

50. 知道数组的sort方法吗?底层用的是什么排序?为什么?

sort排序默认按照字典顺序排。即111会排在20的前面。
底层 :查到博客说:sort使用的是插入排序和快速排序结合的排序算法。
为什么:数组长度不超过10时,使用插入排序。长度超过10使用快速排序。在数组较短时插入排序更有效率。

51.以下代码的结果是?

        console.log("1"+1); // 11
        console.log("1"*1); // 1

52. 聊聊null和undefined

null是一个表示 " 无 " 的对象,转为数值时为0;                    Number(null) // 0
undefined是一个表示 " 无 " 的原始值,转为数值时为NaN。 Number(undefined) //  NaN
		typeof(null) // object
		typeof(undefined) // undefined

null表示 " 没有对象 " ,即该处不应该有值。典型用法是:
(1)作为函数的参数,表示该函数的参数不是对象。
(2)null作为对象原型链的终点。Object.getPrototypeOf(Object.prototype)
  (3)  当需要释放一个对象的时候可以将该对象赋值为null,进而来释放对象

undefined表示 " 缺少值 " ,就是此处应该有一个值,但是还没有定义。典型用法是:
(1)变量被声明了,但没有赋值时,就等于undefined。
(2)  调用函数时,应该提供的参数没有传,该参数等于undefined。
(3)对象没有某个属性,读取属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。

null、undefined是怎么产生的
1、产生null方式一:当访问一个不存的DOM节点时
console.log(document.getElementById(“#aaaaaaa”)); // null
2、产生null方式二:Object的原型链终点:
console.log(Object.prototype.__proto__);// null
1、产生undefined方式一:声明了变量但未赋值:

	var a;
	console.log(a);//undefined

2、产生undefined方式二:对象的属性没有赋值的情况下:

	var obj = {a:1}; 
	console.log(obj.age)//undefined

3、产生undefined方式三:函数调用的时候,函数的参数没有提供的情况下:

	function add(num){ 
	 	console.log(num)
	}; 
	add(); // undefined

4、产生undefined方式四:当函数没有返回值的情况下:

	var a = function(){};
	console.log(a()) // undefined

53. querySelector可以选择伪元素吗?

常见的伪元素有::after和::brfore,他们用于在CSS渲染中向元素的头或者尾插入内容,其不影响文档本身,只会影响最终的样式。
也即是说,这些伪元素不会出现在DOM中,仅仅在CSS渲染层中。
我们使用Window…querySelector(“::before”)其实操作的是DOM元素,因为伪元素不存在DOM中,所以无法操作伪元素。

54. 异步设定的时间准吗?如何解决异步设置的时间不准确的问题?

只查到可以使用webworker这种模拟多线程处理,其他不知道。。。这个题不大会

55. 数组去重兼容IE浏览器

在 IE6-8 下,数组的 indexOf 方法还不存在。所以要写出一个方法代替indexOf方法。
思路:通过对比数组前后元素是否相等,如果相等利用splice方法删除后面再次出现的元素,将删除重复元素后的原数组元素push到结果数组
splice删除元素方法的参数为两个splice(index,num),分别为开始下标和删除个数

56. 数组去重复要求杂度为O(n) 如何实现 ( 数组中有 “1” 和1) ?

57. indexOf的原理

indexOf有两个参数,第一个参数是要查询的元素,第二个参数是开始查询位置的下标start。

	   Array.prototype.myIndexOf = function (param,start=0) {
            //如果start大于等于数组长度,此时this[start]越界,返回-1
             if (start >= this.length) return -1
             //如果start小于0,判断start + this.length
            if (start < 0) {
                start = start + this.length < 0 ? 0 : start + this.length;
            }
            //start处理完毕,开始从start处遍历数组,查找元素下标
            for (let i = start; i < this.length; i++) {
                if (this[i] === param) return i;
            }
            //遍历完毕没有找到相应元素,返回-1
            return -1
        }

58. 柯里化函数的应用常见有哪些?

什么是函数柯里化?
     就是将一个函数的多个参数,分成多个单一参数的函数返回,柯里化函数是闭包的典型应用
好处:
	入口单一,便于测试和复用; 易于定位bug
坏处:
	嵌套的函数多,占用内存较多,效率低,每个函数都会在栈中占据内存,都有单独的函数级作用域
        // 函数柯里化
        function add(){
            // let args = arguments; // 第一个括号里的参数 // 但args不是一个数组,要进行数组转换
            let args = [...arguments];
            let inner = function(){ // 接收第二个括号里的参数
                args.push(...arguments)
                return inner

            }
            inner.toString = function(){
                return args.reduce((prev,current)=>{
                    return prev + current;
                },0)
            }
            return inner
        }
        console.log(+add(1)(3)); // 4
        console.log(+add(1,2)(3)); // 6
        console.log(+add(1)(2)(3)) // 6
        console.log(+add(1)(2)(3)(1,4)) // 11

59. 如何通过柯里化函数统计函数的执行次数 ?

60. 举例js的函数编程、类编程、闭包相关编写方式。

函数式编程是一种编程范式,主要是利用函数把运算过程封装起来,通过组合各种函数来计算结果。

61. 如何实现浏览器内多个标签页之间的通信

localstorage
localstorage是浏览器多个标签共用的存储空间,可以实现多标签之间的通信。
使用 Websocket,通信的标签页连接同一个服务器,发送消息到服务器后,服务器推送消息给所有连接的客户端。
参考博客: 点击跳转参考博客

62. webSocket 如何兼容低浏览器 ?

webSocket在开始的时候依旧使用的是http协议,只不过后面保持tcp持久链接,webSockets和http很像,它的请求uri用的是ws、wss,对应http、https
在这里插入图片描述
webSocket参考博客:点击跳转参考博客

这里补充一下http的轮询(面试也有可能问轮询):点击跳转http轮询参考博客

63. 请说出三种减少页面加载时间的方法。

	压缩代码
	压缩图片
	导入时使用CDN资源

64. 针对前端你有哪些性能优化的方法 ?

减少http请求
路由懒加载,图片懒加载
使用CDN
提取公共功能
CSS样式放在头部
js资源可以放在底部引入

65. 什么是FE 立即执行函数 ? 如何实现 ?

(function(){函数体}()); // 自执行函数写法1
(function(){ 函数体 })(); // 自执行函数写法2
前面的函数都是声明和调用分开,而且可以不限次被调用,这是模块化思想的体现。但是对那些只需要执行一次的函数,怎么办呢?这就要用到立即执行函数。

立即执行函数,其实也可以叫初始化函数,英文名:IIFE。
立即执行函数就是在定义的时候就立即执行,执行完以后就释放,包括函数内部的所有变量。

比如在页面完成初始化完成后执行的函数一般都是立即执行函数。

66. 前端工程化的理解、如何自己实现一个文件打包,比如一个JS文件里同时又ES5 和ES6写的代码,如何编译兼容他们(webpack前端工程化)

67. web存储、cookies、localstroge、如何实现一个在一定时间后过期的localstorage、session和cookies的区别、cookies存储在哪

// cookie的应用代码
<body>
    <form>
        <label>用户名</label>
        <input type="username">
        <label>密码</label>
        <input type="password">
        <input type="checkbox" id="rememberMe">
        <label for="rememberMe">记住我</label>
        <input type="submit" value="登录">
    </form>
    <script>
        const username = document.querySelector('input[type="username"]')
        const checkbox = document.querySelector('input[type="checkbox"]')
        const submit = document.querySelector('input[type="submit"]')

        // 读取cookie
        let cookie = {}
        let array = document.cookie.split('; ').map(cookie => cookie.split('='));
        for(let i =0;i<array.length;i++){
            let name = array[i][0];
            let value = array[i][1];
            // 设置cookie的时候编码了,所以这里要解码
            cookie[name] = decodeURIComponent(value);
        }
        console.log(cookie);
        if(document.cookie){
            username.value = cookie.username;
            checkbox.checked = true;
        }



        // 设置cookie
        submit.addEventListener('click',e=>{
            if(checkbox.checked && username.value != ''){
                let key = 'username';
                // 因为cookie的值必须不能有空格等多余字符,所以需要对这个值进行编码后存储
                let value = encodeURIComponent(username.value);
                // cookie只能一条一条设置
                // 给cookie设置过期时间:max-age   和towDays值
                let twoDays = 2 * 24 * 60 * 60;
                document.cookie = `${key}=${value}; max-age=${twoDays}`;
            }
            e.preventDefault();
        })
    </script>
</body>

localStorage设置过期时间,可以给某个值设置一个过期时间字段存储一下,通过设置定时器,过了多长时间后让它失效,但页面关闭时定时器也会失效,此时可以通过当前时间减去本地存储的过期时间计算一下,然后删除localStorage
在这里插入图片描述
cookie的存储位置是:浏览器和服务器都有存储,因为cookie在进行网络请求时会被携带。
参考了技术蛋老师的视频讲解:视频链接

后续学习:store.js 是一个实现了浏览器的本地存储的 JavaScript 封装 API 。可以自定义储存方式,命名空间,设置过期时间等功能。在github搜索包“store.js”,可以下下来学习,能够设置过期时间之类的,以及选择存储方式之类的

68. JS如何实现重载和多态

重载,从简单说,就是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者重载方法。
多态是指不同类的对象在调用同一个方法时所呈现出的多种不同行为。
参考博客:点我跳转参考博客

【HTML】

1. html有哪些标签?语义化标签听过吗?有什么用?

html标签有很多,语义化标签有header footer section aside article nav等 ,这些标签本身就具有语义化,容易读懂标签的含义,便于浏览器搜索引擎爬虫对网页的爬取,从而提升了SEO。

2. html5有哪些新特性、移除了那些元素 ? 如何处理 HTML5 新标签的浏览器兼容问题 ? 如何区分 HTML 和 HTML5?

移除了big、center、font、s、strike、tt、u、frame等元素
新特性:canvas svg webStorage(localstorage/sessionstorage) video audio 语义化标签 webSocket
区分html和html5:区分文档声明
html5的文档声明很短:<!DOCTYPE html>

3. 对SSR有了解吗,它主要解决什么问题?

SSR是指服务器端渲染页面,指由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程

好处:1. 网页内容在服务器端渲染完成,一次性传输到浏览器,所以,首屏加载速度非常快(能够提高首页加载速度,因为模板渲染动作由后端完成,前端直接拿到后端替换好的html页面)
2. 有利于SEO,因为服务器返回的是一个完整的html,在浏览器可以看到完整的DOM,对于爬虫、百度搜索等引擎友好。
单页面应用:页面主要由服务器端渲染
只有访问频率非常高的才会用SSR

【css】

点我跳到顶部 点我跳到vue 点我跳到程序题

1. 关于页面的加载,css的解析会影响js的执行吗?css加载会影响吗?

css的解析不会影响js的执行,css的加载会影响js的执行。由于js可能会操作之前的Dom节点和css样式,因此浏览器会维持html中css和js的顺序。因此,样式表会在后面的js执行前先加载执行完毕。所以css会阻塞后面js的执行。

优化:可以使用CDN资源
压缩CSS,可以使用打包工具webpack,开启gzip压缩
减少http请求次数,合并多个css文件

参考链接: https://blog.csdn.net/qq_44606064/article/details/120619095

2. 行内元素有哪些 ? 块级元素有哪些 ?CSS 的盒模型 ?

行内元素:a span em strong i  b...   【独占一行,可以设置宽高】
块级元素:div ul ol form h1-h6 p...【占自身大小,不可设置宽高】
行内块级元素:input img 【占自身大小,可设置高宽】

css盒模型:标准盒模型 和 IE盒模型
由内到外都是 content padding border margin
标准盒模型width、height = content  其他都是往外扩
IE盒模型width、height = content + padding + border 属于向内收

3. CSS 选择符有哪些 ? 哪些属性可以继承 ? 优先级算法如何计算 ? 内联和 !important哪个级高 ?

CSS的选择器有:id选择器 > 类选择器 > 元素选择器 通配符选择器 合并类选择器 关系选择器 属性选择器
属性继承:text- font- line-height都可以继承,cursor光标也可以继承,visibility元素可见性
优先级计算:根据选择器的权重不同来叠加
优先级从高到低: !important>内联样式 > id选择器 > 类选择器 > 元素选择器 >通配符选择器>从父标签身上继承的样式
!important的优先级高于内联样式和其他选择器

4. 解释 css sprites,如何使用?

css精灵图是将网页要用到的多张图片合成一张图片使用,
可以减少网络请求的次数,减少服务器压力。

使用:
background-image:url('./1.jpg')引入精灵图图片,
background-position:-10px 10px;调整图片位置。来规定显示整个图片中的哪一张小图。
缺点:图片也有可能会失真

5. 你如何对网站的文件和资源进行优化 ? 期待的解决方案包括

文件合并(目的是减少http请求):Web性能优化最佳实践中最重要的一条是减少HTTP 请求,减少HTTP请求的方案主要有合并JavaScript和CSS文件、CSS Sprites(雪碧图)、图像映射 (Image Map)和使用Data URI来编码图片。
文件压缩:目的是直接减少文件体积,减少文件加载时间
使用 CDN (内容分发网络)来托管资源。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。从而使用户就近取得数据,提升浏览网站的速度。
使用缓存(并且多个域名来提供缓存),可以减少服务器请求的次数,加快加载速度。
服务端开启GZIP 压缩,对用户请求的页面进行压缩处理,以达到节省网络带宽,提高浏览网站速度的作用

6. position有哪些属性和区别

position主要有 relative、absolute、fixed这几个属性,默认是static属性
区别是:relative相对定位不会脱离文档流,元素本身相对自身原位置进行偏移。
absolute和fixed会脱离文档流,且这两个定位时是根据定位父级进行定位,如果没有定位父级,则相对于文档定位。
都有left/right/bottom/top四个属性,relative的这四个属性代表向哪里移动的距离,absolute和fixed的这个属性,代表距离左边的距离,即向相反方向移动的距离。
static 代表正常的文档流,static和fixed的区别是,fixed定位的元素不随页面的滚动而滚动。

7. 浏览器字体<12px如何设置?

Zoom 非标属性,有兼容问题,缩放会改变了元素占据的空间大小,触发重排

      .span1 {
            font-size: 12px;
            display: inline-block;
            zoom: 0.8;
        }
        .span2 {
            font-size: 12px;
        }
        
        <span class="span1">测试10px</span>
        <span class="span2">测试12px</span>

transform:scale() 大部分现代浏览器支持,并且对英文、数字、中文也能够生效,缩放不会改变了元素占据的空间大小,页面布局不会发生变化

       .span3 {
            font-size: 12px;
            display: inline-block;
            -webkit-transform:scale(0.8);
        }
        .span4 {
            font-size: 12px;
            display: inline-block;
        }
        
       <span class="span3">测试10px</span>
       <span class="span4">测试12px</span>

8. BFC的理解

BFC是块级格式化上下文,内部的布局不会影响外部的整体布局,属于一个独立的区域。视为具有块级元素的属性。
BFC的应用/开启BFC:
清除浮动:父元素高度塌陷时,给父元素加上visibility:hidden,即可将父元素包裹的盒子变成BFC形式,从而父元素高度就不再塌陷了。
开启BFC的一些属性:overflow:hidden/auto; float:left;[会导致元素只占自身大小,宽度丢失,不推荐] display:inline-block;[元素只占自身大小,宽度丢失,不推荐]
BFC的应用2:当两个盒子一个设置了margin-top一个设置了margin-bottom,垂直方向只有大的那个生效,要想要两个都生效,可以分别给两个盒子外层嵌套一个div.container,将div.container加上visbility:hidden,高度重叠问题将得到解决。

9. 页面垂直居中的方法有哪些,如何实现?

    <style>
/* 弹性盒 */
        .out{
            display: flex;
            align-items: center;
        } 
/* margin回移(必须知道宽高) */
        .out{
            position: relative;
        }
        .box{
            position: absolute;
            top: 50%;
            margin-top: -100px;
        } 
/* 定位取值0法(必须有宽高,否则铺满全屏) */
        .out{
            position: relative;
        }
        .box{
            position: absolute;
            left: 0;
            right: 0;
            top: 0;
            bottom: 0;
            margin: auto;
        } 
/* translate -50%法 */
        .out{
            position: relative;
        } 
        .box{
            position: absolute;
            top: 50%; 外盒子的一半 
            transform: translateY(-50%);回移自身的50%
        } 
/* display:table-cell方法 */
        .out{
            display: table-cell;
            vertical-align: middle;
        }
    </style>

<body>
    
    <div class="out" style="width: 500px;height:500px;border:1px solid #000;">
        <div class="box" style="width: 200px;height: 200px;background-color: #0f0;"></div>
    </div>
</body>

10. flex布局了解吗,讲讲?

在这里插入图片描述
子项目之间的间隙用margin处理即可。
flex布局适合于移动端布局。有主轴和交叉轴两个轴
采用flex布局的元素,称为flex容器,简称容器。它的所有的子元素自动称为容器成员,称为flex项目,简称项目。div就是flex父容器,span就是子容器flex项目,子容器可以横向排列也可以纵向排列
总结:flex布局原理:就是通过给父盒子添加flex属性,来控制子盒子的位置和排列方式
在这里插入图片描述
在这里插入图片描述

有一个有名的圣杯布局:

    <style>
        .out{
            width: 80%;
            height: 500px;
            margin: 0 auto;
            border: 1px solid #000;

            display: flex;
        }
        .in{
            display: inline-block;
            height: 500px;
        }
        .in:nth-child(1),.in:nth-child(3){
            /* 1\3 盒子宽度固定*/
            width: 50px;
            background-color: blueviolet;
        }
        .in:nth-child(2){
            flex: 1; /*自适应宽度: 占据剩余空间 */
            background-color: blue;
        }
    </style>
    
    <body>
	    <div class="out">
	        <span class="in">1</span>
	        <span class="in">2</span>
	        <span class="in">3</span>
	    </div>
	</body>

圣杯布局:两边宽度写死,中间盒子宽度自适应,自适应宽度通过弹性盒的flex:1这种实现的,因为flex属性可以自动的分配剩余空间,此处相当于2号盒子直接占据整个剩余空间。
在这里插入图片描述

11. 如何获得当前域名?

1、方法一

  var domain = document.domain;

2、方法二

  var domain = window.location.host;

二、获取当前Url的4种方法
  var url = window.location.href;

  var url = self.location.href;

  var url = document.URL;

  var url = document.location;

  ie 地址栏显示的是什么,获取到的 url 就是什么。

12. 流式布局如何实现,响应式布局如何实现

移动端浏览器对新特性的支持更好,兼容性只考虑webkit内核即可
移动端屏幕尺寸不同
视口:是浏览器显示页面内容的屏幕区域,视口可以分为布局视口、视觉视口、理想视口
我们写的网页应该根据实际手机的视口宽度而自动进行缩放,设备有多宽,我们布局的视口就有多宽。布局视口的宽度应该与理想视口一致。【meta视口标签】
在这里插入图片描述
单位:在pc端1px=1个物理像素 在移动端1px不一定=1个物理像素
在这里插入图片描述
流式布局:百分比布局,主要是宽度要设置为百分比形式,高度单位可以是px,高度需要随着屏幕变化的话,可以用rem单位

	<title>流式布局,就是百分比布局</title>
    <style>
        .out{
            width: 100%;
            height: 500px;
            /* 这两个属性是为了让它不无限伸缩 */
            /* 浏览器视口宽度>980px就不会再放大了 */
            max-width: 980px;
            /* 浏览器视口宽度<320px就不会再缩小了 */
            min-width: 320px;
        }
        .in{
            float: left;
            width: 50%;
            height: 100%;
        }
        .in:nth-child(1){
            background-color: pink;
        }
        .in:nth-child(2){
            background-color: blue;
        }
    </style>

<body>
    <div class="out">
        <div class="in">1</div>
        <div class="in">2</div>
    </div>
</body>

运行结果:流式布局随着视口变化等比例缩小
在这里插入图片描述
文字大小随着屏幕大小变化:rem单位(相对于根元素的字体大小设置大小的单位)
媒体查询:可以根据不同尺寸设备设置不同样式

 /* <700px */
        @media screen and (max-width: 700px){
            body{
                background-color: blue;
            }
        }
 /* >200 <500 */
        @media screen and (min-width: 200px) and (max-width: 500px){
            body{
                background-color: aquamarine;
            }
        }

媒体查询配合rem单位实现文字大小适配:

	<style>
 		@media screen and (min-width: 320px){
            html{
                font-size: 50px;
            }
        }

        @media screen and (min-width: 640px){
            html{
                font-size: 100px;
            }
        }


        .text{
            height: 1rem;  // 1rem=(1*font-size)px
            font-size: .5rem;
            background-color: green;
            color: #fff;
            text-align: center;
            line-height: 1rem;
        }
    </style>

	<body>
	    <div class="text">我是文字</div>
	</body>

运行结果:可以看到文字也随页面缩放了
在这里插入图片描述
响应式布局:BootStrap框架,基于媒体查询实现的布局,一套代码适配多个屏幕
在这里插入图片描述

13. CSS预处理器

less scss都是css预处理器,他们都有相关的文档有语法规范。
他们可以使得css样式书写简化,选择器有层次嵌套,还有变量(方便样式统一修改),可以通过vsCode中的easy less 和 easy sass插件,通过ctrl+s保存后,即可转化成正常的css样式。它有计算功能,可以方便单位转化,比如html{font-size:50px;} 问一个元素在设计稿中是82px,它是多少rem? 1rem = 50px => 82px = ?rem = 82 / 50rem这种单位可以使用计算来得到。
在这里插入图片描述
在这里插入图片描述

14. CSS3的新特性有哪些

	圆角 (border-radius:8px)
	多列布局 (multi-column layout)
	阴影和反射 (Shadow\Reflect)
	文字特效 (text-shadow、)
	文字渲染 (Text-decoration)
	线性渐变 (gradient)
	旋转 (transform)

15. 你了解的浏览器的重绘和回流导致的性能问题

回流必定会发生重绘,重绘不一定会引发回流。
在这里插入图片描述

16. 优雅降级和渐进增强

渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,
完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。

优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器
测试和修复。比如一开始使用CSS3 的特性构建了一个应用,然后逐步针对各大浏览器进行
hack 使其可以在低版本浏览器上正常浏览。

其实渐进增强和优雅降级并非什么新概念,只是旧的概念换了一个新的说法。在传统软件开发中,
经常会提到向上兼容和向下兼容的概念。渐进增强相当于向上兼容,而优雅降级相当于向下兼容

17. px rpx em rem vw等单位的了解

px:像素单位
rpx:由微信小程序官方推出的新单位,适用于移动端的 uni-app或者微信小程序的开发。
1rpx实际上等于相对于屏幕宽度的1物理像素。在设计时可以将1px约等于2rpx。
em:相对于父元素字体大小而言的大小
rem:相对于根元素字体大小而言的大小【css3的单位】
vw:1%的视口宽度,视窗宽度1vw等于是窗宽度的1%。也就是说,如果当前开发浏览器或者设备的宽度为1280px,那么1vw就等于12.8px。在开发设计的过程中,100vw才能真正占据当前屏幕宽度的100%。【css3的单位】

【程序题】

点我跳到css 点我跳到顶部 点我跳到vue

1. [“1”, “2”, “3”].map(parseInt) 返回的结果为()

答案:【1,NaN,NaN】
答案详解: https://zhuanlan.zhihu.com/p/457662291

2. 以下代码运行结果:

         const promise = new Promise((resolve,reject) => {
            console.log(1);
            setTimeout(() => {
                console.log("timerStart");
                resolve("success");
                console.log("timerEnd");
            }, 0);
            console.log(2);

        })
        promise.then((res) => {
            console.log(res);
        });
        console.log(4);
------------------------------------------------------------------------------        
>>> 运行结果:1  2  4  "timerStart"  "timerEnd"  "success"
>>> 原因:
>Promise内部的代码仍然是同步执行代码,它的then和catch才会被推入微任务队列。
>因此输出1,将setTimeout推入宏任务队列,再输出2。
>接下来看到Promise.then,然而我们此时并不能将其推入微任务队列,它此时还是pedding状态,
>定义它的promise还并未执行resolve或者是reject,先不执行它。因此接下来输出的是4。
>接下来查看微任务队列,无,再查看宏任务,有,输出timerStart,将该promise状态改为resolved
>并将之前的promise.then推入微任务队列,输出timerEnd。
>该宏任务执行完毕。执行完一段宏任务后查看微任务队列,有,输出success。

3. js的浮点数有精确度问题

浮点小数计算精度问题:
0.8 - 0.6 != 0.2 以及经典的 0.2 + 0.1 != 0.3

 <script>
        var two = 0.2;
        var one = 0.1; 
        var eight = 0.8; 
        var six = 0.6; 
        console.log([two - one == one, eight - six == two]); // true false
  </script>

4. 以下代码的输出结果,考察promise的理解

        Promise.reject('err!!!')
            .then((res) => {
                console.log('success', res)
            }, (err) => {
                    console.log('error', err)
                })
            .catch(err => {
                console.log('catch', err)
            })
            
   >>> 运行结果:error err!!!
   >>> 因为reject()函数表示失败的回调函数,会进入.then(),.then中的res接收的是resolve()成功后的回调函数返回的结果,err接收的是reject()失败后返回的结果。
   >>>只有.then()中抛出问题才会到.catch()去执行

5. 写一个数组去重的方法

6. js实现日期/时间戳转换

// 时间戳转日期 --- 为了方便,这里直接拿总毫秒数来作为时间戳处理
// 若使用总秒数时间戳,需要 timestamp = timestamp * 1000 
        function timestampToTime(timestamp){
            var date = new Date(timestamp); // 时间戳对应的utc格式的日期,date是实例化对象
            var Y = date.getFullYear(); // 年
            var M = date.getMonth()+1; // 月
            var D = date.getDate(); // 日
            var h = date.getHours(); // 时
            var m = date.getMinutes()>=10 ? date.getMinutes():"0"+date.getMinutes(); // 分
            var s = date.getSeconds()>=10 ? date.getSeconds():"0"+date.getSeconds(); // 秒
            return Y +"-"+M+"-"+D+" "+h+":"+m+":"+s;
        }

        var currentTime = timestampToTime(1605305889755);
        console.log(currentTime);

7. 添加、删除、替换、插入节点的方法

 1      // 获取元素
 2     var div=document.getElementById("div1");
 3     // 创建元素,给元素添加些文字
 4     var p=document.createElement("p");
 5     p.innerHTML="添加1";
 6     var p1=document.createElement("p");
 7     p1.innerHTML="添加2";
 8     var p2=document.createElement("p");
 9     p2.innerHTML="添加3";
10     // 添加到div中
11     div.appendChild(p); // 添加
12     div.insertBefore(p1,p); // 插入
13     div.insertBefore(p2,p1);
14     // 删除p1
15     div.removeChild(p1); // 删除
16     // 将p2替换为p
17     div.replaceChild(p,p2); // 替换

8. 哪个属性能够实现层的隐藏

display:none

9. js中parseInt(“X8X8”)+parseFloat(“8”)结果是多少

    console.log(parseInt("X8X8"));  // NaN
    console.log(parseFloat("8")); // 8
    console.log(parseInt("X8X8")+parseFloat("8"));  // NaN

10. 以下代码弹出框弹出的值为多少?

	function b ( x , y , a ){
		arguments [ 2 ] = 10 ; 
		alert ( 2 );
	}
	b ( 1 , 2 , 3 )
	>>> 弹出:2   

    function b ( x , y , a ){
        arguments [ 2 ] = 10 ;
        alert ( a );
    }
    b ( 1 , 2 , 3 )
    >>> 弹出:10
    
   function b ( x , y , a ){
        a = 10 ;
        alert ( arguments [ 2 ]); // 10
    }
    b ( 1 , 2 , 3 )
    >>> 弹出:10

答案解析:
 function b ( x , y , a ){
        console.log(arguments);  //  Arguments(3) [1, 2, 3]
        arguments [ 2 ] = 10 ;
        console.log(arguments);  //  Arguments(3) [1, 2, 10]
        alert ( a );
   }
 b ( 1 , 2 , 3 )

11. 手写Ajax操作

        // 1.创建xhr对象
        var xhr = new XMLHttpRequest();
        // 2.准备数据,准备发送请求
        xhr.open('get','http://xxx.com')
        // 发送请求
        xhr.send(),
        // 3.事件监听
        xhr.onreadystatechange = function(){
            // 4.监听前后端交互状态
            if(xhr.readyState === "4"){ // 4代表请求完成了
                if(res.state === "200"){
                     // 成功了,打印响应文本
                     console.log(xhr.responseText);
                }else{
                     // 打印失败时的状态文本
                     console.log(xhr.statusText);
                }
            }
        }

12. 用Vue实现一个下拉框组件,要求不使用elementUI等组件库实现,效果要点击哪个选项将它放入输入框中显示

<!DOCTYPE html>
<html lang="en">

<head>
	// xxx省略了一些meta标签代码
    <title>用view实现一个下拉框</title>
    // 引入vue资源
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

</head>

<body>
    <!-- 准备一个容器 Vue模板-->
    <div id="app">{{ message }}
        <form>
            <input type="text"  :value="item">
            <span @click="clickHandle">&gt;</span>
            <div v-if="flag">
                <ul v-for="(item,index) in data" @click="clickLiHandle(item)">
                    <li>{{ item }}</li>
                </ul>
            </div>
        </form>
    </div>

    <script>
        // 创建vue实例  1个Vue实例只能对应1个实例   
        var app = new Vue({
            // el:元素 css的id选择器  
            el: '#app', // el用于指定当前vue实例为哪个容器服务,值通常为css选择器字符串
            // data中用于存储数据,供el所指定的容器去使用
            data: {
                message: 'Hello Vue!',
                data:['Jack','Lucky','Tom'],
                flag: false,
                item:''
            },
            methods:{
                clickHandle(){
                    this.flag = this.flag == true ? false : true;
                },
                clickLiHandle(item){
                    console.log(item)
                    this.item = item;
                    console.log(this.item)
                }
            }
        })
    </script>
</body>

</html>

在这里插入图片描述

13. 这段代码的输出结果

        (function () {
            var a = b = 10; // 相当于var a = 5; b = 5;
            // 函数外部读不到a这个局部变量
        })()
        console.log(typeof a, b) // undefined 10
        >>> 输出结果:undefined 10

14. var data = [ 8 , [ 3 ,[ [ 7 , 4 ], 5 ], 6 ]];转换成一维数组

15. 两个没有刻度的水桶,容量分别为4升和9升,如何盛出6升水 ?(算法,说出逻辑即可)

答案:链接: https://jingyan.baidu.com/article/9158e0005b8dcfe35512287a.html

16. 在 String 对象上定义一个 repeatify 函数。这个函数接受一个整数参数,来明确字符串需要重复几次。例如:console.log(‘hello’.repeatify(3))应该打印出 hellohellohello 。

17. 定义一个函数 spacify,将一个字符串作为参数传入,然后返回一个字符串,不过该字符串相对传入参数的变化是字母与字母之间多了一个空格。(如 ∶spacify( ‘hello world’ ) //=>'helloworld)

18. 以下代码输出结果是?

var nodes =document.getElementsByTagName('button');
        for (var i = 0; i < nodes.length; i++) {
            nodes[i].addEventListener('click', function(){
                console.log(i); // 4 4 4 4
            })
        }
 >>> 输出结果: 4 4 4 4 

19. 以下代码打印结果?(考察this指向问题)

    var fullname = ' 李雷 ';
    var obj = {
        fullname: ' 韩梅梅 ' ,
        prop: {
            fullname: ' 汤姆 ' ,
            getFullname: function () {
                return this.fullname;
            }
        }
    }
    console.log(obj.prop.getFullname()); // 汤姆
    var test = obj.prop.getFullname; // 李雷
    console.log(test());
    >>> 汤姆 李雷

20. 定义一个 log 方法,让它可以代理 console.log 的方法。

21. 定义一个sort 方法,将指定数组按照顺序重新排列,如: [ 10 , 2 , 4 , 5 , 7 , 34 ] => [ 2 , 4 , 5 , 7 , 10 , 34 ]

22. 请使用原生 JS实现一个简单的图片懒加载功能(可提供思路)

23. 请写出 js继承

24. 以下代码的打印结果?

因为var有变量提升,let没有变量提升

var name = 'Tom' ;
( function () {
	if ( typeof name == 'undefined' ) {
		name = 'Jack' ;
		console . log ( 'Goodbye ' + name );
	} else {
		console . log ( 'Hello ' + name );
	}
})();
>>> 输出: Hello Tom

        var name = 'Tom';
        (function () {
            if (typeof name == 'undefined') {
                var name = 'Jack';
                console.log('Goodbye ' + name);
            } else {
                console.log('Hello ' + name);
            }
        })();
   >>> 输出: Goodbye Jack

        var name = 'Tom';
        (function () {
            if (typeof name == 'undefined') {
                let name = 'Jack';
                console.log('Goodbye ' + name);
            } else {
                console.log('Hello ' + name); // Hello Tom
            }
        })();
   >>> 输出: Hello Tom

25. 以下代码的输出结果

        var a = [1, 2]
        var b = [1, 2]
        console.log(a + b); // 1,21,2

在这里插入图片描述

【vue】

点我跳到顶部 点我跳到css 点我跳到程序题

1. MVVM 框架是什么?说说对双向数据绑定的理解?他和其他框架(MVC框架)的区别是什么?

MVC框架中,View可以直接访问Model!View里会包含Model信息,还可能包括一些业务逻辑。
在MVC模型里,Model不依赖于View,但是 View是依赖于Model的。因为有一些
业务逻辑在View里实现了,导致要更改View也是比较困难的。

MVVM框架中,View的改变会导致Model的改变,Model的改变也可以导致View的改变,
它的逻辑是通过中间的ViewModel来实现双向数据绑定,ViewModel中可以监听数据的变化。
由于数据双向绑定,开发人员就不用一次次的操作DOM来更新视图了,只需要关注简单的业务逻辑。

Vue的MVVM模型的理解
MVVM模型(Model-view-viewModel)是一种软件架构模式。
Vue的模型是参考MVVM模型进行设计的。
M(Model)模型--- 对应data中的数据
V(View)视图 ---- 页面结构
VM(ViewModel)视图模型 --- Vue的实例化对象 --- 所以vue的实例对象用vm表示
【双向数据绑定】:数据的修改可以映射在视图上,视图的表单中修改数据能映射回data上

数据劫持监听数据的变化,配合订阅者和解析器来实现。主要是数据劫持比较重要,可能会问。

在这里插入图片描述

2. Vue中的Object.defineproperty()

    <script> 
        // Object.defineproperty()是ES6的内容  --- 作用拦截对象,为对象增加新的属性
        var Person = {
            name: 'Tom',
            sex: 'boy'
        }
        // 通过它添加的属性,不能被遍历到
        Object.defineProperty(Person,'age',{
            value: 18,
            enumerable: true, // 加上这个属性就可以被遍历到了,默认是false
            writable: true, // age的值可以被修改,默认是false
            configurable: true // 控制属性是否可以被删除,默认是false
        })
        console.log(Person); // {name: 'Tom', sex: 'boy', age: 18}
    </script>

getter 和 setter

    <script> 
        // Object.defineproperty()是ES6的内容  --- 作用拦截对象,为对象增加新的属性
        // Person对象
        var Person = {
            name: 'Tom',
            sex: 'boy'
        }
        let number = 22; // 初始化年龄
        Object.defineProperty(Person,'age',{    
            //【getter】 当读取Person的age属性时,get函数(getter)会被调用,且返回值是age的值
           get(){
            console.log("有人读取了age属性")
            return number;
           },
            // 【setter】当修改Person的age属性时,set函数(setter)会被调用,且会收到具体值
           set(value){
            console.log("有人修改了age属性,值是",value);
            number = value;
           }
        })
        console.log(Person); 
    </script>

在这里插入图片描述

3. Vue中的数据代理—即在B对象中读和写A对象的属性和方法

Vue中的数据代理:通过vm对象来代理data对象中属性的操作(读/写)
Vue中数据代理的好处:更方便操作data中的数据
基本原理:
	通过Object.defineProperty()把data对象中所有属性和方法添加到vm上,
	为每一个添加到vm上的属性,都指定一个getter和setter
	在getter/setter内部操作(读/写)data中对应的属性
 <script>
        // 【数据代理的定义,在obj2中也要能读写obj1的内容】---通过obj2代理obj1
        let obj1 = {x:100}
        let obj2 = {y:200}

        // obj2读写obj1中的x属性
        Object.defineProperty(obj2,'x',{
            get(){
                return obj1.x
            },
            set(value){
                obj1.x = value
            }
        })
    </script>

在这里插入图片描述

vue中的vm实例化对象中有个属性 _data,这里面存放的是我们在data中定义是数据。数据代理就是把data中的数据放到了vm身上,通过vm操作数据的getter和setter,来实现双向绑定

4. Vue中的数据劫持

5. Vue中父子组件如何传值 ( 父传子,子传父 )

父传子:props【单向数据流】【对象和数组的默认类型必须是工厂函数方式】

父组件
    <!-- 父级中的数据传递 -->
    <Child :message="message" :age="age" :list="list"/>
子组件
	export default {
	  // 子级名字
	  name:"Child",
	  // 子级中用props读取父级传递过来的数据
	  // props:["message","age"]
		  props:{
		    message:{
		      type:String,
		      // required是必选项,不传会报警告
		      required:true
		    },
		    age:{
		      // type:Number,
		      // age可以既接收number又接收string
		      type:[Number,String],
		      // 当age没有传值的时候,页面默认显示age为0
		      default:0
		    },
		    // 数组和对象的默认值写法: default:[]这种写法错误 -> 工厂模式
		    // 数字和字符串可以直接写:default:0  default:""
		    list:{
		      type:Array,
		      default:function(){
		        return []
		      }
		    }
	  }
	}

子传父:自定义事件 $emit (自定义事件)

子组件
   <button @click="chickHandle">发送数据给parent</button>
    methods:{
        chickHandle(){
            this.$emit("onEvent",this.message)
        }
    }
    
父组件
   <Child2 @onEvent="messageHandle"/> // 实现子组件传递过来的事件
    methods:{
       // data为onEvent事件所传递过来的this.message就是参数
	   messageHandle(data){
	      this.child2Data = data;
	   }
	},

6. vue 如何实现父子组件通信,以及非父子组件的通信参考

参考博客:参考博客
1eventbus(适合小型项目) 2 provide inject(父传子) 3props(父传子) 4emit自定义事件(子传父) 5 vuex(大型项目)

7. 说说你对Vuex的理解,它有哪几种属性

vuex是一个综合管理程序中数据的一个插件,它的核心是一个store,其中数据存放在state中,被称为状态。用户触发页面事件时,通过dispatch分发给actions,actions执行完这个异步操作将结果拿到并通过commit提交给mutations,mutations中对数据进行修改,通过mutate让state中数据状态发生变更,state通过render重新渲染页面数据呈现给用户
主要属性:state mutations actions getters modules
state:存储项目中要用的数据
mutations:里面放同步操作,对数据进行修改
actions:里面放异步操作,通过context对象将获取到的异步数据commit提交给mutations进行修改
getters:相当于一个数据过滤器,对数据进行过滤后显示
module:为了防止主模块中state mutations ations getters等函数中内容过多,而划分不同的模块来写各个模块的state mutations actions getters,以及加入namespace命名空间,这样即使方法同名也互不影响。

8. vue 生命周期 ? 写出其生命周期钩子函数以及作用

在这里插入图片描述

9. 写出至少4中vue当中的指令和它的用法

v-if与v-else配合来控制切换
v-show来控制元素的显示隐藏
v-for用于循环创建标签等,语法的item in items

//  src / directives / index.js
 import Vue from 'vue'

// 使用v-focus来使用这个指令
// v-focus
  Vue.directive('focus', {
    // inserted是指令提供的,相当于指令的生命周期
    // inserted自定义指令的钩子函数
    // inserted函数表示当绑定了该指令的元素被插入到dom时候会自动触发
    inserted(el){
      console.log(el); // HTML元素对象--当前元素对象
      el.focus();
    }
  })

// v-red
  Vue.directive('red',{
    inserted(el){
      el.style.color = "#ff0000";
    }
  })

// main.js 
import './directives'  // 全局自定义指令,在所有组件中生效

// 其他组件中,直接以 “v-..” 形式使用
<input type="text" v-focus>
<p v-red>Hello</p>

10. vue-router有哪几个导航钩子,也就是生命周期

const router = new VueRouter({
  routes,
})

// 1 【全局前置导航守卫】 --- 所有的路由跳转都会触发这个函数
router.beforeEach((to, from, next) => {
  // console.log(from); // 从哪个页面
  console.log(to); // 跳转到哪个页面
  // some来进行遍历
  if(to.matched.some(record => record.meta.requiresAuth)){
    // 需要判断用户是否登录
    // 用户是否已经登录
    //token为true代表用户已经登录了,token为false代表用户未登录,则要进入about页面会进入登录页面,登录之后才能进入
    const token = true;  // token之后再讲,这里先把数据写死
            // if(token){
            //   next(); // 进入当前页面
            // }else{
            //   // 如果用户未登录,那我们就进入login页面
            //   next("/login"); // 进入登录页面进行登录
            // }
    // 注释掉的if...else..这段,可以改成三目运算符实现,代码更优雅
    token ? next() : next('/login');

  }else{
    next(); // 必须要调用,否则不跳转 // next中可以指定跳转到哪个页面中
  }
})
// 2 【全局后置导航守卫】 --- 完成时触发 --没有next参数,是因为都已经跳转完成了
router.afterEach((to, from) => {
   console.log(from);
   console.log(to);
 })
export default router
 {
    path: '/about/:id',
    name: 'about',
    component: () => import( '../views/AboutView.vue'),
    // 3. 【路由独享的导航守卫】--- 只有进入about页面才会触发该导航守卫
    beforeEnter: (to, from, next) => {
      // console.log(from);
      // console.log(to);
      next(); // 不调用next会无法跳转
    },
【组件中的钩子函数】
<script>
export default {
  data(){
    return{
      message:"测试数据message"
    }
  },
  beforeRouteEnter(to, from, next) {
    // 因为当守卫执行前,组件实例还没被创建,所以没有this
    // 不过,你可以通过传一个回调给 next来访问组件实例vm。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
    // console.log("beforeRouteEnter内-this存在与否",this);
    // console.log("beforeRouteEnter-from",from);
    // console.log("beforeRouteEnter-to",to);
    next(vm => {
      // console.log(vm.message);
    });
  },
  beforeRouteUpdate(to, from, next) {
    // console.log("beforeRouteUpdate内-this存在与否",this);
    // console.log("beforeRouteUpdate-from",from);
    // console.log("beforeRouteUpdate-to",to);
    next();
  },
  beforeRouteLeave(to, from, next) {
    // console.log("beforeRouteLeave内-this存在与否",this);
    // console.log("beforeRouteLeave-from",from);
    // console.log("beforeRouteLeave-to",to);
    next();
  },
  methods:{
    // 参数发生变化时,触发的是beforeRouteUpdate
    gotoSelfHandle(){
      this.$router.push("/about/1002")
    }
  }
}

11. axios的特点有哪些

axios七大特点
1、在浏览器中发送 XMLHttpRequests 请求;
2、在 node.js 中发送 http请求;
3、基于 promise 的 HTTP 库,支持promise所有的API
4、拦截请求和响应;(修改请求数据,只能用’PUT’,'POST’和’PATCH’这几个请求方法)
5、转换请求和响应数据,响应回来的内容自动转换;
6、自动转换 JSON 数据;
7、客户端支持保护安全免受 XSRF 攻击;

12. 路由跳转的时候原来的页面去哪了?

当我们做一些查询或者翻页操作后,进行了路由的跳转,当我们返回到起始页面时发现,数据已经回到了初始状态。
解决方法:经过对比,决定将数据保存在sessionStorage中。
解决方法的原因:
1- 仅在当前会话下有效,浏览器被关闭或当前页面被关闭的情况下清除。存储的记录将不会对下次开启页面的查询或操作产生影响。
2- 使用简单,存取方便。
3- 只存在于客户端(浏览器)中,不参与和服务器的通信。
参考博客:参考博客点击跳转

还有就是可以通过keep-alive组件保持组件数据状态

13. 聊聊懒加载和预加载

14. 优化首屏加速

代码简洁
引入CDN
懒加载,视频音频取消自动播放
使用按需加载
js放在底部引入,防止async阻塞
服务器启用gzip压缩

15. 父孙组件通信方式

provide和inject
参考博客:参考博客

16. 引入第三方组件库并自行封装一个table

17. vue的路由模式(hash和history)及区别?

hash模式网址中有#,history模式需要后台做重定向,增加了服务器开发人员的工作量。

18. hash路由和history路由实现原理说一下

19. 谈谈你对webpack的理解

20. v-if和v-show都可以控制显示和隐藏,请说明他们的区别

v-if是DOM元素的添加和删除,v-show是通过控制display:block、none;来进行显示 和隐藏。所以v-if切换开销较高。v-show渲染开销较高,若切换不频繁,可以使用v-if,若切换频繁就使用v-show。

21.数组更新和对象更新

pop/push/shift/unshift这些数组方法会更新原数组,而filter/concat/slice不会更新原数组,所以数组的更新需要重新对该数组进行赋值操作。
更新对象的话,需要用Vue.set() $set()两种方案
Vue.set(this.userInfo,'job','it') // 工作是it这个项加到userInfo对象中

this.$set(this.userInfo,'job','it')

22.v-model是表单的双向绑定,何为双向绑定?

v-bind:value=“msg” v-on:input=“事件名”
实现事件名的函数中,拿e.target.value来拿到表单中输入的值

23.计算属性和侦听器的区别,计算属性和methods的区别

计算属性computed: 本质上是一个属性,有setter和getter,第一次会调用执行,后面若依赖的数据不发生变化会直接读取第一次执行的结果返回,而不去执行内部代码。调用时不需要加()
侦听器 watch:监听data中某一个属性的变化,一般进行异步操作
methods:每次被调用都会被执行,调用需要加()

24.组件的组成

组件中包含一个代表html结构,代表js业务逻辑, 中代表CSS样式。style中的scoped代表当前样式的作用域只在当前组件生效,它的原理是会被编译成一些data-xxx的唯一标识,通过这些标识来指定样式的唯一性。

25.data(){return{}}中的data为什么需要是函数?是对象不行吗?

data()是函数的话,可以保证实例化时是相互独立的组件,不共享内存空间
而且代码具有可复用性
如果data是对象,那么共享的是一块内存空间,那么数据会在多个组件中共用,会污染全局环境

26.插槽 往B组件传递A组件的html结构

// A组件中(在A组件中引入并注册B组件)
<B组件名>
	<div>我是A组件中的一段HTML结构</div>
</B组件名>
// B组件中接收这段结构
  <slot>默认值</slot>
具名插槽
// A组件中(在A组件中引入并注册B组件)
	<B组件名>
		<template v-slot:header>
	        <div>我是A组件中的头部结构</div>
	    </template>
	    <!-- v-slot: 可以简写为  # -->
	    <template v-slot:footer>
	        <div>我是A组件中的底部结构</div>
	    </template>
	</B组件名>

// B组件中接收这段结构
 	<slot name="header"></slot>
 	好处是两个插槽中间可以插入其他本组件自己的结构 
    <slot name="footer"></slot>
作用域插槽:通过插槽传值到父级进行显示
// A组件中(在A组件中引入并注册B组件)
	<B组件名>
			<template v-slot:header>
		        <div>我是A组件中的头部结构</div>
		    </template>
	  <!-- <template v-slot:footer="slotProps">    -->
      <!-- v-slot: 可以简写为  # -->
	      <template #footer="slotProps">
	        <div>底部测试:{{ slotProps.message }}</div>
	      </template>
	</B组件名>
	
// B组件中接收这段结构
 	<slot name="header"></slot>
 	// message就是传过去的值
    <slot name="footer" :message='message'></slot>

27.如何获得原生的DOM节点?

      <p ref="container">Hello ref</p>
      // 获得p节点
      console.log(this.$refs.container);

28.nextTick

29. vue登录验证流程

登录流程:前端用表单收集用户输入的用户名和密码,将用户输入的用户名和密码提交给后台服务器端进行验证,后台验证成功的话,生成一个token令牌返回给前端,前端拿到token数据将其存放在localStorage中,并且配置路由进行页面跳转。
为什么要生成token返回?因为用户名和密码不能明文存储,容易被劫持造成数据泄漏,所以需要后台对数据进行处理,将处理后的数据返回前端。
nodejs中后台如何生成token字段?通过jwt鉴权(需要安装jsonwebtoken依赖)来生成。jwt中对用户名和相关信息(这些信息中不能放密码,密码不能对外暴露)进行加密处理,生成token字段。

token的格式:
在这里插入图片描述

vuex和本地localStorage中都要存储token,因为为了防止刷新浏览器造成数据丢失,如果只存在vuex中,那么刷新浏览器就会重新获取token,无法实现页面跳转。
参考博客点我跳转

30. 注册时候要对输入的信息进行验证

31. 退出登录时要做的事情

    退出登录:要清除本地存储的token; 要清除vuex中的存储的token
methods: {
    ...mapMutations("loginModule", ["clearToken"]),
    logout() {
      /**
       * 1. 存储方式:存储在Vuex
       * 2. 存储在本地localStorage
       */
      // 1 清空vuex中的token
      this.clearToken();
      // 2 清空本地存储的token,localStorage中清空token令牌,代表用户退出登录了
      localStorage.removeItem("token");
      // 3 点退出就跳转到登录页
      this.$router.push("/login");
    },
}

32.vue2和vue3响应式的区别

相对于Vue2.0,Vue3.0重构了响应式系统,使用Proxy替换Object.,那现在,为什么要用Proxy替换掉Object.defineProperty?
我们先来看一下Object.defineProperty存在着哪些弊端:
1、Object.defineProperty无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实时响应。 push()pop()shift()unshift()splice()sort()reverse()
2、但尽管如此,由于只针对以上八中方法进行hack处理,所以其他数组的二属性也是检测不到,存在很大的局限性。Object.defineProperty只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。Vue 2.x里,是通过 递归 + 遍历 data 对象来实现对数据的监控的如果属性值也是对象那么需要深度遍历,显然如果能劫持一个完整的对象是才是更好的选择。
3、相比之下,Proxy的优点就非常明显了:它可以劫持整个对象,并返回一个新的对象,有13种劫持操作,可直接监听数组类型的数据变化,监听的目标为对象本身,不需要像Object.defineProperty一样遍历每个属性,有一定的性能提升,直接实现对象属性的新增/删除,可以说非常nice了

33.vue-router的三种模式

34.vue-cli的三种模式

35.实现实时通讯的方式,除了websocket和长轮询还有哪些?比如uniapp中的哪个?

36.git你们在开发时有几个分支?

主要有三个分支:开发环境分支 测试环境分支 生产环境分支
Link参考博客

37.遇到git冲突怎么办?

Link参考博客

【小程序/uniapp】

点我跳到顶部 点我跳到css 点我跳到程序题

1. 小程序有哪些组件,可以说说吗?

view  视图 --- 相当于div盒子
text 文本  --- 相当于span标签
button 按钮
block  
image 图片 --- 图片默认有固定大小,需要通过设置mode来进行图片设置
video 视频   audio 音频
swiper 轮播图
scroll-view 滚动视图
icon 字体图标
progress 进度条
slider 滑块选择器
form表单
input输入框
textarea文本框
picker 底部弹起的选择器
slider 滑块选择器
switch 开关
navigator 路由跳转
carema 相机
map 可以使用腾讯地图插件

2. 小程序的路由跳转方式?

wx.navigateTo  有回退箭头
wx.redirectTo    会关闭当前页面
wx.reLaunch     关闭所有页面
wx.switchTab    可跳转底部导航tabbar页面

wx.showToast   消息提示框
wx.showToast(icon:"loading")  消息加载框
wx.showLoading() / wx.hideLoading()  加载框不会主动消失,而消息提示框会主动消失
wx.showModel()    模态对话框
wx.showActionSheet() 底部弹出框
wx.iploadFile() 上传文件  success回调函数中就可以显示上传成功提示

3. 小程序的网络请求

wx.request() --- request是小程序专门用来实现网络请求的解决方案,其中method可以指定请求方式get/post,有success和fail和complete这些回调函数。在complete这个回调函数代表网络请求完成无论成功或失败都会调用,所以在这个里面进行隐藏loading加载框。
// pages/allrequest/allrequest.js
Page({
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    wx.request({
      url:'http://xxx.com/xxx/xxx/xxx.php',
      // get请求的参数
      data:{
        // id=868987
        id:"868987"
      },
      // 请求头
      header:{
        'content-type':'application/json'
      },
      timeout:10000,
      // 若是post接口,method:"POST" --- 不写的话默认是get请求
      method:"GET",
      success(res){
        console.log("网络请求成功了");
        console.log(res.data);
      },
      fail(err){
        console.log("网络请求失败了");
        console.log(err);
      },
      complete(){
        console.log("网络请求完成,无论网络请求成功、失败都会调用这个");
      }
    })
  },
})

4. 小程序的下拉刷新和上拉加载

生命周期函数

onPullDownRefresh(){}  // 实现下拉刷新

onReachBottom(){} // 实现上拉加载
上拉加载不能是替换数据,而是老数据concat合并新数据

5. 小程序的数据存储

数据缓存有同步和异步两种方案:异步无论数据是否保存成功,程序都会继续往下执行。而同步只有数据保存成功,才会执行后面的代码。
使用异步性能更好,使用同步数据更安全
【异步操作】
存储: wx.setStorage(){key:"键",data:"值",encrypt:true // 加密存储}  除非用户主动删除,否则数据一直存在
数据通常要用AES加密处理
读取: wx.getStorage(excrypt:true // 读取的时候也需要加密方式读取)  通过success回调函数来拿到数据
删除: wx.removeStorage()
清空: wx.clearStorage()

【同步操作】
存储: wx.setStorageSync()
数据通常要用AES加密处理
读取: wx.getStorageSync()
删除: wx.removeStorageSync()
清空: wx.clearStorageSync()

6. 小程序的分享朋友圈或转发功能

wx.onShareAppMessage() 转发小程序
wx.onShareTimeline() 分享到朋友圈

7. 小程序的用户登录如何实现

通过wx.login()来实现的,调用这个方法,会自动将code发送给服务器,服务器会结合appID和appSecret来一起发送给微信的服务器,微信的服务器将标识返回给服务器,服务器经过处理后返回给前端,前端将内存存储在本地,这样来实现数据持久化存储

1. uniapp有哪些组件,可以说说吗?

view 视图
text 文本
image 图片
button 按钮
form 表单
input 输入框
video 视频
audio 音频
tabbar 底部导航

2. uniapp的网络请求方式是怎样的呢?

uni.request() 里面可以写请求的url地址和一些参数

3. uniapp中写底部导航用 tabbar

tabbar 底部导航 — 最少2个,最多5个

4. uniapp的网络请求及其封装知道吗?

uniapp的网络请求主要是uniapp内部提供的 uni.request()
网络请求的封装:通过promise对象来封装网络请求,这样就可以实现通过.then()来调用这种

还有什么要问的问题吗?

一些前端词汇

走马灯 — 轮播图
面包屑
导航条

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值