img的srcset属性的作⽤?

响应式页面中常常用到依据屏幕密度设置不同的图片。这时就用到了 img 标签的srcset属性。srcset属性用于设置不同屏幕密度下,img 会主动加载不同的图片。用法如下:

<img src="image-128.png" srcset="image-256.png 2x" />

应用下面的代码,就能实现在屏幕密度为1x的状况下加载image-128.png, 屏幕密度为2x时加载image-256.png。

依照下面的实现,不同的屏幕密度都要设置图片地址,目前的屏幕密度有1x,2x,3x,4x四种,如果每一个图片都设置4张图片,加载就会很慢。所以就有了新的srcset规范。代码如下:

<img src="image-128.png"     srcset="image-128.png 128w, image-256.png 256w, image-512.png 512w"     sizes="(max-width: 360px) 340px, 128px" />

其中srcset指定图片的地址和对应的图片品质。sizes用来设置图片的尺寸零界点。对于 srcset 中的 w 单位,能够了解成图片品质。如果可视区域小于这个品质的值,就能够应用。浏览器会主动抉择一个最小的可用图片。

sizes语法如下:

sizes="[media query] [length], [media query] [length] ... "

sizes就是指默认显示128px, 如果视区宽度大于360px, 则显示340px。

左右居中计划

  • 行内元素: text-align: center
  • 定宽块状元素: 左右 margin 值为 auto
  • 不定宽块状元素: table布局,position + transform
/* 计划1 */.wrap {  text-align: center}.center {  display: inline;  /* or */  /* display: inline-block; */}/* 计划2 */.center {  width: 100px;  margin: 0 auto;}/* 计划2 */.wrap {  position: relative;}.center {  position: absulote;  left: 50%;  transform: translateX(-50%);}

Loader和Plugin 有什么区别

Loader:直译为"加载器"。Webpack将所有文件视为模块,然而webpack原生是只能解析js文件,如果想将其余文件也打包的话,就会用到loader。 所以Loader的作用是让webpack领有了加载和解析非JavaScript文件的能力。 Plugin:直译为"插件"。Plugin能够扩大webpack的性能,让webpack具备更多的灵活性。 在 Webpack 运行的生命周期中会播送出许多事件,Plugin 能够监听这些事件,在适合的机会通过 Webpack 提供的 API 扭转输入后果。

什么是 JavaScript 中的包装类型?

在 JavaScript 中,根本类型是没有属性和办法的,然而为了便于操作根本类型的值,在调用根本类型的属性或办法时 JavaScript 会在后盾隐式地将根本类型的值转换为对象,如:

const a = "abc";a.length; // 3a.toUpperCase(); // "ABC"

在拜访'abc'.length时,JavaScript 将'abc'在后盾转换成String('abc'),而后再拜访其length属性。

JavaScript也能够应用Object函数显式地将根本类型转换为包装类型:

var a = 'abc'Object(a) // String {"abc"}

也能够应用valueOf办法将包装类型倒转成根本类型:

var a = 'abc'var b = Object(a)var c = b.valueOf() // 'abc'

看看如下代码会打印出什么:

var a = new Boolean( false );if (!a) {    console.log( "Oops" ); // never runs}

答案是什么都不会打印,因为尽管包裹的根本类型是false,然而false被包裹成包装类型后就成了对象,所以其非值为false,所以循环体中的内容不会运行。

为什么函数的 arguments 参数是类数组而不是数组?如何遍历类数组?

arguments是一个对象,它的属性是从 0 开始顺次递增的数字,还有calleelength等属性,与数组类似;然而它却没有数组常见的办法属性,如forEach, reduce等,所以叫它们类数组。

要遍历类数组,有三个办法:

(1)将数组的办法利用到类数组上,这时候就能够应用callapply办法,如:

function foo(){   Array.prototype.forEach.call(arguments, a => console.log(a))}

(2)应用Array.from办法将类数组转化成数组:

function foo(){   const arrArgs = Array.from(arguments)   arrArgs.forEach(a => console.log(a))}

(3)应用开展运算符将类数组转化成数组

function foo(){     const arrArgs = [...arguments]     arrArgs.forEach(a => console.log(a)) }

代码输入后果

function runAsync(x) {  const p = new Promise(r =>    setTimeout(() => r(x, console.log(x)), 1000)  );  return p;}function runReject(x) {  const p = new Promise((res, rej) =>    setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x)  );  return p;}Promise.race([runReject(0), runAsync(1), runAsync(2), runAsync(3)])  .then(res => console.log("result: ", res))  .catch(err => console.log(err));

