关于javascript:前端面试比较好的回答

36次阅读

共计 10743 个字符,预计需要花费 27 分钟才能阅读完成。

DNS 同时应用 TCP 和 UDP 协定?

DNS 占用 53 号端口,同时应用 TCP 和 UDP 协定。(1)在区域传输的时候应用 TCP 协定

  • 辅域名服务器会定时(个别 3 小时)向主域名服务器进行查问以便理解数据是否有变动。如有变动,会执行一次区域传送,进行数据同步。区域传送应用 TCP 而不是 UDP,因为数据同步传送的数据量比一个申请应答的数据量要多得多。
  • TCP 是一种牢靠连贯,保障了数据的准确性。

(2)在域名解析的时候应用 UDP 协定

  • 客户端向 DNS 服务器查问域名,个别返回的内容都不超过 512 字节,用 UDP 传输即可。不必通过三次握手,这样 DNS 服务器负载更低,响应更快。实践上说,客户端也能够指定向 DNS 服务器查问时用 TCP,但事实上,很多 DNS 服务器进行配置的时候,仅反对 UDP 查问包。

常见的 DOM 操作有哪些

1)DOM 节点的获取

DOM 节点的获取的 API 及应用:

getElementById // 依照 id 查问
getElementsByTagName // 依照标签名查问
getElementsByClassName // 依照类名查问
querySelectorAll // 依照 css 选择器查问

// 依照 id 查问
var imooc = document.getElementById('imooc') // 查问到 id 为 imooc 的元素
// 依照标签名查问
var pList = document.getElementsByTagName('p')  // 查问到标签为 p 的汇合
console.log(divList.length)
console.log(divList[0])
// 依照类名查问
var moocList = document.getElementsByClassName('mooc') // 查问到类名为 mooc 的汇合
// 依照 css 选择器查问
var pList = document.querySelectorAll('.mooc') // 查问到类名为 mooc 的汇合

2)DOM 节点的创立

创立一个新节点,并把它增加到指定节点的前面。 已知的 HTML 构造如下:

<html>
  <head>
    <title>DEMO</title>
  </head>
  <body>
    <div id="container"> 
      <h1 id="title"> 我是题目 </h1>
    </div>   
  </body>
</html>

要求增加一个有内容的 span 节点到 id 为 title 的节点前面,做法就是:

// 首先获取父节点
var container = document.getElementById('container')
// 创立新节点
var targetSpan = document.createElement('span')
// 设置 span 节点的内容
targetSpan.innerHTML = 'hello world'
// 把新创建的元素塞进父节点里去
container.appendChild(targetSpan)

3)DOM 节点的删除

删除指定的 DOM 节点, 已知的 HTML 构造如下:

<html>
  <head>
    <title>DEMO</title>
  </head>
  <body>
    <div id="container">       <h1 id="title"> 我是题目 </h1>
    </div>     </body>
</html>

须要删除 id 为 title 的元素,做法是:

// 获取指标元素的父元素
var container = document.getElementById('container')
// 获取指标元素
var targetNode = document.getElementById('title')
// 删除指标元素
container.removeChild(targetNode)

或者通过子节点数组来实现删除:

// 获取指标元素的父元素 var container = document.getElementById('container')// 获取指标元素 var targetNode = container.childNodes[1]// 删除指标元素 container.removeChild(targetNode)

4)批改 DOM 元素

批改 DOM 元素这个动作能够分很多维度,比如说挪动 DOM 元素的地位,批改 DOM 元素的属性等。

将指定的两个 DOM 元素替换地位, 已知的 HTML 构造如下:

<html>
  <head>
    <title>DEMO</title>
  </head>
  <body>
    <div id="container">       <h1 id="title"> 我是题目 </h1>
      <p id="content"> 我是内容 </p>
    </div>     </body>
</html>

当初须要调换 title 和 content 的地位,能够思考 insertBefore 或者 appendChild:

// 获取父元素
var container = document.getElementById('container')   

// 获取两个须要被替换的元素
var title = document.getElementById('title')
var content = document.getElementById('content')
// 替换两个元素,把 content 置于 title 后面
container.insertBefore(content, title)

什么是 margin 重叠问题?如何解决?

问题形容: 两个块级元素的上外边距和下外边距可能会合并(折叠)为一个外边距,其大小会取其中外边距值大的那个,这种行为就是外边距折叠。须要留神的是,浮动的元素和相对定位 这种脱离文档流的元素的外边距不会折叠。重叠只会呈现在 垂直方向

