前端面试题知识点整理(代码相关)

1、JS获取DOM元素

原生JS获取HTML DOM元素的8种方法

  1. 通过ID获取
  2. 通过name属性
  3. 通过标签名
  4. 通过类名
  5. 通过选择器获取一个元素
  6. 通过选择器获取一组元素
  7. 获取html
  8. 获取body

1、通过ID获取(getElementById)

document.getElementById('id')
  • 上下文必须是document。
  • 必须传参数,参数是string类型,是获取元素的id。
  • 返回值只获取到一个元素,没有找到返回null。

2、通过name属性(getElementsByName)

document.getElementsByName('name')
  • 上下文必须是document。
  • 必须传参数,参数是获取元素的name属性。
  • 返回值是一个类数组,没有找到返回空数组。

3、通过标签名(getElementsByTagName)

document.getElementsByTagName('div')
  • 上下文可以是document,也可以是一个元素,注意这个元素一定要存在。
  • 参数是是获取元素的标签名属性,不区分大小写。
  • 返回值是一个类数组,没有找到返回空数组。

4、通过类名(getElementsByClassName)

document.getElementsByClassName('class')
  • 上下文可以是document,也可以是一个元素。
  • 参数是元素的类名。
  • 返回值是一个类数组,没有找到返回空数组。

5、通过选择器获取一个元素(querySelector)

document.querySelector('.animated')
  • 上下文可以是document,也可以是一个元素。
  • 参数是选择器,如:”div .className”。
  • 返回值只获取到第一个元素。

6、通过选择器获取一组元素(querySelectorAll)

document.querySelectorAll('.animated')
  • 上下文可以是document,也可以是一个元素。
  • 参数是选择器,如:”div .className”。
  • 返回值是一个类数组。

7、获取html(document.documentElement)

document.documentElement是专门获取html这个标签的

8、获取body(document.body)

document.body是专门获取body这个标签的。

2、前端布局

一、静态布局

静态布局就是传统的网站形式,网页上的所有元素的尺寸一律使用px作为单位。

1.布局特点

不管浏览器尺寸具体是多少,网页布局始终按照最初写代码时的布局来显示。常规的pc的网站都是静态(定宽度)布局的,也就是设置了min-width,这样的话,如果小于这个宽度就会出现滚动条,如果大于这个宽度则内容居中外加背景,这种设计常见于pc端。

2.设计方法

--------PC--------
居中布局,所有样式使用绝对宽度/高度(px),设计一个Layout,当窗口缩小时,内容被遮挡,呈现横竖向滚动条。
--------优点--------
这种布局方式对设计师和CSS编写者来说都是最简单的,亦没有兼容性问题。
--------缺点--------
显而易见,即不能根据用户的屏幕尺寸做出不同的表现。当前,大部分门户网站、大部分企业的PC宣传站点都采用了这种布局方式。固定像素尺寸的网页是匹配固定像素尺寸显示器的最简单办法。但这种方法不是一种完全兼容未来网页的制作方法,我们需要一些适应未知设备的方法。

二、自适应布局

简单来说就是分别为不同的屏幕分辨率定义布局,即创建多个静态布局,每个静态布局对应一个屏幕分辨率范围。

1.布局特点

屏幕分辨率变化时,页面里面元素的位置会变化而大小不会变化。

2.设计方法

使用 @media 媒体查询给不同尺寸和介质的设备切换不同的样式。
在优秀的响应范围设计下可以给适配范围内的设备最好的体验,在同一个设备下实际还是固定的布局。

三、流式布局(栅格布局)

页面元素的宽度按照屏幕分辨率进行适配调整,但整体布局不变。

1.布局特点

当屏幕分辨率变化时,页面里元素的大小会变化而但布局不变。这就导致如果屏幕太大或者太小都会导致元素无法正常显示。

2.设计方法

(1)使用百分比定义宽度,高度大都是用px来固定住,可以根据可视区域 (viewport) 和父元素的实时尺寸进行调整,尽可能的适应各种分辨率。往往配合 max-width/min-width 等属性控制尺寸流动范围以免过大或者过小影响阅读。

