每天三道面试题~持续更新中。。。。。
1,vue响应式原理是如何实现?有何缺陷?vue3为什么抛弃vue2中的实现响应式方式?如何使用响应式实现数据双向绑定?如何解决数据响应到视图过度执行问题(如何实现精确更新)。
首先,这是一类问题,我在之前的文章有详细介绍
i.vue3为何抛弃vue2实现响应式的方式:
1 ) .Object.defineProperty 无法低耗费的监听到数组下标的变化,导致通过数组下标添加元素,不能实时响应;2).Object.defineProperty 只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历。如果属性值是对象,还需要深度遍历。 Proxy 可以劫持整个对象, 并返回一个新的对象。3).Proxy 不仅可以代理对象,还可以代理数组。还可以代理动态增加的属性。
2,react/vue中列表遍历为什么用key,其作用是什么?
为了使遍历对象的时候使得每个项一一对应一个标签(网上的解读有很多,很多情况自己看还不一定看懂,我自己就简单总结了)
每个项一一对应一个标签这个是重点,普通遍历的时候,不给key,没什么问题,有个隐形的问题是效率低下。
virtual dom
要理解diff的过程,先要对virtual dom有个了解,这里简单介绍下。
 【作用】
我们都知道重绘和回流,回流会导致dom重新渲染,比较耗性能;而virtual dom就是用一个对象去代替dom对象,当有多次更新dom的动作时,不会立即更新dom,而是将变化保存到一个对象中,最终一次性将改变渲染出来。
为什么不能使用index作为key而是使用对象的唯一表示作为key
	<head>
		<meta charset="UTF-8" />
		<title>姓名案例_计算属性实现</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
		<button @click='add'>加</button>
		<ul>
			<li v-for="(p,index) in array" :key='index'>{{p.name}}
				<input type="text" >
			</li>
			
		</ul>
	</div>
	</body>
	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		const vm = new Vue({
			el:'#root',
			data:{
				array:[
					{id:'1',name:'xiao'},
					{id:'2',name:'bai'},
					{id:'3',name:'hahah'},
					{id:'4',name:'wuwuw'}]
			},
			methods: {
				add(){
					let p={id:'5',name:'biee'}
					this.array.unshift(p)
				}
			},
		})
	</script>初始化input输入:

添加之后结果:

会发现没有实现一一对应关系:原因——input在生成的时候,input使用的是数组的1,2,3,4下标的index,所以它会在上面,此时要想一一对应,得input这里需要使用数组项的唯一标识,这样不管数组加了多少元素,input使用的index和数组项的唯一标识都会一一对应。
<li v-for="(p,index) in array" :key='p.id'>
    {{p.name}}
	<input type="text" >
</li> 
3,['1', '2', '3'].map(parseInt)执行结果?
数组的map方法:array.map(item,index)。item遍历的数组项,index是数组下标
字符串的方法:string.parseInt(str,num)。str是字符串,num是进制
完整写法:
['1', '2', '3'].map((item,index)=>{
    return parseInt(item,index)
})结果为:1,NaN,NaN
4,什么是防抖和节流?有什么区别? 如何实现?
let set =new Set()
Set实例属性:
size:set容器的元素个数
Set实例的方法
add(value):添加元素
delete(value):删除元素
clear():清空容器
has(value):判断某值是否存在
let set =new Set(array)ii.Map
Map:也是一个容器,元素成键值对存在,键唯一,值不唯一。
获取Map实例
let map =new Map()
let map =new Map(array)
Map实例的方法
set(key,value):添加元素
get(key):通过key获取到value
delete(key):通过key删除键值对
clear():清空容器
has(key):判断某键值对是否存在
function Person(name, age) {
    this.name = name
    this.age = age
  }
  Person.prototype.setName = function (name) {
    this.name = name
  }
  function Student(name, age, price) {
    Person.call(this, name, age) //得到父类型的属性
    this.price = price
  }
  Student.prototype = new Person()  //得到父类型的方法
  Student.prototype.constructor = Student
  Student.prototype.setPrice = function (price) {
    this.price = price
  }es6通过extends实现