输入后果如下:

0Error: 0123

能够看到在catch捕捉到第一个谬误之后,前面的代码还不执行,不过不会再被捕捉了。

留神:allrace传入的数组中如果有会抛出异样的异步工作,那么只有最先抛出的谬误会被捕捉,并且是被then的第二个参数或者前面的catch捕捉;但并不会影响数组中其它的异步工作的执行。

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

事件是什么?事件模型?

事件是用户操作网页时产生的交互动作,比方 click/move, 事件除了用户触发的动作外,还能够是文档加载,窗口滚动和大小调整。事件被封装成一个 event 对象,蕴含了该事件产生时的所有相干信息( event 的属性)以及能够对事件进行的操作( event 的办法)。

事件是用户操作网页时产生的交互动作或者网页自身的一些操作,古代浏览器一共有三种事件模型:

  • DOM0 级事件模型,这种模型不会流传,所以没有事件流的概念,然而当初有的浏览器反对以冒泡的形式实现,它能够在网页中间接定义监听函数,也能够通过 js 属性来指定监听函数。所有浏览器都兼容这种形式。间接在dom对象上注册事件名称,就是DOM0写法。
  • IE 事件模型,在该事件模型中,一次事件共有两个过程,事件处理阶段和事件冒泡阶段。事件处理阶段会首先执行指标元素绑定的监听事件。而后是事件冒泡阶段,冒泡指的是事件从指标元素冒泡到 document,顺次查看通过的节点是否绑定了事件监听函数,如果有则执行。这种模型通过attachEvent 来增加监听函数,能够增加多个监听函数,会按程序顺次执行。
  • DOM2 级事件模型,在该事件模型中,一次事件共有三个过程,第一个过程是事件捕捉阶段。捕捉指的是事件从 document 始终向下流传到指标元素,顺次查看通过的节点是否绑定了事件监听函数,如果有则执行。前面两个阶段和 IE 事件模型的两个阶段雷同。这种事件模型,事件绑定的函数是addEventListener,其中第三个参数能够指定事件是否在捕捉阶段执行。

== 操作符的强制类型转换规定?

对于 == 来说,如果比照单方的类型不一样,就会进行类型转换。如果比照 xy 是否雷同,就会进行如下判断流程:

  1. 首先会判断两者类型是否雷同,雷同的话就比拟两者的大小;
  2. 类型不雷同的话,就会进行类型转换;
  3. 会先判断是否在比照 nullundefined,是的话就会返回 true
  4. 判断两者类型是否为 stringnumber,是的话就会将字符串转换为 number
1 == '1'      ↓1 ==  1
  1. 判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断
'1' == true        ↓'1' ==  1        ↓ 1  ==  1
  1. 判断其中一方是否为 object 且另一方为 stringnumber 或者 symbol,是的话就会把 object 转为原始类型再进行判断
'1' == { name: 'js' }        ↓'1' == '[object Object]'

原型批改、重写

function Person(name) {    this.name = name}// 批改原型Person.prototype.getName = function() {}var p = new Person('hello')console.log(p.__proto__ === Person.prototype) // trueconsole.log(p.__proto__ === p.constructor.prototype) // true// 重写原型Person.prototype = {    getName: function() {}}var p = new Person('hello')console.log(p.__proto__ === Person.prototype)        // trueconsole.log(p.__proto__ === p.constructor.prototype) // false

能够看到批改原型的时候p的构造函数不是指向Person了,因为间接给Person的原型对象间接用对象赋值时,它的构造函数指向的了根构造函数Object,所以这时候p.constructor === Object ,而不是p.constructor === Person。要想成立,就要用constructor指回来:

Person.prototype = {    getName: function() {}}var p = new Person('hello')p.constructor = Personconsole.log(p.__proto__ === Person.prototype)        // trueconsole.log(p.__proto__ === p.constructor.prototype) // true

对 rest 参数的了解

扩大运算符被用在函数形参上时,它还能够把一个拆散的参数序列整合成一个数组