计算准则: 折叠合并后外边距的计算准则如下:

  • 如果两者都是负数,那么就去最大者
  • 如果是一正一负,就会正值减去负值的绝对值
  • 两个都是负值时,用 0 减去两个中绝对值大的那个

解决办法: 对于折叠的状况,次要有两种:兄弟之间重叠 父子之间重叠(1)兄弟之间重叠

  • 底部元素变为行内盒子:display: inline-block
  • 底部元素设置浮动:float
  • 底部元素的 position 的值为absolute/fixed

(2)父子之间重叠

  • 父元素退出:overflow: hidden
  • 父元素增加通明边框:border:1px solid transparent
  • 子元素变为行内盒子:display: inline-block
  • 子元素退出浮动属性或定位

箭头函数与一般函数的区别

(1)箭头函数比一般函数更加简洁

  • 如果没有参数,就间接写一个空括号即可
  • 如果只有一个参数,能够省去参数的括号
  • 如果有多个参数,用逗号宰割
  • 如果函数体的返回值只有一句,能够省略大括号
  • 如果函数体不须要返回值,且只有一句话,能够给这个语句后面加一个 void 关键字。最常见的就是调用一个函数:
let fn = () => void doesNotReturn();

(2)箭头函数没有本人的 this

箭头函数不会创立本人的 this,所以它没有本人的 this,它只会在本人作用域的上一层继承 this。所以箭头函数中 this 的指向在它在定义时曾经确定了,之后不会扭转。

(3)箭头函数继承来的 this 指向永远不会扭转

var id = 'GLOBAL';
var obj = {
  id: 'OBJ',
  a: function(){console.log(this.id);
  },
  b: () => {console.log(this.id);
  }
};
obj.a();    // 'OBJ'
obj.b();    // 'GLOBAL'
new obj.a()  // undefined
new obj.b()  // Uncaught TypeError: obj.b is not a constructor

对象 obj 的办法 b 是应用箭头函数定义的,这个函数中的 this 就永远指向它定义时所处的全局执行环境中的 this,即使这个函数是作为对象 obj 的办法调用,this 仍旧指向 Window 对象。须要留神,定义对象的大括号 {} 是无奈造成一个独自的执行环境的,它仍旧是处于全局执行环境中。

(4)call()、apply()、bind()等办法不能扭转箭头函数中 this 的指向

var id = 'Global';
let fun1 = () => {console.log(this.id)
};
fun1();                     // 'Global'
fun1.call({id: 'Obj'});     // 'Global'
fun1.apply({id: 'Obj'});    // 'Global'
fun1.bind({id: 'Obj'})();   // 'Global'

(5)箭头函数不能作为构造函数应用

构造函数在 new 的步骤在下面曾经说过了,实际上第二步就是将函数中的 this 指向该对象。然而因为箭头函数时没有本人的 this 的,且 this 指向外层的执行环境,且不能扭转指向,所以不能当做构造函数应用。

(6)箭头函数没有本人的 arguments

箭头函数没有本人的 arguments 对象。在箭头函数中拜访 arguments 实际上取得的是它外层函数的 arguments 值。

(7)箭头函数没有 prototype

(8)箭头函数不能用作 Generator 函数,不能应用 yeild 关键字

参考:前端进阶面试题具体解答

什么是作用域链?

首先要理解作用域链,当拜访一个变量时,编译器在执行这段代码时,会首先从以后的作用域中查找是否有这个标识符,如果没有找到,就会去父作用域查找,如果父作用域还没找到持续向上查找,直到全局作用域为止,,而作用域链,就是有以后作用域与下层作用域的一系列变量对象组成,它保障了以后执行的作用域对合乎拜访权限的变量和函数的有序拜访。

原型链

原型链实际上在下面原型的问题中就有波及到,在原型的继承中,咱们继承来多个原型,这里再提一下实现完满
继承的计划,通过借助寄生组合继承,PersonB.prototype = Object.create(PersonA.prototype)
这是当咱们实例化 PersonB 失去实例化对象,拜访实例化对象的属性时会触发 get 办法,它会先在本身属性上查
找,如果没有这个属性,就会去__proto__中查找,一层层向上直到查找到顶层对象 Object,这个查找的过程
就是原型链来。

CSS 中可继承与不可继承属性有哪些