class person{
.......
}
class son extends person{
........
}需要重写父类非私有构造方法
1. 浏览器获取用户输入,等待 url 输入完毕,触发 enter 事件;2. 解析 URL ,分析协议头,再分析主机名是域名还是 IP 地址;3. 如果主机名是域名的话,则发送一个 DNS 查询请求到 DNS 服务器,获 得主机 IP 地址;4. 使 用 DNS 获 取 到 主 机 IP 地 址 后 , 向 目 的 地 址 发 送 一 个 (http/https/protocol )请求,并且在网络套接字上自动添加端口信息 http 80 https 443);5. 等待服务器响应结果;6. 将响应结果(html )经浏览器引擎解析后得到 Render tree ,浏览器将 Render tree 进行渲染后显示在显示器中,用户此时可以看到页面被渲染。 9. 简述 HTTP2.0 与 HT
在执行全局代码前将window确定为全局执行上下文
对全局数据进行预处理
var定义的全局变量==>undefined, 添加为window的属性
function声明的全局函数==>赋值(fun), 添加为window的方法
this==>赋值(window)
ii. 函数执行上下文
对局部数据进行预处理
形参变量==>赋值(实参)==>添加为执行上下文的属性
arguments==>赋值(实参列表), 添加为执行上下文的属性
var定义的局部变量==>undefined, 添加为执行上下文的属性
function声明的函数 ==>赋值(fun), 添加为执行上下文的方法
this==>赋值(调用函数的对象)
1. 在全局代码执行前, JS引擎就会创建一个栈来存储管理所有的执行上下文对象
2. 在全局执行上下文(window)确定后, 将其添加到栈中(压栈)
3. 在函数执行上下文创建后, 将其添加到栈中(压栈)
4. 在当前函数执行完后,将栈顶的对象移除(出栈)
5. 当所有的代码执行完后, 栈中只剩下window
21.数组相关
22.手写call、apply和bind
i.手写call
call的用法:用于改变this的指向,第一个参数为需要指向的this对象,其余参数表示的是函数参数:
function.call(thisArg, arg1, arg2, ...)
<script>
    function fn(){
        console.log(this.name);
    }
    let obj={
        name:'小智'
    }
    fn.call(obj)
</script>通过call将this指向obj对象,可以使用obj对象的name属性:

首先call()是Function原型对象里面的,如果要重写,需要在Function原型对象添加一个新的方法,这里取名:newCall()
Function.prototype.newCall=function(){}其次,在我们使用call进行this指向的时候,相当在对象内部添加了函数并调用该对象内部的属性。然后使用对象调用方法
let obj={
        name:'小智',
        fn:function(){
            console.log(this.name);
        }
    }
obj.fn()按照上面的思路,手写的call方法为:
<script>
    Function.prototype.newCall=function(obj){
        console.log(this);
    }
    function fn(){
        console.log(this.name);
    }
    let obj={
        name:'小智',
    }
    fn.newCall(obj)
</script>我们打印this:

发现this指向的是fn,这是因为这个fn调用了newCall,name就没有打印出来。此时我们就需要将该this指向obj对象:过程就是将fn添加到obj属性中并调用,即将this赋值给obj自定义属性内(主要需要删除添加的属性,主要是obj原则上不能被修改):

最后需要解决的问题是参数问题和this为空的问题,最终代码:
<script>
    Function.prototype.newCall=function(){
        let array=Array.from(arguments)
        let newArguments=[]
        array[0]= array[0]||window
        array[0].p=this
        for(let i=1;i<array.length;i++){
            newArguments.push(array[i])
        }
        array[0].p(...newArguments)
        delete array[0].p
    }
    function fn(a,b,c,d){
        console.log(this.name,a,b,c,d);
    }
    let obj={
        name:'小智',
    }
    fn.newCall(null,'小妹妹','小弟弟','小哥哥','大哥哥')
</script>结果为:

ii.手写apply
这里和call差别不大,只是函数的参数入参的时候是一个数组,可以说是比call更简单:
<script>
    Function.prototype.newApply=function(){
        let array=Array.from(arguments)
        array[0]= array[0]||window
        array[0].p=this
        array[0].p(...array[1])
        delete array[0].p
    }
    function fn(a,b,c,d){
        console.log(this.name,a,b,c,d);
    }
    let obj={
        name:'小智',
    }
    fn.newApply(null,['小妹妹','小弟弟','小哥哥','大哥哥'])
</script>iii.手写bind
bind使用方式和call类似,bind是将this指向哪个函数,而call的实现思路是将函数指向哪个对象。即对象调用函数的方式。
bind的实现原理:生成一个指向对象的函数
<script>
    Function.prototype.newBind=function(obj){
        let _this=this
        let argOne=Array.from(arguments)
        let array=argOne.shift()
        return function(){
            let argTwo=Array.from(arguments)
            //使用call或者applay修改this指向,可以手写
            _this.apply(obj,[...argOne,...argTwo])
        }
    }
    function fn(a,b,c,d,e){
        console.log(this.name,a,b,c,d,e);
    }
    let obj={
        name:'小智',
    }
    //链式调用
   fn.newBind(obj,'小妹妹','小弟弟','小哥哥','大哥哥')()
</script>23.JavaScript模块化编程,什么是模块化?你对模块化编程的理解
模块化就是一组特定的函数组,原始写法就是把功能写在一个个函数内,需要的时候就调用。但是为了方便管理,一般情况我们需要把特定函数懂放在一个对象内,在es6之后,可以把具有类似功能的写到一个js文件中,然后通过deport导出来(import导入),需要的时候就使用。
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号