function mutiple(...args) {  let result = 1;  for (var val of args) {    result *= val;  }  return result;}mutiple(1, 2, 3, 4) // 24

这里,传入 mutiple 的是四个拆散的参数,然而如果在 mutiple 函数里尝试输入 args 的值,会发现它是一个数组:

function mutiple(...args) {  console.log(args)}mutiple(1, 2, 3, 4) // [1, 2, 3, 4]

这就是 … rest运算符的又一层威力了,它能够把函数的多个入参收敛进一个数组里。这一点常常用于获取函数的多余参数,或者像下面这样解决函数参数个数不确定的状况。

JS 整数是怎么示意的?

  • 通过 Number 类型来示意,遵循 IEEE754 规范,通过 64 位来示意一个数字,(1 + 11 + 52),最大平安数字是 Math.pow(2, 53) - 1,对于 16 位十进制。(符号位 + 指数位 + 小数局部无效位)

代码输入后果

function runAsync (x) {  const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000))  return p}function runReject (x) {  const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x))  return p}Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)])       .then(res => console.log(res))       .catch(err => console.log(err))

输入后果如下:

// 1s后输入13// 2s后输入2Error: 2// 4s后输入4

能够看到。catch捕捉到了第一个谬误,在这道题目中最先的谬误就是runReject(2)的后果。如果一组异步操作中有一个异样都不会进入.then()的第一个回调函数参数中。会被.then()的第二个回调函数捕捉。

new操作符的实现原理

new操作符的执行过程:

(1)首先创立了一个新的空对象

(2)设置原型,将对象的原型设置为函数的 prototype 对象。

(3)让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象增加属性)

(4)判断函数的返回值类型,如果是值类型,返回创立的对象。如果是援用类型,就返回这个援用类型的对象。

具体实现:

function objectFactory() {  let newObject = null;  let constructor = Array.prototype.shift.call(arguments);  let result = null;  // 判断参数是否是一个函数  if (typeof constructor !== "function") {    console.error("type error");    return;  }  // 新建一个空对象,对象的原型为构造函数的 prototype 对象  newObject = Object.create(constructor.prototype);  // 将 this 指向新建对象,并执行函数  result = constructor.apply(newObject, arguments);  // 判断返回对象  let flag = result && (typeof result === "object" || typeof result === "function");  // 判断返回后果  return flag ? result : newObject;}// 应用办法objectFactory(构造函数, 初始化参数);

常见的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)

Promise.resolve