(2)这种布局方式在Web前端开发的早期历史上,用来应对不同尺寸的PC屏幕(那时屏幕尺寸的差异不会太大),在当今的移动端开发也是常用布局方式,但缺点明显:主要的问题是如果屏幕尺度跨度太大,那么在相对其原始设计而言过小或过大的屏幕上不能正常显示。

(3)因为宽度使用%百分比定义,但是高度和文字大小等大都是用px来固定,所以在大屏幕的手机下显示效果会变成有些页面元素宽度被拉的很长,但是高度、文字大小还是和原来一样,显示非常不协调。

3.主要的问题

是在于如果屏幕尺度跨度太大,那么在相对其原始设计而言过小或过大的屏幕上不能正常显示。网页中主要的划分区域的尺寸使用百分数(搭配min-*、max-*属性使用)。例如,设置网页主体的宽度为80%,min-width为960px。图片也作类似处理(width:100%, max-width一般设定为图片本身的尺寸,防止被拉伸而失真)。

四、响应式布局

为不同的屏幕分辨率定义布局,同时,在每个布局中,应用流式布局的理念,即页面元素宽度随着窗口调整而自动适配。可以把响应式布局看作是流式布局自适应布局设计理念的融合。即:创建多个流式布局,分别对应一个屏幕分辨率范围。响应式几乎已经成为优秀页面布局的标准。

1.布局特点

每个屏幕分辨率下面会有一个布局样式,即元素位置和大小都会变。

2.设计方法

媒体查询+流式布局。通常使用 @media 媒体查询 和网格系统 (Grid System) 配合相对布局单位进行布局,实际上就是综合响应式、流动等上述技术通过 CSS 给单一网页不同设备返回不同样式的技术统称。

--------优点--------
适应pc和移动端,如果足够耐心,效果完美。

--------缺点--------
(1)媒体查询是有限的,也就是可以枚举出来的,只能适应主流的宽高。
(2)要匹配足够多的屏幕大小,工作量不小,设计也需要多个版本。

五、弹性布局(rem/em布局)

rem是相对于html元素的font-size大小而言的,而em是相对于其父元素。使用rem单位的弹性布局在移动端很受欢迎。

1.优点

(1)适应性强,在做不同屏幕分辨率的界面时非常实用
(2)可以随意按照宽度、比例划分元素的宽高
(3)可以轻松改变元素的显示顺序
(4)弹性布局实现快捷,易维护

3、JS深拷贝和浅拷贝

1、浅拷贝和深拷贝都只针对于引用数据类型
2、浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存
3、深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象;
4、区别:浅拷贝只复制对象的第一层属性、深拷贝可以对对象的属性进行递归复制;
5、slice() 和 concat() 都并非深拷贝;

浅拷贝:

let obj2 = Object.assign({},obj1)

Object.assign()实现浅拷贝及一层的深拷贝

深拷贝:

var obj2 = $.extend(true, {}, obj1)

jquery 实现深拷贝:jquery 提供一个$.extend可以用来做深拷贝

4、CSS盒模型

每个盒模型都由元素的内容(content)、内边距(padding)、边框(border)和外边距(margin)组成。
盒模型分为标准盒模型和IE盒模型。
盒模型默认为标准盒模型,在标准盒模型下通过设置 box-sizing: border-box; 可转换为 IE 盒模型。

标准盒模型

  • 元素的 width、height 只包含内容 content,不包含 border 和 padding 值;
  • 盒子的大小由元素的宽高、边框和内边距决定。

我们用盒子的宽高来度量盒子的大小,可以看做是总的元素宽度和高度,与元素本身设置的宽高(width、height)不是同一个概念。

盒子的宽 = width + border-width * 2 + padding-left + padding-right
盒子的高 = height + border-width * 2 + padding-top + padding-bottom

IE盒模型

  • 元素的 width、height 不仅包括 content,还包括 border 和 padding;
  • 盒子的大小取决于 width、height,修改 border 和 padding 值不能改变盒子的大小。