一、无继承性的属性

  1. display:规定元素应该生成的框的类型
  2. 文本属性
  3. vertical-align:垂直文本对齐
  4. text-decoration:规定增加到文本的装璜
  5. text-shadow:文本暗影成果
  6. white-space:空白符的解决
  7. unicode-bidi:设置文本的方向
  8. 盒子模型的属性:width、height、margin、border、padding
  9. 背景属性:background、background-color、background-image、background-repeat、background-position、background-attachment
  10. 定位属性:float、clear、position、top、right、bottom、left、min-width、min-height、max-width、max-height、overflow、clip、z-index
  11. 生成内容属性:content、counter-reset、counter-increment
  12. 轮廓款式属性:outline-style、outline-width、outline-color、outline
  13. 页面款式属性:size、page-break-before、page-break-after
  14. 声音款式属性:pause-before、pause-after、pause、cue-before、cue-after、cue、play-during

二、有继承性的属性

  1. 字体系列属性
  2. font-family:字体系列
  • font-weight:字体的粗细
  • font-size:字体的大小
  • font-style:字体的格调
  • 文本系列属性
  • text-indent:文本缩进
  • text-align:文本程度对齐
  • line-height:行高
  • word-spacing:单词之间的间距
  • letter-spacing:中文或者字母之间的间距
  • text-transform:管制文本大小写(就是 uppercase、lowercase、capitalize 这三个)
  • color:文本色彩
  • 元素可见性
  • visibility:管制元素显示暗藏
  • 列表布局属性
  • list-style:列表格调,包含 list-style-type、list-style-image 等
  • 光标属性
  • cursor:光标显示为何种状态

vue-router

vue-router 是 vuex.js 官网的路由管理器,它和 vue.js 的外围深度集成,让构建但页面利用变得大海捞针

<router-link> 组件反对用户在具备路由性能的利用中 (点击) 导航。通过 to 属性指定指标地址

<router-view> 组件是一个 functional 组件,渲染门路匹配到的视图组件。<keep-alive> 组件是一个用来缓存组件

router.beforeEach

router.afterEach

to: Route: 行将要进入的指标 路由对象

from: Route: 以后导航正要来到的路由

next: Function: 肯定要调用该办法来 resolve 这个钩子。执行成果依赖 next 办法的调用参数。介绍了路由守卫及用法,在我的项目中路由守卫起到的作用等等

箭头函数和一般函数有啥区别?箭头函数能当构造函数吗?

  • 一般函数通过 function 关键字定义,this 无奈联合词法作用域应用,在运行时绑定,只取决于函数的调用形式,在哪里被调用,调用地位。(取决于调用者,和是否独立运行)
  • 箭头函数应用被称为“胖箭头”的操作 => 定义,箭头函数不利用一般函数 this 绑定的四种规定,而是依据外层(函数或全局)的作用域来决定 this,且箭头函数的绑定无奈被批改(new 也不行)。

    • 箭头函数罕用于回调函数中,包含事件处理器或定时器
    • 箭头函数和 var self = this,都试图取代传统的 this 运行机制,将 this 的绑定拉回到词法作用域
    • 没有原型、没有 this、没有 super,没有 arguments,没有 new.target
    • 不能通过 new 关键字调用

      • 一个函数外部有两个办法:[[Call]] 和 [[Construct]],在通过 new 进行函数调用时,会执行 [[construct]] 办法,创立一个实例对象,而后再执行这个函数体,将函数的 this 绑定在这个实例对象上
      • 当间接调用时,执行 [[Call]] 办法,间接执行函数体
      • 箭头函数没有 [[Construct]] 办法,不能被用作结构函数调用,当应用 new 进行函数调用时会报错。
function foo() {return (a) => {console.log(this.a);
  }
}

var obj1 = {a: 2}

var obj2 = {a: 3}

var bar = foo.call(obj1);
bar.call(obj2);

文档申明(Doctype)和 <!Doctype html> 有何作用? 严格模式与混淆模式如何辨别?它们有何意义?

文档申明的作用: 文档申明是为了通知浏览器,以后 HTML 文档应用什么版本的 HTML 来写的,这样浏览器能力依照申明的版本来正确的解析。

的作用:<!doctype html> 的作用就是让浏览器进入规范模式,应用最新的 HTML5 规范来解析渲染页面;如果不写,浏览器就会进入混淆模式,咱们须要防止此类情况产生。