Promise.resolve = function(value) {    // 1.如果 value 参数是一个 Promise 对象,则一成不变返回该对象    if(value instanceof Promise) return value;    // 2.如果 value 参数是一个具备 then 办法的对象,则将这个对象转为 Promise 对象,并立刻执行它的then办法    if(typeof value === "object" && 'then' in value) {        return new Promise((resolve, reject) => {           value.then(resolve, reject);        });    }    // 3.否则返回一个新的 Promise 对象,状态为 fulfilled    return new Promise(resolve => resolve(value));}

JavaScript有哪些内置对象

全局的对象( global objects )或称规范内置对象,不要和 "全局对象(global object)" 混同。这里说的全局的对象是说在
全局作用域里的对象。全局作用域中的其余对象能够由用户的脚本创立或由宿主程序提供。

规范内置对象的分类:

(1)值属性,这些全局属性返回一个简略值,这些值没有本人的属性和办法。例如 Infinity、NaN、undefined、null 字面量

(2)函数属性,全局函数能够间接调用,不须要在调用时指定所属对象,执行完结后会将后果间接返回给调用者。例如 eval()、parseFloat()、parseInt() 等

(3)根本对象,根本对象是定义或应用其余对象的根底。根本对象包含个别对象、函数对象和谬误对象。例如 Object、Function、Boolean、Symbol、Error 等

(4)数字和日期对象,用来示意数字、日期和执行数学计算的对象。例如 Number、Math、Date

(5)字符串,用来示意和操作字符串的对象。例如 String、RegExp

(6)可索引的汇合对象,这些对象示意依照索引值来排序的数据汇合,包含数组和类型数组,以及类数组构造的对象。例如 Array

(7)应用键的汇合对象,这些汇合对象在存储数据时会应用到键,反对依照插入程序来迭代元素。
例如 Map、Set、WeakMap、WeakSet

(8)矢量汇合,SIMD 矢量汇合中的数据会被组织为一个数据序列。
例如 SIMD 等

(9)结构化数据,这些对象用来示意和操作结构化的缓冲区数据,或应用 JSON 编码的数据。例如 JSON 等

(10)管制形象对象
例如 Promise、Generator 等

(11)反射。例如 Reflect、Proxy

(12)国际化,为了反对多语言解决而退出 ECMAScript 的对象。例如 Intl、Intl.Collator 等

(13)WebAssembly

(14)其余。例如 arguments

总结: js 中的内置对象次要指的是在程序执行前存在全局作用域里的由 js 定义的一些全局值属性、函数和用来实例化其余对象的构造函数对象。个别常常用到的如全局变量值 NaN、undefined,全局函数如 parseInt()、parseFloat() 用来实例化对象的构造函数如 Date、Object 等,还有提供数学计算的单体内置对象如 Math 对象。

JavaScript 类数组对象的定义?

一个领有 length 属性和若干索引属性的对象就能够被称为类数组对象,类数组对象和数组相似,然而不能调用数组的办法。常见的类数组对象有 arguments 和 DOM 办法的返回后果,还有一个函数也能够被看作是类数组对象,因为它含有 length 属性值,代表可接管的参数个数。

常见的类数组转换为数组的办法有这样几种:

(1)通过 call 调用数组的 slice 办法来实现转换

Array.prototype.slice.call(arrayLike);

(2)通过 call 调用数组的 splice 办法来实现转换

Array.prototype.splice.call(arrayLike, 0);

(3)通过 apply 调用数组的 concat 办法来实现转换

Array.prototype.concat.apply([], arrayLike);

(4)通过 Array.from 办法来实现转换

Array.from(arrayLike);

对类数组对象的了解,如何转化为数组

一个领有 length 属性和若干索引属性的对象就能够被称为类数组对象,类数组对象和数组相似,然而不能调用数组的办法。常见的类数组对象有 arguments 和 DOM 办法的返回后果,函数参数也能够被看作是类数组对象,因为它含有 length属性值,代表可接管的参数个数。

常见的类数组转换为数组的办法有这样几种:

  • 通过 call 调用数组的 slice 办法来实现转换
Array.prototype.slice.call(arrayLike);
  • 通过 call 调用数组的 splice 办法来实现转换
Array.prototype.splice.call(arrayLike, 0);
  • 通过 apply 调用数组的 concat 办法来实现转换
Array.prototype.concat.apply([], arrayLike);
  • 通过 Array.from 办法来实现转换
Array.from(arrayLike);

说一下JSON.stringify有什么毛病?

1.如果obj外面有工夫对象,则JSON.stringify后再JSON.parse的后果,工夫将只是字符串的模式,而不是对象的模式2.如果obj里有RegExp(正则表达式的缩写)、Error对象,则序列化的后果将只失去空对象;3、如果obj里有函数,undefined,则序列化的后果会把函数或 undefined失落;4、如果obj里有NaN、Infinity和-Infinity,则序列化的后果会变成null5、JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则应用JSON.parse(JSON.stringify(obj))深拷贝后,会抛弃对象的constructor;6、如果对象中存在循环援用的状况也无奈正确实现深拷贝;

CSS预处理器/后处理器是什么?为什么要应用它们?

预处理器, 如:lesssassstylus,用来预编译sass或者less,减少了css代码的复用性。层级,mixin, 变量,循环, 函数等对编写以及开发UI组件都极为不便。

后处理器, 如: postCss,通常是在实现的样式表中依据css标准解决css,让其更加无效。目前最常做的是给css属性增加浏览器公有前缀,实现跨浏览器兼容性的问题。

css预处理器为css减少一些编程个性,无需思考浏览器的兼容问题,能够在CSS中应用变量,简略的逻辑程序,函数等在编程语言中的一些根本的性能,能够让css更加的简洁,减少适应性以及可读性,可维护性等。

其它css预处理器语言:Sass(Scss), Less, Stylus, Turbine, Swithch css, CSS Cacheer, DT Css

应用起因:

  • 构造清晰, 便于扩大
  • 能够很不便的屏蔽浏览器公有语法的差别
  • 能够轻松实现多重继承
  • 完满的兼容了CSS代码,能够利用到老我的项目中