在 IE 盒模型中,border 和padding 的空间会挤压 content 的空间,使得元素的内容宽高小于 width、height 设置的值。

5、数组去重

1、Array.filter() + indexOf

使用 ES6 中的 Array.filter() 遍历数组,并结合 indexOf 来排除重复项

function (arr) {
    return arr.filter((item, index)=> {
        return arr.indexOf(item) === index
    })
}

2、双重 for 循环

外层循环遍历元素,内层循环检查是否重复,也可以把循环改成递归,当有重复值的时候,可以使用 push(),也可以使用 splice()

function(arr) {
    for (let i=0, len=arr.length; i<len; i++) {
        for (let j=i+1; j<len; j++) {
            if (arr[i] == arr[j]) {
                arr.splice(j, 1);
                // splice 会改变数组长度,所以要将数组长度 len 和下标 j 减一
                len--;
                j--;
            }
        }
    }
    return arr
}

3、for…of + includes()

双重for循环的升级版,外层用 for…of 语句替换 for 循环,(也可以换成Array.reduce(),每次将元素加到新数组的末尾并返回这个新数组),再把内层循环改为 includes()。先创建一个空数组,当 includes() 返回 false 的时候,就将该元素 push 到空数组中 。类似的,还可以用 indexOf() 来替代 includes()

function(arr) {
    let result = []
    for (let i of arr) {
        !result.includes(i) && result.push(i)
    }
    return result
}

4、Array.sort()

首先使用 sort() 将数组进行排序,然后比较相邻元素是否相等,从而排除重复项

function(arr) {
    arr = arr.sort()
    let result = [arr[0]]
    for (let i=1, len=arr.length; i<len; i++) {
        arr[i] !== arr[i-1] && result.push(arr[i])
    }
    return result
}

5、new Set()

ES6 新增了 Set 这一数据结构,类似于数组,但Set 的成员具有唯一性

function(arr) {
    return Array.from(new Set(arr))
}

6、for…of + Object / Map

用 for 循环遍历,利用对象的key不会重复这一特性,校验数组元素是否重复
因为对象的key只能是字符串,所以不能直接使用 obj[i] 或者 obj[i + i] ,例如[“1”,1,11]这种时候,会把这些值当成同一个值
也可以用Map代替Object,Map同样有key不会重复的特性,而且Map的key可以是任意值,也就是说可以直接使用 i 作为Map的key

function(arr) {
    let result = []
    let obj = {}
    for (let i of arr) {
        if (!obj[typeof i + i]) {
            result.push(i)
            obj[typeof i + i] = 1
        }
    }
    return result
}
function(arr) {
    var obj = {};
    return arr.filter(function(item, index, arr){
        return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
        //利用hasOwnProperty 判断是否存在对象属性
    })
}

6、获取对象的key

1、for…in 循环

可以加上hasOwnProperty()方法过滤掉非对象自身的属性(继承自原型链的属性)

2、Object.keys()

Object.keys(obj) 方法会返回一个由一个给定对象的自身可枚举属性组成的字符串数组,数组中属性名的排列顺序和使用 for…in 循环遍历该对象时返回的顺序一致 。

3、Object.getOwnPropertyNames()

Object.getOwnPropertyNames(obj) 返回一个数组,该数组的元素是 obj 自身拥有的枚举或不可枚举属性名称字符串。 数组中枚举属性的顺序与通过 for…in 循环(或 Object.keys)迭代该对象属性时一致。数组中不可枚举属性的顺序未定义。

7、CSS经典三栏布局

这种三栏布局都是两边固定宽度,中间自适应,并且主要内容要优先渲染,按照 DOM 从上至下的加载原则,中间的自适应部分要放在前面。
其中耳熟能详的便是圣杯布局和双飞翼布局了,这里因为篇幅问题,就没有放具体代码了,大家有兴趣的话可以点击小标题的超链接查看。

8、CSS选择器及优先级

选择器分类

