11day-Web 前端 JavaScript 测试

Web 前端 JavaScript 测试

一、 简答题(50)

1、 JavaScript 的数据类型有哪些?(2)

简单数据类型:number、string、boolean、null、undefined
引用数据类型:function、Object、Array

2、 如何进行数据类型的判断?(2)

typeof
Object.prototype.toString().call(data).slice(8,-1)

3、 null 和 undefined 的区别?(2)

null:表示空值
undefined:表示定义了,但没有赋值

4、 使用 continue 或 break 终止循环时,两种方式的区别是?(2)

continue:表示跳过当前这次循环,直接进入下一个循环
break:终止整个循环

5、 如何判断字符串内是否包含指定字符?(3)

indexOf
lastIndexOf
includes

6、 列举 5 个 String 方法以及用处(5)

indexOf:查找指定字符,如果找到返回对应字符位置下标,否则返回-1
includes:查找指定字符,找到返回 true,反之 false
slice:截取字符串,特点:包前不包后,允许负数
split:切割字符串,最终以数组的形式返回,数组中的每一项为分割开的字符串
concat:拼接字符串

7、 请尽量列举出 Array 方法,并且注明作用以及哪些方法会修改原数组,哪些不会 (5)

会修改原数组:push、pop、shift、unshift、splice、reverse、sort
不会修改原数组:forEach、reduce、filter、concat、join、slice、map、some、every

8、 什么是函数作用域和作用域链? (3)

作用域:指某一变量或函数访问权限的代码空间。作用域也可以堆叠成层次结构,子作用域可以访问父作用域,反之则不行。

函数作用域:局部作用域

作用域链:各个作用域的嵌套关系组成的一条作用域链。假设有 a1、a2、a3 三个函数,他们是嵌套关系 a1>a2>a3。在 a3 函数中访问某一变量,当前 a3 函数作用域中没有那么就会往上寻找找到 a2 函数作用域,再没有继续往上找到 a1,在没有就继续找到全局作用域,在没有就报错。那么在这个一层一层往上寻找的过程中就产生了一条访问链,这个链就叫做作用域链

作用域链主要是进行标识符(变量和函数)的查询,标识符解析就是沿着作用域链一级一级的搜索标识符的过程,而作用域链就是保证对变量和函数的有序访问。

9、 请写出下面语句的输出结果 (3)

var bar = true;
number = 0;
console.log(bar + 0); // 1
console.log(bar + "xyz"); // truexyz
console.log(bar + true); // 2
console.log(+true); // 1
console.log(!"bluej"); // false
console.log(number++); // 0
console.log(++number)// 2
console.log(number); // 2

10、 对象有几种操作语法,有什么区别?(2)

点语法、数组关联语法
区别:
关于变量:
点语法无法解析变量,即使在点语法后跟上一个变量,这个变量的变量名会被解析为字符串,而数组关联语法可以解析变量,也可以访问对象中的键名。
关于特殊键名:
数组关联语法可以正常访问如 font-size 这种特殊键名,但点语法会报错

11、 js 中,变量是存放在哪里的,数据存放有什么区别?(3)

变量一般存在于作用域中,数据存放于内存中
简单数据存放在栈内存中
复杂数据存放在堆内存中

12、 js 中什么情况下会发生提升,如果 var 声明的变量与提升的函数重名会发生什么?(5)

使用 var 关键字声明变量以及声明式函数会发生提升
var 声明变量与提升的函数名称发生重名时,在提升阶段会以函数为准。当开始执行代码时,变量被赋值之后,即使变量的赋值在函数定义前面,这个名称从此以后也都是被赋值的那个值。函数不会在重新声明。

13、 值传递和引用传递的区别?(2)

值传递一般出现在简单数据类型中,传递过后,两个值不会发生关联
引用传递一般出现在复杂数据类型中,这时传递的是指向这个数据的指针,所以此时对一个变量进行操作另一个也会出现相应的改变。

14、 简述 js 编译原理(编译经历的三个阶段)。(6)

  1. 分词/词法分析:
    分词:把由字符组成的代码分解成有意义的代码块,这些代码块称为词法单元。
    词法分析:如果生成的词法单元是已经声明的,那么解析的过程就被称为词法分析。
  2. 解析/语法分析:
    将词法单元流(数组)转换为有层次关系的抽象语法树(Abstract Syntax Tree,AST)
  3. 代码生成:
    将 AST 转换为可执行代码的过程被称为代码生成
    15、 简述深拷贝的原理(自己的理解)。(5)
    例如现需要拷贝一个对象,在这个对象中有一些人物信息,还分别有一个对象和数组,在这里面还有其他数据。
    首先第一步,在最外面创建出一个新对象
    第二步:开始对原对象进行遍历(拿到这个对象中所有的值)
    第三步:在循环中进行使用 Object.prototype.toString().call(data).slice(8,-1) 判断,判断当前被遍历是否为对象或数组亦或是基本数据类型。
    第四步:根据判断结果进行操作,
    如果是对象则在新对象中对应位置创建一个新对象,之后遍历该对象,拿到里面所有的值,之后在做判断,如果还有复杂数据类型,则重复前面的操作。
    如果判断是数组,则在新对象中对应为创建一个新数组,之后遍历该数组,拿到所有的值,在做判断,如果还有复杂数据类型,则重复前面的操作。
    如果判断是简单数据类型则直接进行复制。
    以上步骤重复执行直到没有最后将被拷贝对象中的所有值全部拷贝完成即可。

二、 编程题(50)

1、 写出五种数组去重的方法(10)

  let arr = [1, 2, 3, 4, 3, 2, 1, 1, 2, 3, 2, 1, 2, 3, 4, 5];