严格模式与混淆模式的辨别:

  • 严格模式 :又称为规范模式,指浏览器依照W3C 规范解析代码;
  • 混淆模式:又称怪异模式、兼容模式,是指浏览器用本人的形式解析代码。混淆模式通常模仿老式浏览器的行为,以避免老站点无奈工作;

辨别 :网页中的DTD,间接影响到应用的是严格模式还是浏览模式,能够说DTD 的应用与这两种形式的区别非亲非故。

  • 如果文档蕴含严格的 DOCTYPE,那么它个别以严格模式出现( 严格 DTD ——严格模式);
  • 蕴含过渡 DTDURIDOCTYPE,也以严格模式出现,但有过渡 DTD 而没有 URI(对立资源标识符,就是申明最初的地址)会导致页面以混淆模式出现(有 URI 的过渡 DTD ——严格模式;没有 URI 的过渡 DTD ——混淆模式);
  • DOCTYPE 不存在或模式不正确会导致文档以混淆模式出现(DTD 不存在或者格局不正确——混淆模式);
  • HTML5 没有 DTD,因而也就没有严格模式与混淆模式的区别,HTML5 有绝对宽松的 法,实现时,曾经尽可能大的实现了向后兼容(HTML5 没有严格和混淆之分)。

总之,严格模式让各个浏览器对立执行一套标准兼容模式保障了旧网站的失常运行。

浏览器乱码的起因是什么?如何解决?

产生乱码的起因:

  • 网页源代码是 gbk 的编码,而内容中的中文字是 utf-8 编码的,这样浏览器关上即会呈现 html 乱码,反之也会呈现乱码;
  • html网页编码是 gbk,而程序从数据库中调出出现是utf-8 编码的内容也会造成编码乱码;
  • 浏览器不能自动检测网页编码,造成网页乱码。

解决办法:

  • 应用软件编辑 HTML 网页内容;
  • 如果网页设置编码是gbk,而数据库贮存数据编码格局是UTF-8,此时须要程序查询数据库数据显示数据后退程序转码;
  • 如果浏览器浏览时候呈现网页乱码,在浏览器中找到转换编码的菜单进行转换。

compose

题目形容: 实现一个 compose 函数

// 用法如下:
function fn1(x) {return x + 1;}
function fn2(x) {return x + 2;}
function fn3(x) {return x + 3;}
function fn4(x) {return x + 4;}
const a = compose(fn1, fn2, fn3, fn4);
console.log(a(1)); // 1+4+3+2+1=11

实现代码如下:

function compose(...fn) {if (!fn.length) return (v) => v;
  if (fn.length === 1) return fn[0];
  return fn.reduce((pre, cur) =>
      (...args) =>
        pre(cur(...args))
  );
}

z-index 属性在什么状况下会生效

通常 z-index 的应用是在有两个重叠的标签,在肯定的状况下管制其中一个在另一个的上方或者下方呈现。z-index 值越大就越是在下层。z-index 元素的 position 属性须要是 relative,absolute 或是 fixed。

z-index 属性在下列状况下会生效:

  • 父元素 position 为 relative 时,子元素的 z -index 生效。解决:父元素 position 改为 absolute 或 static;
  • 元素没有设置 position 属性为非 static 属性。解决:设置该元素的 position 属性为 relative,absolute 或是 fixed 中的一种;
  • 元素在设置 z -index 的同时还设置了 float 浮动。解决:float 去除,改为 display:inline-block;

说一下 web worker

在 HTML 页面中,如果在执行脚本时,页面的状态是不可相应的,直到脚本执行实现后,页面才变成可相应。web worker 是运行在后盾的 js,独立于其余脚本,不会影响页面的性能。并且通过 postMessage 将后果回传到主线程。这样在进行简单操作的时候,就不会阻塞主线程了。

如何创立 web worker:

  1. 检测浏览器对于 web worker 的支持性
  2. 创立 web worker 文件(js,回传函数等)
  3. 创立 web worker 对象

画一条 0.5px 的线

  • 采纳 transform: scale()的形式,该办法用来定义元素的 2D 缩放转换:
transform: scale(0.5,0.5);
  • 采纳 meta viewport 的形式
<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5"/>

这样就能缩放到原来的 0.5 倍,如果是 1px 那么就会变成 0.5px。viewport 只针对于挪动端,只在挪动端上能力看到成果

原型