CSS的选择器其实大类的话可以分为三类,即id选择器、class选择器、标签选择器。

  • id选择器: #id名 { 属性名:属性值; }
  • class选择器 :.class名 { 属性名:属性值; }
  • 标签选择器: 标签名 { 属性名:属性值; }

其中,他们之间又可以以不同的方式进行组合,如下:

  • 后代选择器: 父代名 后代名 { 属性名:属性值; }
  • 子代选择器:父代名>子代名 { 属性名:属性值; }
  • 群组选择器: #name1, .name2, #name div { 属性名:属性值; }
  • 伪类选择器: name:伪类
  • 通用(通配符)选择器:* { 属性名: 属性值; } ……

选择器优先级

  • 最高优先级是 (直接在标签中的设置样式,假设级别为1000)
  • 次优先级是(ID选择器 ,假设级别为100) #myDiv{color:Red;}
  • 其次优先级是(类选择器,假设级别为10).divClass{color:Red;}
  • 最后优先级是 (标签选择器,假设级别是 1) div{color:Red;}

比如 .divClass span { color:Red;} 优先级别就是:10+1=11
可以在样式后面加上!important将优先级设置成最高

9、CSS元素水平居中

1、margin和width实现水平居中

给元素定义一个宽度,然后配合margin的左右值为“auto”实现

2、inline-block实现水平居中

设置子元素为display: inline-block; 或 display: inline;即将其转换成行内块级/行内元素,给父元素设置 text-align: center;

3、使用浮动

首先让父元素和子元素都向左浮动
浮动1
再通过“position:relative”属性让父元素向右移动50%(left:50%;)
浮动2
紧接着在子元素上也定义“position:relative”属性,但其移动的方向和父元素移动的方向刚好是反方向,而其移动的值保持一致(right: 50%;)
浮动3

4、使用定位属性

思路有点类似上一个方法,首先设置父元素为相对定位,再设置子元素为绝对定位,设置子元素的left:50%,即让子元素的左上角水平居中;再设置绝对子元素的 margin-left: -元素宽度的一半px(定宽); 或者设置transform: translateX(-50%)(不定宽);

5、使用flexbox布局

给父元素添加属性 display: flex; justify-content: center;

6、使用CSS3的fit-content

“fit-content”是CSS中给“width”属性新加的一个属性值,给元素添加属性 width: fit-content; 然后配合margin的左右值为“auto”实现

10、typeof与instanceof的区别

typeof是一元运算符,typeof a返回值为字符串,该字符串用来获取运算数的数据类型。返回的值有number、boolean、undefined、function、object、string。
而对象、数组、null以及函数实例(new + 函数)这些引用类型都会返回object。正因为typeof遇到数组、null都会返回object,所以我们要判断某个对象是否是数组或者某个变量是否是对象的实例时就要使用instanceof。
instanceof运算符用来判断一个构造函数的prototype属性所指向的对象是否存在另外一个要检测对象的原型链上。通常来讲,使用 instanceof 就是判断一个实例是否属于某种类型,或者用于继承关系。obj1 instanceof obj2返回值为布尔值。

11、大数相加

Number.MAX_VALUE // 1.7976931348623157e+308
Number.MAX_SAFE_INTEGER // 9007199254740991
Number.MIN_VALUE // 5e-324
Number.MIN_SAFE_INTEGER // -9007199254740991

Js 和任何一门语言一样,对其数值的范围有限制。
如果我们想要对一个超大的整数(> Number.MAX_SAFE_INTEGER)进行加法运算,但是又想输出一般形式,那么使用 + 是无法达到的,一旦数字超过 Number.MAX_SAFE_INTEGER 数字会被立即转换为科学计数法,并且数字精度相比以前将会有误差。在此时就需要自己实现一套加法算法。

