资讯详情

2021前端笔试题

https://github.com/lydiahallie/javascript-questions/blob/master/zh-CN/README-zh_CN.md https://blog.csdn.net/liuyan19891230/article/details/102385743

1.什么是闭包,为什么要用闭包?

  • 嵌套在一个函数中的另一个函数是一个封闭的包。

  • 功能:创建私有变量,减少全局变量,防止变量名污染。可操作外部功能域的变量,变量不会被浏览器回收,变量值。

2.以下代码输出结果是什么?想输出吗? 0 1 2 3 4 怎么解决?

for(var i = 0; i < 5; i  ){  setTimeout(function(){   console.log(i);  },1000) } 

输出结果为 5个5 输出 0 1 2 3 4 5 方法如下: 方法一:

for (let i = 0; i < 5; i  ) {  setTimeout(function() {   console.log(i);  }, 1000); } 

方法二:

for (var i = 0; i < 5; i  ) {  (function(j) {     setTimeout(function() {       console.log(j);   }, 1000);  })(i); } 

方法三:

for (var i = 0; i < 5; i  ) {     setTimeout(function(j) {        console.log(j);     }, 1000, i); } 

3.委托分析事件? 事件委托是指将事件绑定到目标元素的父元素上,利用泡沫机制触发事件。

ulEl.addEventListener('click', function(e){     var target = event.target || event.srcElement;     if(!!target && target.nodeName.toUpperCase() === "LI"){         console.log(target.innerHTML);     } }, false); 

4.有以下段落HTML写一段代码 js 实现:单击列表时,输出相应的索引。

<ul>  <li>1<li>  <li>2<li>  <li>3<li>  <li>4<li> </ul> 

方法1:立即使用执行函数

var liList = document.getElementsByTagName('li') for (var i = 0; i < liList.length; i  ) {      (function(i){           liList[i].onclick = function(){              console.log(i)           }      })(i)   }; 

方法二:使用ES6的let

var liList = document.getElementsByTagName('li') for (let i = 0; i < liList.length; i  ) {     liList[i].onclick = function(){         console.log(i)     } }; 

方法三:forEach实现

var liList = document.getElementsByTagName('li') var liArr = [].slice.call(liList)//将liList这类数组转化为数组,forEach只能遍历数组 liArr.forEach(function(ele,i){    ele.onclick = function(){ console.log(i)  }   }) 

方法四:call方法

var liList = document.getElementsByTagName('li') function fun(idx){      this.onclick = function(){ console.log(idx) }  }  for (var i = 0; i < liList.length; i  ) {      fun.call(liList[i],i)  }; 

5、数组方法 pop() push() unshift() shift() 的作用

shift():删除数组的第一个元素,返回第一个元素的值。 pop() : 删除数组的最后一个元素,返回最后一个元素的值。 push():在数组末尾添加一个或多个元素,以返回新数组的长度。 unshift() :将一个或多个元素添加到数组头部,以返回新数组的长度。

6、var arr = [4,0,7,9,0,0,2,6,0,3,1,0]; 数组中的要求 0 去掉项目,不会 0 将值存储在新的数组中,生成新的数组。 方法1:逐步反映要求

//定义数组 var arr = [4, 0, 7, 9, 0, 0, 2, 6, 0, 3, 1, 0]; //创建空数组,接收新生成的数组 var mn=[] //创建函数 function fn(arr,ma) {     ///循环添加随机元素     for(var i=0;i<arr.length;i  ) {         //判断         if(arr[i] == ma){             //删除               arr.splice(i,1);               i--;               //空数组,接收新生成的数据             mn=arr;         }       } } fn(arr,0); console.log(新数组,mn); 

方法二:使用 forEach

var arr = [4,0,7,9,0,0,2,6,0,3,1,0]; var a = [] arr.forEach(item=>{     if(item != 0){         a.push(item)     } }) console.log('a',a) 

方法三:使用 for 循环

var arr = [4,0,7,9,0,0,2,6,0,3,1,0]; var b = [] for(var i = 0; i < arr.length; i  ){     if(arr[i] != 0){         b.push(arr[i])     } } console.log('b',b) 

7、如何解决 ajax 地狱回调问题?

Promise使用场景:ajax请求、回调函数、复杂操作判断。 Promise是ES为了解决异步编程的诞生。 异步操作解决方案:Promise、Generator、定时器(不知道算不算)ES7的async