JavaScript 中的对象都有一个非凡的 prototype 内置属性,其实就是对其余对象的援用
简直所有的对象在创立时 prototype 属性都会被赋予一个非空的值,咱们能够把这个属性当作一个备用的仓库
当试图援用对象的属性时会登程 get 操作,第一步时查看对象自身是否有这个属性,如果有就应用它,没有就去原型中查找。一层层向上直到 Object.prototype 顶层

基于原型扩大形容一下原型链,什么是原型链,原型的继承,ES5 和 ES6 继承与不同点。

异步任务调度器

形容:实现一个带并发限度的异步调度器 Scheduler,保障同时运行的工作最多有 limit 个。

实现

class Scheduler {queue = [];  // 用队列保留正在执行的工作
    runCount = 0;  // 计数正在执行的工作个数
    constructor(limit) {this.maxCount = limit;  // 容许并发的最大个数}
    add(time, data){const promiseCreator = () => {return new Promise((resolve, reject) => {setTimeout(() => {console.log(data);
                    resolve();}, time);
            });
        }
        this.queue.push(promiseCreator);
        // 每次增加的时候都会尝试去执行工作
        this.request();}
    request() {
        // 队列中还有工作才会被执行
        if(this.queue.length && this.runCount < this.maxCount) {
            this.runCount++;
            // 执行先退出队列的函数
            this.queue.shift()().then(() => {
                this.runCount--;
                // 尝试进行下一次工作
                this.request();});
        }
    }
}

// 测试
const scheduler = new Scheduler(2);
const addTask = (time, data) => {scheduler.add(time, data);
}

addTask(1000, '1');
addTask(500, '2');
addTask(300, '3');
addTask(400, '4');
// 输入后果 2 3 1 4

深浅拷贝

浅拷贝:只思考对象类型。

function shallowCopy(obj) {if (typeof obj !== 'object') return

    let newObj = obj instanceof Array ? [] : {}
    for (let key in obj) {if (obj.hasOwnProperty(key)) {newObj[key] = obj[key]
        }
    }
    return newObj
}

简略版深拷贝:只思考一般对象属性,不思考内置对象和函数。

function deepClone(obj) {if (typeof obj !== 'object') return;
    var newObj = obj instanceof Array ? [] : {};
    for (var key in obj) {if (obj.hasOwnProperty(key)) {newObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key];
        }
    }
    return newObj;
}

简单版深克隆:基于简略版的根底上,还思考了内置对象比方 Date、RegExp 等对象和函数以及解决了循环援用的问题。

const isObject = (target) => (typeof target === "object" || typeof target === "function") && target !== null;

function deepClone(target, map = new WeakMap()) {if (map.get(target)) {return target;}
    // 获取以后值的构造函数:获取它的类型
    let constructor = target.constructor;
    // 检测以后对象 target 是否与正则、日期格局对象匹配
    if (/^(RegExp|Date)$/i.test(constructor.name)) {// 创立一个新的非凡对象 (正则类 / 日期类) 的实例
        return new constructor(target);  
    }
    if (isObject(target)) {map.set(target, true);  // 为循环援用的对象做标记
        const cloneTarget = Array.isArray(target) ? [] : {};
        for (let prop in target) {if (target.hasOwnProperty(prop)) {cloneTarget[prop] = deepClone(target[prop], map);
            }
        }
        return cloneTarget;
    } else {return target;}
}

判断数组的形式有哪些

  • 通过 Object.prototype.toString.call()做判断
Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
  • 通过原型链做判断
obj.__proto__ === Array.prototype;
  • 通过 ES6 的 Array.isArray()做判断
Array.isArrray(obj);
  • 通过 instanceof 做判断
obj instanceof Array
  • 通过 Array.prototype.isPrototypeOf
Array.prototype.isPrototypeOf(obj)

PWA 应用过吗?serviceWorker 的应用原理是啥?

渐进式网络应用(PWA)是谷歌在 2015 年底提出的概念。基本上算是 web 应用程序,但在外观和感觉上与 原生 app相似。反对 PWA 的网站能够提供脱机工作、推送告诉和设施硬件拜访等性能。

Service Worker是浏览器在后盾独立于网页运行的脚本,它关上了通向不须要网页或用户交互的性能的大门。当初,它们已包含如推送告诉和后盾同步等性能。未来,Service Worker将会反对如定期同步或天文围栏等其余性能。本教程探讨的外围性能是拦挡和解决网络申请,包含通过程序来治理缓存中的响应。

正文完
 0