function sumBigNumber(a, b) {
  var res = '',
    temp = 0;
  a = a.split('');
  b = b.split('');
  while (a.length || b.length || temp) {
    temp += ~~a.pop() + ~~b.pop();
    res = (temp % 10) + res;
    temp = temp > 9;
  }
  return res.replace(/^0+/, '');
}
sumBigNumber('100000000000002222', '111111'); // 100000000000113333
sumBigNumber('3782647863278468012934670', '23784678091370408971329048718239749083'); // 23784678091374191619192327186252683753
  • 首先我们用字符串的形式来保存大数,就保证了其在数学表示上不会发生变化
  • 初始化res,temp变量来保存中间计算的结果,再将两个字符串split为数组,以便我们进行每一位的运算
  • 循环的第一次就是进行"个位"的运算,将二者最末尾的两个数相加,由于每一位数字是0 - 9,所以需要进行进位,在经过取余数操作后,将结果保留在个位。 判断 temp 是否大于 9,若是则将 temp 赋值为 true
  • 在两个大数中的一个还有数字没有参与运算,或者前一次运算发生进位后,进行下一次循环
  • ~~是为了将字符串转换为数字
  • 接着除了对新的两个数字相加还要加上 temp,若上次发生了进位,则此时 temptrue,Js因为存在隐式转换,所以 true 转换为 1,我们借用 Js 的类型转换,完成了逻辑上的逢10进1操作
  • 接下来就是重复上述的操作,直到计算结束
  • replace(/^0+/, '')若结果是以0开头,则输出空字符串''

12、回文检测

给定一个长度为N的字符串,求最长回文子串。

function returnStr(str){
    console.log(str);
    var arr = [],s = "";
    for(var i=0;i<str.length;i++){
        s = "";
        
        //若回文是ABBA格式
        if(str.charAt(i)==str.charAt(i+1)){
            var j=0;
            while(str.charAt(i+j+1)==str.charAt(i-j)){
                s = str.charAt(i-j) + s + str.charAt(i+j+1);
                j++;
            }
            arr.push(s);
             
        //若回文是ABCBA格式
        }else if(str.charAt(i-1)==str.charAt(i+1)){
            var m=1;
            s = str.charAt(i);
            while(str.charAt(i+m)==str.charAt(i-m)){
                s = str.charAt(i-m) + s + str.charAt(i+m);
                m++;
            }
            arr.push(s);
        }
         
    }
    //等到所有回文字符串的数组;然后取值的最长
    var length =0 ;k = "";
    arr.forEach(function(val,key){
        if(val.length>length){
            length = val.length;
            k = val;
        }
    });
     
    return "所有回文字符串的集合是:"+arr+",最长的回文字符串的长度是:"+length+",内容是:"+k;
     
}
console.log(returnStr("adbdabccbalkj123321jkasdfaswtweypoiuiopsdf"));

13、代码执行顺序题

    new Promise((resolve) => {
console.log('1')
    resolve()
console.log('2')
     }).then(() => {
    console.log('3')
     })
     setTimeout(() => {
    console.log('4')
     })
     console.log('5')

执行顺序为1 2 5 3 4

  1. 首先会执行从上往下执行,Promise内部的代码也会同步执行,所以会打印1、2、5,
  2. 遇到的Promise、setTimeout会放到事件队列里面,其中Promise为微任务,setTimeout为宏任务
  3. 而script也是宏任务,在执行一次宏任务,之后会把满足条件的微任务执行完,然后在执行宏任务,再把满足条件的微任务执行完,直到执行完所有的微任务、宏任务
  4. 因此接下来会执行Promise的then方法 打印 3
  5. 执行宏任务setTimeout打印4

14、连续二进制

计算一个整数的二进制表示中连续出现1最多的次数。
比如13的二进制是:1101,那么他的二进制表示中连续出现的1最多为2次,所以答案就是2。

number.toString(2).match(/1+/g).map((x)=>x.length).reduce((x,y)=> x>y?x:y)
  1. 首先通过toString转化为二进制形式的字符串
  2. 然后通过正则匹配所有的连续的1,由于match(g)全局匹配,返回匹配的字符串数组
  3. 通过map方法得到每个匹配数组的长度
  4. 然后reduce得到最大值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值