8、谈谈你对 ES6 的理解?

  • 新模板字符串(为 JavaScript 字符串插值功能简单)
  • 箭头函数
  • for-of(用于遍历数据-例如数组中的值。
  • arguments 不确定参数和默认参数可以完美地替代对象。
  • ES6 将 promise 对象纳入规范,提供原生 Promise 对象。
  • 增加了 let 和 const 用于声明变量的命令。
  • 块级作用域增加。
  • let 实际上,命令增加了块级作用域。
  • 还有介绍 module 模块的概念

9.常用的库有哪些?开发了哪些应用或组件? 10、用一个 div 模拟 textarea 的实现 给 div 添加 contenteditable=true 即可。 步骤:

  • 给 div 添加一个HTML全局属性:contenteditable="true",使 div 用户可以编辑元素;
  • 给 div 添加样式 resize: vertical;,使 div 用户可以调整尺寸。注:别忘了设置 overflow:auto; 样式,因为 resize 款式不适合 verflow:visible; 的块,不然 resize 不起效;
  • 增加一个属性:placeholder=“请输入……”;
  • 通过 CSS 选择器获取并显示 placeholder 的值;

代码实现:

<div class="textarea" contenteditable="true" aria-placeholder="this is placeholder">


.textarea{
    height: 200px;
    width: 300px;
    padding: 4px;
    border: 1px solid #888888;
    resize: vertical;
    overflow: auto;
}
.textarea:empty:before {
    content: attr(aria-placeholder);
    color: #bbb;
}

10-1、CSS限制显示字数,文字长度超出部分用省略号表示 (1) 文字超出一行,省略超出部分,显示’…’

.line-limit-length {
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap; /*文本不换行,这样超出一行的部分被截取,显示...*/
}

(2) 可以给定容器宽度限制,超出部分省略。

.product-buyer-name {
	max-width: 110px;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

11、怎么让 Chrome 支持小于 12px 的文字? 谷歌 Chrome 最小字体是 12px,不管你设置成 8px 还是 10px,在浏览器中只会显示 12px

针对谷歌浏览器内核,加 webkit 前缀,用 transform:scale() 这个属性进行缩放。

<style>
.span1 span{
    font-size:10px; /* 针对可以识别12px以下字体大小的浏览器 */
    -webkit-transform:scale(0.8);
}
.span2 span{
    font-size:12px;   
}
</style>
<p class="span1">
    <span >测试10px</span>
</p>
<p class="span2">
    <span >最小12px</span>
</p>

12、CSS垂直局居中的写法,请至少写出 2 种。 (1)已知容器尺寸

<div class="parent">
    <div class="child"></div>
</div>

方法一:利用定位(常用方法,比较推荐)

<style>
    .parent{ 
        width:500px; 
        height:500px; 
        border:1px solid #000; 
        position:relative 
    } 
    .child{ 
        width:100px; 
        height:100px; border:1px solid #999;
        position: absolute; 
        top: 50%; 
        left: 50%; 
        margin-top: -50px;
        margin-left: -50px; 
    }
</style>

方法二:利用 margin:auto;

<style>
    .parent { 
        width: 500px; 
        height: 500px; 
        border: 1px solid #000; 
        position: relative;
    } 
    .child { 
        width: 100px; 
        height: 100px; 
        border: 1px solid #999; 
        position: absolute; 
        margin: auto; 
        top: 0; 
        left: 0; 
        right: 0; 
        bottom: 0; 
    }
</style>

方法三:利用 display:table-cell

<style>
    .parent { 
        width: 500px; 
        height: 500px; 
        border: 1px solid #000; 
        display: table-cell; 
        vertical-align: middle; 
        text-align: center;
    } 
    .child { 
        width: 100px; 
        height: 100px; 
        border: 1px solid #999; 
        display: inline-block;
    }
</style>

方法四:利用 display:flex;设置垂直水平都居中

<style>
    .parent { 
        width: 500px; 
        height: 500px; 
        border: 1px solid #000; 
        display: flex; 
        justify-content: center; 
        align-items: center;
    } 
    .child { 
        width: 100px; 
        height: 100px; 
        border: 1px solid #999;
    }
</style>

(2)未知容器尺寸 方法一:

div {
 	position: relative;		/* 相对定位或绝对定位均可 */
 	width:500px;
 	height:300px;
 	top: 50%;
 	left: 50%;
 	margin: -150px 0 0 -250px;     	/* 外边距为自身宽高的一半 */
 	background-color: pink;	 	/* 方便看效果 */
}

方法二: 未知容器的宽高,利用 transform 属性

div {
 	position: absolute;		/* 相对定位或绝对定位均可 */
 	width:500px;
 	height:300px;
 	top: 50%;
 	left: 50%;
 	transform: translate(-50%, -50%);
 	background-color: pink;	 	/* 方便看效果 */
}

方法三: 利用 flex 布局 实际使用时应考虑兼容性

 .container {
 	display: flex;
 	align-items: center; 		/* 垂直居中 */
 	justify-content: center;	/* 水平居中 */
 }
 .container div {
 	width: 100px;
 	height: 100px;
 	background-color: pink;		/* 方便看效果 */
 }  

13、CSS实现宽度自适应 100%,宽高 16:9 的比例的矩形。 解释:通过百分比设置宽度,根据宽度的比例数值*9/16,计算出高度的百分比数值,设置内边距为高度的数值,最后用绝对定位 百分百填充 item。

做法: 第一步先计算高度,假设宽 100%,那么高为h=9/16=56.25% 第二步利用之前所说设置 padding-bottom 方法实现矩形

<div class="box">
    <div class="scale">
        <p class="item">16:9的矩形</p>
    </div>
</div>
<style>
    .box{
        width: 80%;
    }
    .scale{
        width: 100%;
        padding-bottom: 56.25%;
        height:0;
        position:relative;
    }
    .item{
        width: 100%;
        height: 100%;
        background-color: pink;
        position: absolute;
    }
</style>

14、 [] == []输出的结果是?为什么?

  • []单独用在==表达式中时,会隐含转型为""(空字符串)
  • 一个不是 null 或者 undefined 的对象(包括[])用在布尔表达式中,会被作为 true 处理。因此 [] 结果是 true,![] 的结果是false。
  • 所以: []==[] 等价于""==true []==![] 等价于 ""==false
  • 而空字符串在布尔表达式中作为 false 处理。
  • 因此: [] == [] 结果是 false [] == ![] 结果是 true

15、JavaScript 的基本数据类型都有什么?

  • 基本数据类型:Number、String、Boolean、undefined、Null、Symbol、ES10新增的BigInt(任意精度整数)七类。
  • 引用数据类型(Object类):常规名值对的无序对象 {a:1},数组[1,2,3],以及函数。

原始数据类型:

  • 布尔类型:布尔表示一个逻辑实体,可以有两个值:true 和 false。
  • Null 类型:Null 类型只有一个值: null。
  • Undefined 类型:一个没有被赋值的变量会有个默认值 undefined。
  • 数字类型:根据 ECMAScript 标准,JavaScript 中只有一种数字类型:基于 IEEE 754 标准的双精度 64 位二进制格式的值(-(253 -1) 到 253 -1)。它并没有为整数给出一种特定的类型。除了能够表示浮点数外,还有一些带符号的值:+Infinity,-Infinity 和 NaN (非数值,Not-a-Number)。
  • BigInt 类型:BigInt类型是 JavaScript 中的一个基础的数值类型,可以用任意精度表示整数。使用 BigInt,您可以安全地存储和操作大整数,甚至可以超过数字的安全整数限制。BigInt是通过在整数末尾附加 n 或调用构造函数来创建的。
  • String字符串类型:JavaScript的字符串类型用于表示文本数据。它是一组16位的无符号整数值的“元素”。在字符串中的每个元素占据了字符串的位置。第一个元素的索引为0,下一个是索引1,依此类推。字符串的长度是它的元素的数量。
  • Symbols符号类型:符号(Symbols)是ECMAScript 第6版新定义的。符号类型是唯一的并且是不可修改的, 并且也可以用来作为Object的key的值(如下). 在某些语言当中也有类似的原子类型(Atoms). 你也可以认为为它们是C里面的枚举类型。

引用数据类型:

  • Object对象: 在计算机科学中, 对象是指内存中的可以被 标识符引用的一块区域。

16、实现一个对象的浅拷贝和一个基本的深拷贝(可以不考虑函数) demo数据:

// 对象的浅拷贝
var obj = {
    name: '张三',
    age: 33,
    sex: '男',
    hobby: {
        a: '1'
    }
}

方法一:使用循环遍历对象,将其键值赋值给一个新数组;

var newObj = {}; 
//  循环遍历数组
for (var k in obj) {
    newObj[k] = obj[k];
}
console.log(newObj);    //{name: "张三", age: 33, sex: "男", hobby: {…}} 

newObj.hobby.a = '2';
console.log(obj.hobby.a);    // 2
console.log(newObj.hobby.a); // 2

方法二:采用 Object.assign(新数组,拷贝的数组); 方法

var newObj = {};
Object.assign(newObj, obj);  
console.log(newObj);    // {name: "张三", age: 33, sex: "男", hobby: {…}}

newObj.hobby.a = '2';
console.log(obj.hobby.a);    //2
console.log(newObj.hobby.a);    //2

demo数据格式:

// demo test
var objTest = { 
    name:"gino", 
    sex:"male", 
    family:{ 
        brother:"zhipeng", 
        mother:"SunAiyun",     
    }
};

var arrTest = ["a","b","c","d"];

方法一:JSON.parse(JSON.stringify(arrTest)) 不能拷贝对象 方法二:

//深拷贝
function deepCopy(arr) {
  let copyArr = arr.constructor === Array ? [] : {}
  for (let i in arr) {
    if (typeof arr[i] === 'object') {
      copyArr[i] = deepCopy(arr[i]) // 引用类型的话进行递归操作
    } else {
      copyArr[i] = arr[i] // 值类型直接赋值
    }
  }
  return copyArr
}

方法三:使用递归:

function deepClone_1(obj){
    let objClone = Array.isArray(obj)?[]:{};
    if(obj && typeof obj==="object"){
        for(key in obj){
            if(obj.hasOwnProperty(key)){
                //判断ojb子元素是否为对象,如果是,递归复制
                if(obj[key]&&typeof obj[key] ==="object"){
                    objClone[key] = deepClone_1(obj[key]);
                }else{
                    //如果不是,简单复制
                    objClone[key] = obj[key];
                }
            }
        }
    }
    return objClone;
}    

console.log('对象深拷贝', deepClone_1(objTest))
console.log('数组深拷贝', deepClone_1(arrTest))

方法四:利用数组的 Array.prototype.forEach 和其他一些 ECMAScript 5中的 Object.* 函数

var deepClone_2 = function (obj){
    var copy = Object.create( Object.getPrototypeOf(obj) );
    var propNames = Object.getOwnPropertyNames(obj);
    propNames.forEach(function(name){
        if(typeof obj[name] === 'object') {
            let copyObj = deepClone_2(obj[name])
            copy[name] = copyObj
        } else {
            var desc = Object.getOwnPropertyDescriptor(obj, name);
            Object.defineProperty(copy, name, desc);
        }
    }); 
    return copy;
}

console.log('对象深拷贝', deepClone_2(objTest))
console.log('数组深拷贝', deepClone_2(arrTest))

方法五:

// 对象的浅拷贝
var obj = {
    name: '张三',
    age: 33,
    sex: '男',
    hobby: {
        a: '1'
    }
}
 
var newObj = {}; 
 
//递归循环  
function deepCopy_3(newObj, oldObj) {
    for (var k in oldObj) {
        if (oldObj[k] instanceof Array) {
            newObj[k] = [];
            deepCopy_3(newObj[k], oldObj[k]);
        }
        else if (obj[k] instanceof Object) {
            newObj[k] = {};
            deepCopy_3(newObj[k], oldObj[k]);
        } else {
            // 基本数据类型
            newObj[k] = oldObj[k];
        }
    }
}
 
// 对象深拷贝
deepCopy_3(newObj, obj);
console.log(newObj);    //   {name: "张三", age: 33, sex: "男", hobby: {…}}
 
newObj.hobby.a = '2';
console.log(obj.hobby.a);    //    1
console.log(newObj.hobby.a);    //    2

17、数据格式 JSON 转换为字符串,以及把字符串转换为 JSON 的方法。 (1)字符串 → JSON对象:

  • JSON.parse()方法

    var a = ‘{“a”:2}’; JSON.parse(a); //{a:2}

  • eval() 方法:计算某一个字符串,并执行其中的 javascript 代码 【不推荐】

    var s = ‘{a:2}’; eval(’(’ + s + ‘)’); //将json字符串转成json对象,需要在字符串外包裹一对括号(), {a:2}

(2)json对象 → 字符串

  • JSON.stringify()方法 ,将非字符串转成字符串

    var s = {‘a’:2}; JSON.stringify(s); //"{“a”:2}"

(3)将值转换成字符串(值 → 字符串)

  • 转换函数 toString(),弱类型转换,强制类型转换 value.toString() 将数值转成对应进制的字符串

    var n =8; n.toString(几进制);

注意:不能将 null 和 undefined 转换成字符串

  • 弱类型转换:value + '' 将值转换成字符串 2+ ''
  • 强制类型转换:String(value)

(4)字符串 → 值

  • 转换函数:parseInt() 和 parseFloat()

    parseInt(“1234blue”); //returns 1234 parseInt(“22.5”); //returns 22 parseInt(“blue”); //returns NaN

    parseInt(“AF”, 16); //returns 175 parseInt(“10”, 2); //returns 2

    parseFloat(“1234blue”); //returns 1234.0 parseFloat(“22.5”); //returns 22.5 parseFloat(“blue”); //returns NaN

  • 强制类型转换 Number(value)——把给定的值转换成数字(可以是整数或浮点数);

    Number(false) 0 Number(true) 1 Number(undefined) NaN Number(null) 0 Number( "5.5 ") 5.5 Number( "56 ") 56 Number( "5.6.7 ") NaN

补充:小数

  • 四舍五入

    var num =2.4492425542; num = num.toFixed(2); // 输出结果为 2.45

  • 不四舍五入 (不进位)

    Math.floor(15.7784514000 * 100) / 100 // 输出结果为 15.77

  • 当成字符串,使用正则匹配

    Number(15.7784514000.toString().match(/^d+(?:.d{0,2})?/)) // 输出结果为 15.77,不能用于整数如 10 必须写为10.0000

注意:如果是负数,请先转换为正数再计算,最后转回负数。

18、说出至少 4 种 vue 当中的指令和它的用法

  • v-if:判断是否隐藏
  • v-for:数据循环
  • v-bind:class:绑定一个属性
  • v-model:实现数据双向绑定

19、vue-router 怎么定义动态路由的?怎么获取传过来的动态参数?

  • 简单回答: 定义:path:'a/:value' 获取:this.$route.params.value

  • 全面了解: 可以通过 query , param 两种方式 区别: query 通过 url 传参,刷新页面还在 params 刷新页面不在了。 (1)params 的类型: 配置路由格式: /router/:id 传递的方式: 在path后面跟上对应的值 传递后形成的路径: /router/123

    用户

    //在index.js中 { path: ‘/user/:userid’, component: User, },

跳转方法:

// 方法1:
<router-link :to="{ name: 'users', params: { uname: wade }}">按钮</router-link>
// 方法2:
this.$router.push({name:'users',params:{uname:wade}})
// 方法3:
this.$router.push('/user/' + wade)

可以通过 $route.params.userid 获取你说传递的值 (2)query 的类型 配置路由格式: /router,也就是普通配置 传递的方式: 对象中使用 query 的 key 作为传递方式 传递后形成的路径: /routeid=123

<!--动态路由-query -->
<!-- 方法一:直接在 router-link 标签上以对象的形式 -->
<router-link :to="{path:'/profile',query:{name:'why',age:28,height:188}}">档案</router-link>


// 方法二:或者写成按钮以点击事件形式  
<button @click='profileClick'>我的</button>   

//点击事件
profileClick(){
	this.$router.push({
		path: "/profile",
		query: {
			name: "kobi",
			age: "28",
			height: 198
		}
	});
}

跳转方法:

// 方法1:
<router-link :to="{ name: 'users', query: { uname: james }}">按钮</router-link>
// 方法2:
this.$router.push({ name: 'users', query:{ uname:james }})
// 方法3:
<router-link :to="{ path: '/user', query: { uname:james }}">按钮</router-link>
// 方法4:
this.$router.push({ path: '/user', query:{ uname:james }})
// 方法5:
this.$router.push('/user?uname=' + jsmes)

可以通过 $route.query 获取你说传递的值。

20、分别写出 webpack 打包给服务器和本地开发预览的命令代码。 npm run buildnpm run dev 21、下面代码 let a = [1,2,4] let b = a.map(v=>{v = v* 2}) 写出 b 的值 在这里插入图片描述 原题中没有 return v,所以b的值是 [undefined,undefined,undefined]。 如果有 return v,则 b 的值是 [2,4,8],正常 map 写法。

22、请生成下面这段DOM结构,要求:使用标准的DOM方法或属性。

<div class="example">
	<p class="slogan">请编辑这段话!</p>
</div>

主要用到的函数:createElement,appendChild,createTextNode,setAttribute 这几个函数。 (1)创建元素的DOM方法 – createElement; (2)设置元素属性的DOM方法 – setAttribute; (3)添加到元素上的DOM方法 – appendChild; (4)创建文字的DOM方法 - createTextNode; (5)设置样式的DOM属性 – className(HTML DOM属性)

var oDiv=document.createElement("div");
var op=document.createElement("p");
oDiv.appendChild(op);
op.className="slogan";

var oText=document.createTextNode("请编辑这段话!");
op.appendChild(oText);
oDiv.setAttribute("id","example");

document.body.appendChild(oDiv);

23、请使用 Promise 封装 Ajax 操作 原始的 Ajax 操作如下:

var onSuccess = function(result){};  //成功的回调
var onFail = function(error){};  //失败的回调
var req = new XMLHttpRequest();
req.open("POST", "www.baidu.com", true);
req.onload = function(){
	if( req.readyState === 4 && req.status === 200 ){
		onSuccess(req.response);
	}else {
		onFail(req.statusText);
	}
}
req.onerror = function(){
	onFail(Error("网络异常"));
}

答案1:

//参考:https://www.nowcoder.com/questionTerminal/86311e67b9124788b68acdf002da55f8

const ajax = url => {
    return new Promise((resolve, reject) => {
        let req = new XMLHttpRequest();
        req.open("POST", url, true);
        req.onload = () => {
          if(req.readyState === 4 && req.status === 200){
            resolve(req.response);
          } else {
            reject(req.statusText);
          }
        }
        req.onerror = () => {
          reject(Error("网络异常"));
        }
    })
}

答案2:

return new Promise(function(resolve, reject){
    var req = new XMLHttpRequest();
    req.open("POST", "www.baidu.com", true);
    req.onload = function(){
      if(req.readyState === 4 && req.status === 200){
        resolve(req.response);
      } else {
        reject(req.statusText);
      }
    };
    req.onerror = function(){
      reject(Error("网络异常"));
    }
}); 

答案3:

// 参考:https://blog.csdn.net/weixin_45298413/article/details/108809108

const promise = new Promise((resove,reject)=>{
    var req = new XMLTttpRequest();
    req.open("post","http://www.baidu.com",true);
    req.onload = function(){
        if(req.readyState === 4 && req.status === 200){
            onSuccess(req.response);
        } else {
            onFail(req.statusText); 
        }
    }
    req.onerror = function(){
        onFail(Error("网络异常"));  
    }
})

延伸: (1)利用Promise知识,用原生JS封装Ajax 参考:https://www.jianshu.com/p/76b32c84216a

//封装一个Promise函数
function queryData (url){
    //创建一个Promise实例
    var p = new Promise(function(resove,reject){
        var req = XMLHttpRequest();
        req.onreadystatechange = function(){
            if(req.readystate !== 4) return;
            if(req.readystate === 4 && req.status === 200) {
                //处理正常情况
                resove('req.responseText');
            }else{
                //处理异常情况
                reject('服务器错误');
            }
        }
        req.open('get',url);
        req.send();
    })
    return p;
}

//用实例方法调用封装函数
queryData('http://localhost:3000/data')
    .then(function(data){
        console.log('data1',data);
        //想要使用链式编程需要return返回,并且返回的数据将是下一次then方法参数函数的data参数
        return queryData('http://localhost:3000/data1')
    })
    .then(function(data){
        console.log('data2',data);
    })

(2)参考1:https://www.cnblogs.com/jwyblogs/p/11962866.html 参考2:https://www.nowcoder.com/questionTerminal/86311e67b9124788b68acdf002da55f8 参考3:https://segmentfault.com/a/1190000015114855utm_source=tag-newest

、HTML 与 CSS。

  1. 实现两列布局:左列宽度为 200px,右列占据剩余宽度。要求: 可以不兼容旧浏览器; 不能使绝对定位等特殊定位式; 不能使表格布局;

方法一:float+margin-left

div{
  height:200px;
}
.left{
  float: left;
  width: 200px;
  /* background: blue; */
}            
.right{
  margin-left: 200px;
  /* background: red; */
}

方法二:使用 flex

.box{
    width:500px;
    height:200px;
    display: flex;
    /* background:black; */
}
.left{
    width: 200px;
    /* background:pink; */
}
.right{
    flex: 1;
    /* background:green; */
}

方法三:使用 flex + justify-content:space-between;

.box{
    width:500px;
    height:200px;
    /* background:black; */
    display: flex;
    justify-content:space-between;
}
.left{       
	width:200px;
    /* background: pink; */
}
.right{
    /* background:green; */
}
  1. 尺?未知的元素置于浏览器可区域的正中央,且位置不随滚动变化(须兼容旧浏览器)。 有疑问,尺寸未知是是意思?? 写法一:

方法二:

使用position属性的绝对定位
.yuansu{
	position: absolute;
	margin-left: -200px;
	margin-top: -80px;
	top: 50%;
	left: 50%;
	display: block;
	z-index: 2000;
}

、JavaScript。

  1. 使正则表达式检查某段字符串是否为 URL。URL 的认定标准(符合以下条件之): 以「协议://」开头,例如「http://」、「https://」、「ftp://」、「file://」等,但需校验是否为有效协议; 以「//」开头,即跟随协议。

    string httpurl = String.Format(@"http://{0}(/{1}(?{2}){ {0,1}}){ {0,1}}

  2. 假设某个数组的元素全是数字类型,请编写代码找出该数组中的重复元素。要求: 代码中最多只能存在次遍历(数组循环,indexOf、forEach、filter 等法均视为遍历); 不能使 ES>=6 中的新增法和对象。

方法一: 写法一:【正确】

function getRepeat(ele){
  var tmp = [];
  var d = {};
  for(let n of ele){
    if(!d[n]){
      d[n] = 0;
    }
    if(n in d && d[n] == 1){
      tmp.push(n);
    }
    d[n] += 1;
  }
  return tmp;
}
var a = [5, 4, 3, 2, 1, 2, 3, 2, 1];
console.log('取出重复元素',getRepeat(a))

写法二:【正确】

var a = [5, 4, 3, 2, 1, 2, 3, 2, 1];

Array.prototype.duplicate=function() {
  var tmp = [];
  var d = {};
  for(let n of a){
  	//一个个数测试,d保存的就是同一个数字出现的次数
    if(!d[n]){
        d[n] = 0;
    }
    //d[n] == 1的判断是为了确保相同数字只显示一个
    if(n in d && d[n] == 1){
        tmp.push(n);
    }
    //判断有没有重复,就算下它出现了几次
    d[n] += 1;
  }
  return tmp;
}
console.log('取出重复元素', a.duplicate())

方法二:(理解)

var a = [5,4,3,2,1,2,3,2,1,];
Array.prototype.duplicate=function() {
  var tmp = [];
  this.concat().sort().sort(function(a,b){
    if(a==b && tmp.indexOf(a) === -1) tmp.push(a);
  });
  return tmp;
}
console.log('取出重复元素', a.duplicate())

方法三:(理解)不符合本题要求

function remove(arr){
    var new_arr = [];
    var new_arr2 = [];
    arr.forEach((val, index)=> {
        //new_arr是对数组去重
        if(new_arr.indexOf(val) === -1) {
            new_arr.push(val);
        } else {
            //对重复的元素本身去重
            if(new_arr2.indexOf(val) === -1) {
                new_arr2.push(val);
            }
        }
    });   
    return new_arr2;   
}
var a = [1,2,4,4,3,3,1,5,3];
var b = remove(a);
console.log('b',b);
  1. a、b、c 都是执异步操作的函数,请通过 Promise、async、await 实现:a、b 并执完毕后再执 c。 function a(callback) { setTimeout(callback, 10); } function b(callback) { setTimeout(callback, 20); } function c(callback) { setTimeout(callback, 30); }

方法二: 参考:https://blog.csdn.net/qq_39456813/article/details/101191977

一、单选题 1、下列有关定位说法错误的是? A A. absolute 可以基于 static 定位 「 生成绝对定位的元素,相对于static 定位以外的第一个父元素进行定位 」 B. relative 可以基于 absolute 进行定位。 C. fixed 固定悬浮在 视口内 D. 定位 position 不能继承到子元素 2、把鼠标移到按钮并点击时,会产生一串什么样的事件? D A. active hover focus B. hover focus active C. focus hover active D. hover active focus 3、在 JS 中 ES5 以下哪种情况会产生一个新的作用域? E A. if 语句 B. 所有选项都会 C. for 语句 D. try……catch块 E. 函数 4、以下代码在控制台打印结果为? D

<script defer>
	console.log('inline script')
</script>
<script defer src="test1.js"></script>
<script src="test2.js"></script>

其中:

// test1.js
console.log('test1')
// test2.js
console.log('test2')

A. test1 inline script test2 B. inline script test1 test2 C. test1 test2 inline script D. inline script test2 test1 5. 现有如下策略:

Content-Security-Policy: default-src 'self'; script-src *.script1.org; font-src test.org; media-src https:; script-src * .script2.org 

在该网页中,以下说法错误的是: C A. 图片只能从本域获取 B. 多媒体文件必须通过 SSL方式获取 C. 可运行脚本不允许来自于 script2.org或其子域 D. 字体资源允许来自于 test.org 及其子域 解析: 参考:https://www.cnblogs.com/suizhikuo/p/12215229.html Web 安全之内容安全策略(Content-Security-Policy,CSP)配置

二、多选题: 1、以下哪几个选项的输出结果相同? ABD A.

for(var i = 0; i < 10; i++){
	setTimeout(function(i){
		console.log(i)
	}, 0, i)
}

B.

for(let i = 0; i < 10; i++){
	setTimeout(function(){
		console.log(i)
	}, 0)
}

C.

for(var i = 0; i < 10; i++){
	setTimeout(function(){
		console.log(i)
	}, 0)
}

D.

for(var i = 0; i < 10; i++){
	(function(i){
		setTimeout(function(){
			console.log(i)
		}, 0)
	}(i))
}

解析: ABD 输出 0123456789 C 输出10个10 2、以下哪些说法是正确的?ABCD A. 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(null 除外) B. 所有的引用类型(数组、对象、函数),__proto__ 属性值指向它的构造函数的 prototype 属性值 C. 所有的引用类型(数组、对象、函数),都有一个 __proto__ 属性,属性值是一个普通的对象 D. 所有的函数,都有一个 prototype 属性,属性值也是一个普通的对象

原型的5个规则(引用类型指除了null的引用类型 ) (1)所有引用类型(数组,对象,函数),都具有对象特性,即可自由扩展属性

var obj = {}
obj.a=100;
var arr =[]
arr.a =100;
function fn(){}
fn.a=100;

(2)所有的引用类型,都有一个proto属性,属性值是一个普通对象

console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);

(3)所有的函数都有一个prototype属性,属性值也是一个普通对象

console.log(fn.prototype)

(4)所有的引用类型(数组,对象函数),proto属性指向他的构造函数的prototype属性

console.log(obj.__proto__===Object.prototype)   

(5)当试图得到一个引用类型的某个属性时,如果对象本身没有这个属性,那么会去他的proto(即它的构造函数的prototype)中去寻找

function Foo(name){
	this.name= name;
}
Foo.prototype.alertName = function(){
	alert(this.name)
}
var f = new Foo('zs');
f.printName=function(){
    console.log(this.name)
}
f.printName();
f.alertName();      

三、填空题 1、请写出以下表达式的结果: typeof null

类型

结果

Undefined

“undefined”

Null

“object” (见下文)

Boolean

“boolean”

Number

“number”

BigInt(ECMAScript 2020 新增)

“bigint”

String

“string”

Symbol (ECMAScript 2015 新增)

“symbol”

Function 对象 (按照 ECMA-262 规范实现 [[Call]])

“function”

2、请写出以下表达式的结果:

void 0 == null        //true
void 0 == undefined   //true
void 0 === null       //false
void 0 === undefined  //true

四、问答题 题目描述 填写一个函数,实现多个异步任务并行时限制最大并行数量的功能,可参考如下函数结构:

async function runParallel(max: number, tasks: (() => Promise<any>)[]) : Promise<any[]>

使用:

const tasks = [...Array(100).keys()].map(i => () => new Promise(res => setTimeout(res,1000)))

当并行 Promise 的数量达到10个时,就会等待其中某个 resolve 后,才开启队列中下一个 Promise。

五、编程题 1、URL参数提取 时间限制:C/C++ 1秒,其他语言 2 秒 空间限制:C/C++ 32768K,其他语言 65536K 语言限定:JavaScript(V8 6.0.0) 实现一个parseURL函数,用于提取URL中的哈希以及查询参数。 输一个含有哈希的URL,其中包含若干个查询参数 输出有若干行,第一行为URL中的哈希,接下来的每一行为该URL的查询参数名称和值,用空格分隔,它们的顺序按照原本在URL中出现的顺序输出; 输入 http://163.com/role/search/#pagepageSize=20&pageNumber=10 输出 page pageSize 20 pageNumber 10 方法一:

function parseQueryString(argu){
  var str = argu.split('?')[1];
  var result = {};
  var temp = str.split('&');
  for(var i=0; i<temp.length; i++)
  {
     var temp2 = temp[i].split('=');
     result[temp2[0]] = temp2[1];
  }
  return result;
}

var url = "http://www.taobao.com/index.php?key0=0&key1=1&key2=2.............";
var obj = parseQueryString(url);
console.log('obj',obj)

方法二:

function getQueryString(name) {
  var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)')
  var currentUrl = window.location.search
  let r = ''
  if (currentUrl != '') {
    r = window.location.search.substr(1).match(reg) // 没有#的url
  } else {
    r = window.location.hash.split('?')[1].match(reg)
  }
  if (r != null) return unescape(r[2])
  return null
}
this.smallId = getQueryString('smallId')
this.supplierId = getQueryString('supplierId')
this.taskDetailId = getQueryString('taskDetailId')

2、实现一个 format 函数,快捷格式化字符串,不用老写 +号连接。 输入至少有一行: 第一个行是一个字符串,其中包含一些占位符,占位符格式为:{0}、{1}、{2} 依次类推(花括号内可能含有空格,例如 {1} 是合法的 );

后续行(如果有)为上面的占位符按顺序对应的值。

输出只有一行,为格式换后的字符串,将所有占位符替换为对应值;

注:输入输出相关代码已经写好,您只需实现 format 函数即可,该函数返回一个格式化后的字符串。

示例1 输入输出示例仅供调试。 输入 h1 {0},今天是 {1} 年 {2} 月 {3} 号星期 {4} Tom 2015 6 20 五 输出 hi Tom,今天是2015年6月20号星期五 示例2 输入输出示例仅供调试。 输入 Hello {2} a b 示例3 输入输出示例仅供调试。 输入 {0} {2} {2},My {1} is {2} Hello name World 输出 Hello World World,My name is World

JavaScript题:

一、选择题 1、下面代码的输出是什么? B

const person = {
	name:"Lydia",
	age:21
};
for(const item in person){
	console.log(item);
}

A. {name:“Lydia”},{age:21} B. "name","age" C.“Lydia”,21 D. [“name”,“Lydia”],[“age”,21] 在 for-in 循环中,我们可以通过对象的 key 来进行迭代,也就是这里的 name 和 age。在底层,对象的 key 都是字符串(如果他们不是 Symbol 的话)。在每次循环中,我们将 item 设定为当前遍历到的 key 所以一开始, item 是 name,之后 item 输出的则是 age。

for…in 语句用于遍历数组或者对象的属性,得到数组的下标,对象的属性名。 for…of 遍历(当前对象上的)每一个属性值,与 forEach一样

var arr=[{name:'张三'},{name:'李四'}];
var obj={name:'王五'};
for (var i in arr){
  console.log(i)   // 0 1 遍历得到下标
}
for (var i in obj){
  console.log(i)   // name 得到属性名
}

for (var i of arr){
  console.log(i)   // {name:'张三'} {name:'李四'}  得到数组的每一项值,与forEach一样
}

2、num 的值是什么? C const num = parseInt(“7*6”, 10); A. 42 B. “42” C. 7 D. NaN 只返回了字符串中第一个字母,设定了 进制 后 (也就是第二个参数,指定需要解析的数字是什么进制: 十进制、十六机制、八进制、二进制等等……), parseInt 检查字符串中的字符是否合法。一旦遇到一个在指定进制中不合法的字符后,立即停止解析并且忽略后面所有的字符。

* 就是不合法的数字字符。所以只解析到 “7”,并将其解析为十进制的 7, num 的值即为 7。

3、下面代码输出的是什么? A

function getInfo(member, year){
	member.name = "Lydia";
	year = "1998";
}
const person = { name: "Sarah" };
const birthYear = "1997";
getInfo(person, birthYear);
console.log(person, birthYear);

A. {name: "Lydia"}, "1997" B. {name:“Sarah”}, “1998” C. {name:“Lydia”}, “1998” D. {name:“Sarah”}, “1997” 普通参数都是 值 传递的,而对象则不同,是 引用 传递。所以说, birthYear 是值传递,因为他是个字符串而不是对象。当我们对参数进行值传递时,会创建一份该值的 复制 。(可以参考问题46)

变量 birthYear有一个对 "1997"的引用,而传入的参数也有一个对 “1997” 的引用,但二者的引用并不相同。当我们通过给 year 赋值 “1998” 来更新 year 的值的时候我们只是更新了 year(的引用)。此时 birthYear 仍然是 “1997”。

而 person 是个对象。参数 member 引用与之 相同的 对象。当我们修改 member 所引用对象的属性时, person 的相应属性也被修改了,因为他们引用了相同的对象。person 的 name 属性也变成了 “Lydia”。

4、下面代码的输出是什么? A

const name = "Lydia";
age = 21;
console.log(delete name);
console.log(delete age);

A. false, true B. “Lydia”, 21 C. true, true D. undefined, undefined delete 操作符返回一个布尔值:true 指删除成功,否则返回 false。 但是通过 var, const 或 let 关键字声明的变量无法用 delete 操作符来删除。

name 变量由 const 关键字声明,所以删除不成功:返回 false。而我们设定 age 等于 21时,我们实际上添加了一个名为 age 的属性给全局对象。对象中的属性是可以删除的,全局对象也是如此,所以 delete age 返回 true。

5、下面代码的输出是什么? D

const numbers = [1,2,3,4,5]
const [y] = numbers;
console.log(y);

A. [[1,2,3,4,5]] B. [1,2,3,4,5] C. [1] D. 1 通过解构赋值来解析来自对象的数组或属性的值,比如说:[a, b] = [1, 2]; a的值现在是 1, b的值现在是 2。而在题目中: [y] = [1, 2, 3, 4, 5]; 也就是说, y等于数组的第一个值就是数字 1,我们输出 y, 返回 1. 6、下面代码输出什么? C

const value = {number: 10};
const multiply = (x = {...value}) => {
	console.log(x.number *= 2);
};
multiply();
multiply();
multiply(value);
multiply(value);

A. 20, 40, 80, 160 B. 20, 40, 20, 40 C. 20, 20, 20, 40 D. NaN, NaN, 20, 40 在ES6中,我们可以使用默认值初始化参数。如果没有给函数传参,或者传的参值为 “undefined”,那么参数的值将是默认值。上述例子中,我们将 value 对象进行了解构并传到一个新对象中,因此 x 的默认值为 {number:10} 。

默认参数在调用时才会进行计算,每次调用函数时,都会创建一个新的对象。我们前两次调用 multiply 函数且不传递值,那么每一次 x 的默认值都为 {number:10} ,因此打印出该数字的乘积值为 20。

第三次调用 multiply 时,我们传递了一个参数,即对象 value。*= 运算符实际上是 x.number=x.number*2 的简写,我们修改了 x.number 的值,并打印出值 20。

第四次,我们再次传递 value对象。x.number 之前被修改为 20,所以 x.number*=2 打印为 40

7、下面代码输出什么? D [1,2,3,4].reduce((x,y)=> console.log(x,y)); A. 12 and 33 and 64 B. 12 and 23 and 34 C. 1undefined and 2undefined and 3undefined and 4undefined D. 1 2 and undefined 3 and undefined 4 语法: array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

reduce 函数接收4个参数: total:必需。初始值, 或者计算结束后的返回值。 currentValue:必需。当前元素。 currentIndex:可选。当前元素的索引。 arr:可选。当前元素所属的数组对象。

reduce 函数的返回值将会分配给累计器,该返回值在数组的每个迭代中被记住,并最后成为最终的单个结果值。

reduce 函数还有一个可选参数 initialValue, 该参数将作为第一次调用回调函数时的第一个参数的值。如果没有提供 initialValue,则将使用数组中的第一个元素。

在上述例子, reduce方法接收的第一个参数(Accumulator)是 x, 第二个参数(Current Value)是 y

在第一次调用时,累加器 x1,当前值 “y”2,打印出累加器和当前值:12

例子中我们的回调函数没有返回任何值,只是打印累加器的值和当前值。如果函数没有返回值,则默认返回 undefined。在下一次调用时,累加器为 undefined,当前值为“3”, 因此 undefined3被打印出。

在第四次调用时,回调函数依然没有返回值。累加器再次为 undefined ,当前值为“4”undefined4被打印出。

8、使用哪个构造函数可以成功继承 Dog 类? B

class Dog{
	constructor(name){
		this.name = name;
	}
}
class Labrador extends Dog{
	// 1
	constructor(name, size){
		this.size = size;
	}
	// 2
	constructor(name,size){
		super(name);
		this.size = size;
	}
	// 3
	constructor(size){
		super(name);
		this.size = size;
	}
	// 4
	constructor(name,size){
		this.name = name;
		this.size = size;
	}
}

A. 1 B. 2 C. 3 D. 4 解析: 在子类中,在调用 super 之前不能访问到 this 关键字。如果这样做,它将抛出一个 ReferenceError:1和4将引发一个引用错误。

使用 super 关键字,需要用给定的参数来调用父类的构造函数。父类的构造函数接收 name 参数,因此我们需要将 name 传递给 super

Labrador 类接收两个参数, name 参数是由于它继承了 Dogsize 作为 Labrador 类的额外属性,它们都需要传递给 Labrador 的构造函数,因此使用构造函数2正确完成。

9、如何能打印出 console.log 语句后注释掉的值? C

function* startGame(){
	const answer = yield "Do you love JavaScript?";
	if(answer !== "Yes"){
		return "Oh wow... Guess we're gone here";
	}
	return "JavaScript loves you back ??";
}
const game = startGame();
console.log(/* 1 */);  // Do you love JavaScript?
console.log(/* 1 */)   // JavaScript loves you back ??

A. game.next("Yes").value and game.next().value B. game.next.value("Yes") and game.next.value() C. game.next().value and game.next("Yes").value D. game.next.value() and game.next.value("Yes") generator 函数在遇到 yield关键字时会“暂停”其执行。首先,我们需要让函数产生字符串 Doyou loveJavaScript,这可以通过调用 game.next().value 来完成。上述函数的第一行就有一个 yield 关键字,那么运行立即停止了, yield 表达式本身没有返回值,或者说总是返回 undefined, 这意味着此时变量 answerundefined

next 方法可以带一个参数,该参数会被当作上一个 yield 表达式的返回值。当我们调用 game.next("Yes").value 时,先前的 yield 的返回值将被替换为传递给 next() 函数的参数 "Yes"。此时变量 answer 被赋值为 "Yes", if语句返回 false,所以 JavaScriptloves you back??被打印。

10、下面代码输出什么? A

async function getData(){
    return await Promise.resolve("I made it!");
}
const data = getData();
console.log(data);

A. “I made it!” B. Promise(< pending>) C. Promise(< resolved>:“I made it!”) D. undefined 异步函数始终返回一个promiseawait 仍然需要等待promise的解决:当我们调用 getData()并将其赋值给 data,此时 datagetData方法返回的一个挂起的 promise,该 promise 并没有解决。 如果我们想要访问已解决的值 "I made it!",可以在 data 上使用 .then() 方法:data.then(res=>console.log(res)) 这样将打印 "I made it!"

二、问答题 1、var、let const的区别?

var 定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。 let 定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。 const 用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。

    // 块作用域
    {
        var a = 1;
        let b = 2;
        const c = 3;
        // c = 4; // 报错
        var aa;
        let bb;
        // const cc; // 报错
        console.log(a); // 1
        console.log(b); // 2
        console.log(c); // 3
        console.log(aa); // undefined
        console.log(bb); // undefined
    }
    console.log(a); // 1
    // console.log(b); // 报错
    // console.log(c); // 报错
 
    // 函数作用域
    (function A() {
        var d = 5;
        let e = 6;
        const f = 7;
        console.log(d); // 5
        console.log(e); // 6  
        console.log(f); // 7 
 
    })();
    // console.log(d); // 报错
    // console.log(e); // 报错
    // console.log(f); // 报错

延伸:const定义的对象属性是否可以改变:可以改变 参考:https://blog.csdn.net/unionz/article/details/80032048

 const person = {
     name : 'jiuke',
     sex : '男'
 }
 person.name = 'test' 
 console.log(person.name)  //test

因为对象是引用类型的,person中保存的仅是对象的指针,这就意味着,const仅保证指针不发生改变,修改对象的属性不会改变对象的指针,所以是被允许的。也就是说const定义的引用类型只要指针不发生改变,其他的不论如何改变都是允许的。

2、vue中key值的作用是什么? 渲染列表时,key值需要一个唯一确定的id来赋值。

  • key是为每个vnode指定唯一的id,在同级vnode的Diff过程中,可以根据key快速的进行对比,来判断是否为相同节点。
  • 利用 key 的唯一性生成 map 对象来获取对应节点,比遍历方式更快,指定key后,可以保证渲染的准确性(尽可能的复用 DOM 元素。) 参考资料:https://www.jianshu.com/p/a634eb3c19c2

3、简单介绍 Promise 参考:https://www.jianshu.com/p/c8ebbc7d4c01

Promise 是一个对象,保存着未来将要结束的事件,她有两个特征:

  • 对象的状态不受外部影响,Promise对象代表一个异步操作,有三种状态,pending进行中,fulfilled已成功,rejected已失败,只有异步操作的结果,才可以决定当前是哪一种状态,任何其他操作都无法改变这个状态,这也就是promise名字的由来
  • 一旦状态改变,就不会再变,promise对象状态改变只有两种可能,从pending改到fulfilled或者从pending改到rejected,只要这两种情况发生,状态就凝固了,不会再改变,这个时候就称为定型resolved,

Promise的基本用法:

let promise1 = new Promise(function(resolve,reject){
    setTimeout(function(){
        resolve('ok')
    },1000)
})
promise1.then(function success(val){
    console.log(val)
})

最简单代码实现promise

class PromiseM {
    constructor (process) {
        this.status = 'pending'
        this.msg = ''
        process(this.resolve.bind(this), this.reject.bind(this))
        return this
    }
    resolve (val) {
        this.status = 'fulfilled'
        this.msg = val
    }
    reject (err) {
        this.status = 'rejected'
        this.msg = err
    }
    then (fufilled, reject) {
        if(this.status === 'fulfilled') {
            fufilled(this.msg)
        }
        if(this.status === 'rejected') {
            reject(this.msg)
        }
    }
}

测试代码:

var mm=new PromiseM(function(resolve,reject){
    resolve('123');
});
mm.then(function(success){
    console.log(success);
},function(){
    console.log('fail!');
});

4、computed 和 watched 的区别是什么? 共同点:

  • 都是监听数据变化的方法,用来观察和响应Vue实例上的数据变动。
  • 可以将复杂的逻辑放入到计算属性和watch 中,从而使得代码更加整齐,分工明确。

不同点:

  • computed
    • 类型:{ [key: string]: Function | { get: Function, set: Function } }
    • 计算属性将被混入到 Vue 事例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。但是如果使用了箭头函数,那么此时使用 this 就不会指向组件实例了。而且计算的结果是会被缓存的,除非依赖的响应式属性变化才会重新计算,这无疑在性能上更加友好。
    • 计算属性将变量的 get 属性重写成了定义的函数方法,实现了数据劫持。
    • 计算属性可以监听 data 和 props 里的值,只有当被监听的数据发生改变时,才会重新计算,从而得到一个新值。
    • 场景:一个数据受到多个数据的影响
  • watch
    • 类型:{ [key: string]: string | Function | Object | Array }
    • 那这里 key 是咱们要监听的数据,值可以是回调函数,方法名或者对象。同样的如果在watch 中使用箭头函数,则不要使用 this ,因为此时它不会指向 Vue 实例。
    • 会产生一个 watcher 对象,在监视的属性每次变动时都会触发回调
    • 监听 data 里的已知变量的变化
    • 场景:一个数据影响多个数据

5、请详细说下你对 Vue 生命周期的理解? vue生命周期总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。

  • 创建前/后:在beforeCreated阶段,vue实例的挂载完el还没有。

  • 载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。

  • 更新前/后:当data变化时,会触发beforeUpdate和updated方法。

  • 销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在。

    export default { data(){ return { ptext:“测试文本” } }, beforeCreate(){ console.log(‘enter beforeCreate’) }, created(){ console.log(‘enter created’) }, beforeMount(){ console.log(‘enter beforeMount’) }, mounted(){ console.log(‘enter mounted’) }, beforeDestroy(){ console.log(‘enter beforeDestroy’) }, destroyed(){ console.log(‘enter destroyed’) } }

补充:谈谈你对vue的双向数据绑定原理的理解 vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。 具体步骤:

  • 第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter。这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
  • 第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
  • 第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
    • 在自身实例化时往属性订阅器(dep)里面添加自己
    • 自身必须有一个update()方法
    • 待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
  • 第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

简而言之,就是先转化成AST树,再得到的render函数返回VNode(Vue的虚拟DOM节点)

6、介绍一下你对浏览器内核的理解? 主要分成两个部分:渲染引擎(Render Engine)和JS引擎。

  • 渲染引擎:负责取得网页的内容(html,xml和图像等),整理讯息(例如假如css),以及计算网页的显示方式,然后输出到显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不同。所有网页浏览器、电子邮件客户端以及它需要编辑、显示网络内容的应用程序都需要内核。
  • JS引擎:解析和执行JavaScript来实现网页的动态效果。<

标签: 16zs矩形连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台