//  方案 1
//  排序
arr.sort(function (a, b) {
return a - b;
});
//  把连在一起的删除
for (var i = 0; i < arr.length; i++) {
//判断当前的和下一个   是否一样
if (arr[i] === arr[i + 1]) {
//如果一样就删除
    arr.splice(i, 1);
//为了解决塌陷
    i--;
}
}

//  方案 2
//  准备一个新数组
let newArr = [];
//遍历原来的数组
for (var i = 0; i < arr.length; i++) {
//arr[i]原来数组中的每一个
if (newArr.indexOf(arr[i]) === -1) {
//newArr 没有该元素,就 push
    newArr.push(arr[i]);
}
}

//  方案 3
// es6 有一个数据类型叫 Set  他天生不允许重复
arr = [...new Set(arr)]

//  方案 4
//  循环遍历原数组
for (let i = 0; i < arr.length; i++) {
let index = arr.indexOf(arr[i], i + 1);
//  每一个数据判断他的后面是不是还出现了同样的数据
if (index !== -1) {
    arr.splice(index, 1);
//  防止数组塌陷
    i--;
}
}

//  方案 5
let res = arr.reduce(function(prev,item){
if(!prev.includes(item)){
return [...prev,item]
}
return prev
},[])
console.log(res);

2、 写出两种数组排序的方法(5)

//  冒泡排序
for (var i = 0; i < arr.length - 1; i++) {
for (var j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
var tmp = arr[j];
            arr[j] = arr[j + 1];
            arr[j + 1] = tmp;
}
}
}

//  选择排序
for (var j = 0; j < arr.length - 1; j++) {
// 1-1.  假设最小数字的索引是  0
var minIndex = j;

        // 1-2. 循环找到真实最小数字的索引
        for (var i = j + 1; i < arr.length; i++) {
          if (arr[i] < arr[minIndex]) {

minIndex = i;
}
}

        // 1-3. 让索引 j 和 索引 minIndex 交换
        var tmp = arr[j];

arr[j] = arr[minIndex];
        arr[minIndex] = tmp;
}

3、 数组内部成员随机打乱(5)

let arr = ["特等奖", "一等奖", "二等奖", "三等奖", "四等奖", "安慰奖"];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
var randomNum = Math.floor(Math.random() \* arr.length);
if (newArr.indexOf(arr[randomNum]) == -1) {
    newArr.push(arr[randomNum]);
} else {
    i--;
}
}
console.log(newArr);

let arr = ["特等奖", "一等奖", "二等奖", "三等奖", "四等奖", "安慰奖"];
var newArr = [];
for (var i = arr.length; i >= 1; i--) {
var randomNum = Math.floor(Math.random() _ i);
if (randomNum != i - 1) {
[arr[randomNum], arr[i - 1]] = [arr[i - 1], arr[randomNum]];
}
}
console.log(arr);

4、 封装函数,求随机颜色的函数、时间差的函数、求斐波那契数列第 n 位函数、格式化时间函数、(10)

function randomColor() {
let r = Math.floor(Math.random() _ 256);
let g = Math.floor(Math.random() _ 256);
let b = Math.floor(Math.random() _ 256);
return `rgb(${r},${g},${b})`;
}

let nowTime = new Date().getTime();
let willTime = new Date(2023, 6, 30).getTime();
console.log(computeTime(nowTime, willTime));

function computeTime(nowTime, willTime) {
if (nowTime > willTime) {
let temp = nowTime;
        nowTime = willTime;
        willTime = temp;
}
let time = willTime - nowTime;
let s = parseInt(time / 1000 % 60);
let m = parseInt(time / 1000 / 60 % 60);
let h = parseInt(time / 1000 / 60 / 60 % 24);
let d = parseInt(time / 1000 / 60 / 60 / 24);
return `时间差为${d}${h}${m}${s}`;
}

function sum(n) {
if (n == 1 || n == 2) {
return 1;
} else {
return sum(n - 2) + sum(n - 1);
}
}

function initTime(time) {
let seconds = time.getSeconds();
let minutes = time.getMinutes();
let hours = time.getHours();
let day = time.getDate();
let month = time.getMonth() + 1;
let year = time.getFullYear();
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

5、 写出三种数组统计出现次数的方法(10)

// 1.
const arr = [3,2,3,3,5,6,5,5,8,4,4,7,7,7];
const obj = {};

for (let i in arr) {
  obj[arr[i]] = obj[arr[i]]++ || 1
}

// 2.
arr.reduce(function(prev,item){
    prev[item] ? prev[item]++ : prev[item] = 1;
return prev;
},{})

// 3.
let arr = [1, 2, 3, 4, 5, 1, 2, 3, 4, 1, 2, 1, 3, 4, 1, 2, 3, 1, 2];

      // Statistical deduplication
      function SD(arr) {
        let Sarr = [...new Set(arr)];
        let Dobj = arr.reduce(function(prev,item){

prev[item] ? prev[item]++ : prev[item] = 1;
return prev;
},{})

        return {

Sarr,
          Dobj,
}
}

6、 写一个深拷贝函数(10)

function deepClone(obj={}) {
if ( typeof obj !== 'object' || obj == null ){
return obj
}
let result
if ( obj instanceof Array ){
     result = []
} else {
     result = {}
}
for ( let key in obj){
if ( obj.hasOwnProperty( key )){
      result[key] = deepClone(obj[key])
}
}
return result
}

function copy(data, newData) {
for (let key in data) {
let temp = data[key];
if (Object.prototype..call(temp).slice(8,-1) == "Object") {
            newData[key] = {};
copy(temp, data[key])
} else if (Object.prototype..call(temp).slice(8,-1) == "Array") {
            newData[key] = [];
copy(temp, data[key])
} else {
            newData[key] = temp;
}
}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值