面试题
- 谈谈你对盒子模型的理解
- 如何让一个盒子水平垂直居中,有哪些方法越多越好
- 说说javascript都有哪些数据类型,如何存储的?
- 如何理解响应式,有什么区别?
- Css性能优化有哪些常见的方法?具体如何实现?
- 判断数据类型的方法有哪些?有什么区别?
- 说说你对事件循环的理解?
- 说说你对BOM的理解,BOM的核心都有哪些?作用是什么
- Bind,call,apply有什么区别?如何实现一个bind方法?
- 如何理解闭包?闭包的应用场景是?
- 说说你对同步和异步的区别的理解?
- Css选择器有哪些?优先级是什么?哪些属性可以继承?
- 简单说一下什么是事件代理?
- 如何理解重回和回流?什么场景下才能触发?
- 什么是防抖和节流,有什么区别?如何实现?
- 说说你对作用域链的理解?
- 说说你对原型和原型链的理解?
- Vue的生命周期和含义有哪些?
- Vue自定义指令的钩子函数有哪些?
- Javascript本地存储有哪些?区别和使用场景?
谈谈你对盒子模型的理解
盒模型是CSS中的一个重要概念,它指的是一个HTML元素在页面中所占据的空间,包括元素的内容、内边距、边框和外边距。盒模型可以帮助我们理解和控制元素在页面中的布局和样式。
盒模型分为两种:
- 标准盒模型
- IE盒模型
标准盒模型的宽度和高度只包括元素的内容
IE盒模型的宽度和高度包括元素的内容、内边距和边框。
盒模型的属性包括:
-
width:元素的宽度,包括内容、内边距和边框。
-
height:元素的高度,包括内容、内边距和边框。
-
padding:元素的内边距,指的是元素内容和边框之间的距离。
-
border:元素的边框,指的是元素内容和外边距之间的距离。
-
margin:元素的外边距,指的是元素和其他元素之间的距离。
盒模型的理解对于CSS的布局和样式非常重要,可以帮助我们更好地控制元素在页面中的位置和大小,实现更加丰富的页面效果。
如何让一个盒子水平垂直居中,有哪些方法越多越好
1.绝对定位(position: absolute)
.box{
position: absolute;
width: 100px;
height: 100px;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
background-color: greenyellow;
}
2.绝对定位(position: absolute)
.box{
position: absolute;
width: 100px;
height: 100px;
top: calc(50% - 50px);
left: calc(50% - 50px);
margin: auto;
background-color: greenyellow;
}
3.flex布局
//父元素
.par{
display: flex;
width: 500px;
height: 500px;
align-items: center;
justify-content: center;
background-color: red;
}
.sun{
width: 100px;
height: 100px;
background-color: greenyellow;
}
4.table布局(子元素需设置成行内块元素/行内元素)
.par{
width: 500px;
height: 500px;
background-color: red;
display: table;
display:table-cell;
vertical-align:middle;
text-align:center;
}
.sun{
display: inline-block;
width: 100px;
height: 100px;
background-color: greenyellow;
}
5.grid布局
.par{
width: 500px;
height: 500px;
background-color: red;
display:grid;
justify-content:center;
align-items:center;
}
.sun{
width: 100px;
height: 100px;
background-color: greenyellow;
}
说说javascript都有哪些数据类型,如何存储的?
数据类型大体分为两种:
- 基本数据类型
- 引用数据类型(复杂数据类型)
基本数据类型:
存储在栈内存中,值是不可变的,每次修改都会创建一个新的值。
-
Number:数字类型,包括整数和浮点数。
-
String:字符串类型,用单引号、双引号或反引号表示。
-
Boolean:布尔类型,只有两个值:true和false。
-
Null:空类型,表示一个空值。
-
Undefined:未定义类型,表示一个未定义的值。
-
Symbol:符号类型,表示唯一的标识符。
引用数据类型
可以统称为Object类型
存储在堆内存中,值是可变的,可以通过引用来访问和修改。
-
Object:对象类型,包括普通对象、数组、函数等。
-
Function:函数类型,是一种特殊的对象类型,可以被调用执行。
-
Array:数组
如何理解响应式,有什么区别?
定义
响应式设计是一种设计方法,它可以使网站或应用程序在不同的设备上自适应,以提供更好的用户体验。
响应式设计的目标是使网站或应用程序在不同的屏幕尺寸和设备上都能够呈现出最佳的布局和用户界面。
实现响应式设计的方法有以下几种:
-
使用CSS媒体查询:通过CSS媒体查询来检测设备的屏幕尺寸和方向,并根据不同的条件来应用不同的CSS样式。
-
使用弹性网格布局:使用弹性网格布局来创建灵活的布局,以适应不同的屏幕尺寸和设备。
-
使用流式布局:使用流式布局来创建自适应的布局,以适应不同的屏幕尺寸和设备。
-
使用响应式框架:使用响应式框架,如Bootstrap、Foundation等,来快速创建响应式设计。
这些方法的区别在于
- 实现的方式和效果。
- 使用CSS媒体查询可以根据不同的设备条件来应用不同的CSS样式,但需要手动编写CSS代码。
- 使用弹性网格布局和流式布局可以创建灵活的布局,但需要更多的CSS和HTML代码。
- 使用响应式框架可以快速创建响应式设计,但可能需要更多的学习和定制。
Css性能优化有哪些常见的方法?具体如何实现?
CSS性能优化的常见方法如下:
-
减少CSS文件的大小:可以通过压缩CSS文件、删除不必要的注释和空格、合并多个CSS文件等方式来减少CSS文件的大小。
-
避免使用通配符选择器:通配符选择器会匹配页面中的所有元素,会导致性能问题。应该尽量避免使用通配符选择器,而使用更具体的选择器。
-
避免使用复杂的选择器:复杂的选择器会导致浏览器需要更多的计算来匹配元素,应该尽量避免使用复杂的选择器。
-
避免使用@import:@import会导致浏览器需要额外的请求来获取CSS文件,应该尽量避免使用@import。
-
避免使用!important:!important会覆盖其他样式,会导致样式冲突和性能问题,应该尽量避免使用!important。
-
使用缩写属性:使用缩写属性可以减少CSS代码的大小,例如使用margin代替margin-top、margin-right、margin-bottom和margin-left。
-
避免使用CSS表达式:CSS表达式会导致浏览器需要计算表达式的值,会导致性能问题,应该尽量避免使用CSS表达式。
-
避免使用过多的浮动:过多的浮动会导致页面重排和重绘,应该尽量避免使用过多的浮动。
-
使用CSS Sprites:使用CSS Sprites可以减少页面的HTTP请求,提高页面加载速度。
-
使用媒体查询:使用媒体查询可以根据不同的设备条件来应用不同的CSS样式,可以提高页面的响应性能。
这些方法的具体实现可以根据具体的情况来进行调整和优化,例如使用CSS预处理器、使用CSS模块化等方式来提高CSS性能。
判断数据类型的方法有哪些?有什么区别?
方法
- typeof
- instanceof
- Object.prototype.toString.call()
- Array.isArray()
typeof:typeof是一种操作符,可以返回一个值的数据类型。
例如:
typeof( 123)会返回"number"
typeof( “hello”)会返回"string“
但是typeof对于null和数组的判断会有问题,null会返回"object",数组会返回"object"。
instanceof:instanceof是一种操作符,可以判断一个对象是否是某个类的实例。
例如
obj instanceof Array可以判断obj是否是数组的实例。但是instanceof只能判断对象是否是某个类的实例,不能判断基本数据类型。
Object.prototype.toString.call():这是一种比较准确的判断数据类型的方法,可以返回一个值的具体数据类型。
例如
Object.prototype.toString.call(123)会返回"[object Number]“,Object.prototype.toString.call(“hello”)会返回”[object String]“。
这种方法可以准确地判断基本数据类型和对象类型,但是需要注意的是,对于null和undefined,返回的结果会是”[object Null]“和”[object Undefined]"。
Array.isArray():这是一种判断数组类型的方法,可以判断一个值是否是数组类型。
例如
Array.isArray([1,2,3])会返回true,Array.isArray(“hello”)会返回false。
但是这种方法只能判断数组类型,不能判断其他类型。
这些方法的区别在于判断的精度和适用范围。
- typeof可以快速判断基本数据类型,但是对于null和数组的判断会有问题;
- instanceof可以判断对象是否是某个类的实例,但是不能判断基本数据类型;
- Object.prototype.toString.call()可以准确地判断基本数据类型和对象类型,但是对于null和undefined的判断需要注意;
- Array.isArray()可以判断数组类型,但是不能判断其他类型。
说说你对事件循环的理解?
定义
事件循环是JavaScript中一种处理异步事件的机制,它是JavaScript的核心机制之一。事件循环的基本思想是,将所有的事件放入一个事件队列中,然后不断地从队列中取出事件并处理,直到队列为空为止。
事件循环的执行过程如下:
- 执行同步代码,将所有的异步事件放入事件队列中。
- 从事件队列中取出一个事件,执行相应的回调函数。
- 如果事件队列中还有其他事件,返回第2步,否则执行下一步。
- 如果有其他的异步事件被触发,将它们放入事件队列中。
- 返回第2步,继续执行事件队列中的事件。
事件循环的优点
- 可以处理异步事件,避免了阻塞线程的情况,提高了程序的响应性能。
事件循环也有一些缺点
- 可能会导致回调地狱
- 可能会出现竞态条件等问题,需要注意处理。
在浏览器中,事件循环是由浏览器的事件循环线程来处理的,而在Node.js中,事件循环是由Node.js的事件循环机制来处理的。
说说你对BOM的理解,BOM的核心都有哪些?作用是什么
定义
BOM(Browser Object Model)是浏览器对象模型,它是JavaScript与浏览器交互的接口,提供了访问和操作浏览器窗口、浏览器历史记录、浏览器地址栏等浏览器相关对象的方法和属性。
BOM的核心包括以下几个对象:
-
window对象:代表浏览器窗口,是BOM的顶层对象,提供了访问和操作浏览器窗口的方法和属性。
-
location对象:代表浏览器的地址栏,提供了访问和操作浏览器地址栏的方法和属性。
-
history对象:代表浏览器的历史记录,提供了访问和操作浏览器历史记录的方法和属性。
-
navigator对象:提供了浏览器相关的信息,例如浏览器的名称、版本、操作系统等。
BOM的作用
- 提供了JavaScript与浏览器交互的接口,可以通过BOM来访问和操作浏览器相关的对象和信息
- 可以通过BOM来打开新的浏览器窗口、跳转到其他页面、获取浏览器的信息等。
- BOM还可以用于检测浏览器的类型和版本,以便在不同的浏览器中提供不同的功能和样式。
Bind,call,apply有什么区别?如何实现一个bind方法?
定义
Bind、call和apply都是JavaScript中用于改变函数执行上下文的方法
它们的区别如下:
-
call和apply都是立即调用函数,而bind返回一个新的函数,需要手动调用。
-
call和apply的参数是直接传递给函数的,而bind的参数是在返回的新函数被调用时传递的。
-
call和apply可以传递多个参数,而bind只能传递一个参数。
-
call和apply可以直接调用函数并传递参数,而bind需要先返回一个新函数,再调用新函数并传递参数。
下面是一个实现bind方法的示例:
Function.prototype.bind = function(context) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(context, args.concat(bindArgs));
}
}
这个bind方法的实现思路是:将原函数保存在self变量中,将传入的上下文保存在context变量中,将传入的参数保存在args变量中,返回一个新函数,新函数中将传入的参数和之前保存的参数合并后,使用apply方法调用原函数,并将上下文设置为传入的上下文。这样就实现了一个简单的bind方法。
如何理解闭包?闭包的应用场景是?
定义
闭包是指在一个函数内部定义的函数可以访问该函数的变量和参数,即使该函数已经返回,闭包仍然可以访问这些变量和参数。
闭包可以理解为一个函数和它所能访问的外部变量的组合,它可以保留函数的状态,使得函数可以在之后的调用中继续使用这些状态。
闭包的应用场景包括:
- 封装变量:使用闭包可以将变量封装在函数内部,避免变量污染全局作用域。
- 延迟执行:使用闭包可以实现延迟执行,例如在定时器中使用闭包可以保留定时器回调函数的状态。
- 实现私有变量和方法:使用闭包可以实现私有变量和方法,例如在构造函数中使用闭包可以实现私有变量和方法,避免外部访问。
- 模块化开发:使用闭包可以实现模块化开发,将一些相关的函数和变量封装在一个闭包中,避免全局作用域的污染。
- 需要注意的是,闭包会占用内存,如果使用不当会导致内存泄漏的问题,因此在使用闭包时需要注意内存管理。
说说你对同步和异步的区别的理解?
同步和异步是两种不同的处理方式。
同步是指在执行某个操作时,必须等待该操作完成后才能进行下一步操作。在同步模式下,程序会一直等待操作完成,直到得到结果后才会继续执行下一步操作。
异步是指在执行某个操作时,不必等待该操作完成,可以继续执行下一步操作。在异步模式下,程序会提交一个操作请求,然后继续执行下一步操作,等到操作完成后再去处理结果。
简单来说,同步是一种阻塞式的处理方式,而异步是一种非阻塞式的处理方式。同步需要等待操作完成后才能继续执行下一步操作,而异步则可以在操作进行的同时执行其他操作。在实际应用中,异步通常比同步更高效,因为它可以充分利用系统资源,提高程序的并发性和响应速度。
Css选择器有哪些?优先级是什么?哪些属性可以继承?
CSS选择器有以下几种:
-
元素选择器:通过元素名称来选择元素,如p、div、span等。
-
类选择器:通过类名来选择元素,以点号(.)开头,如.class。
-
ID选择器:通过元素的ID属性来选择元素,以井号(#)开头,如#id。
-
属性选择器:通过元素的属性来选择元素,如[type=“text”]。
-
伪类选择器:通过元素的状态来选择元素,如:hover、:active、:focus等。
-
后代选择器:通过元素的后代关系来选择元素,如div p。
-
相邻兄弟选择器:通过元素的相邻兄弟关系来选择元素,如h1 + p。
-
通用选择器:选择所有元素,用*表示。
CSS选择器的优先级是根据选择器的特殊性(specificity)来确定的,特殊性越高,优先级越高。
特殊性的计算规则是:
- ID选择器的特殊性最高,为100;
- 类选择器、属性选择器和伪类选择器的特殊性为10;
- 元素选择器和伪元素选择器的特殊性为1。
如果有多个选择器应用于同一个元素,优先级高的选择器会覆盖优先级低的选择器。
CSS中有一些属性是可以继承的,包括
- 字体相关属性(font-family、font-size、font-weight、font-style、line-height
- 文本相关属性(text-align、text-indent、text-transform、text-decoration、letter-spacing、word-spacing)
- 颜色相关属性(color、background-color、border-color)和列表相关属性(list-style-type、list-style-position、list-style-image)
其他大部分属性都不会被继承。
简单说一下什么是事件代理?
事件代理(Event Delegation)是一种常用的事件处理技术,它利用了事件冒泡的机制,将事件处理程序绑定到父元素上,从而避免了在子元素上绑定事件处理程序的繁琐操作。当子元素触发事件时,事件会一直向上冒泡到父元素,父元素就可以根据事件的类型和目标元素来判断需要执行哪个事件处理程序。
事件代理的优点在于可以减少事件处理程序的数量,提高性能和代码的可维护性。当页面中有大量的子元素需要绑定事件处理程序时,使用事件代理可以避免为每个子元素都绑定事件处理程序的麻烦,而且当新增或删除子元素时,也不需要重新绑定事件处理程序,只需要在父元素上绑定一次即可。
如何理解重回和回流?什么场景下才能触发?
重绘和回流是浏览器渲染页面时的两个重要概念。
重绘是指当元素样式的改变不影响其在文档流中的位置时,浏览器会将新样式绘制在元素上,这个过程称为重绘。
回流是指当元素的尺寸、位置或内容发生改变时,浏览器需要重新计算文档流中所有元素的位置和大小,然后重新绘制页面,这个过程称为回流。
回流比重绘的代价更高,因为回流会涉及到页面布局的改变,需要重新计算元素的位置和大小,而重绘只需要重新绘制元素的样式。
触发重绘和回流的场景有很多,比如改变元素的样式、尺寸、位置、内容等。
改变元素的尺寸和位置是最容易触发回流的操作,因为它会影响到其他元素的位置和大小。因此,应尽量避免在循环中频繁改变元素的尺寸和位置,可以使用一些技巧来减少回流的次数,比如使用文档片段 (DocumentFragment)来批量操作DOM,或者使用CSS3的transform属性来改变元素的位置和大小,因为transform不会触发回流。
什么是防抖和节流,有什么区别?如何实现?
定义
防抖和节流是两种常用的性能优化技术,它们都可以减少事件触发的次数,提高页面的响应速度。
防抖(Debounce)是指在事件触发后,等待一段时间再执行事件处理函数,如果在这段时间内又触发了该事件,则重新计时。防抖的作用是防止某个事件在短时间内多次触发,比如搜索框输入时,只有在用户停止输入一段时间后才会触发搜索。
节流(Throttle)是指在一定时间内只执行一次事件处理函数,如果在这段时间内又触发了该事件,则忽略该事件。
节流的作用是减少事件处理函数的执行次数,比如页面滚动时,只有在一定时间内才会触发滚动事件。
防抖和节流的区别在于,
- 防抖是在事件触发后等待一段时间再执行事件处理函数
- 节流是在一定时间内只执行一次事件处理函数。
- 防抖适用于事件触发频率较高的场景,比如输入框输入、窗口大小改变等,
- 节流适用于事件触发频率较低的场景,比如页面滚动、鼠标移动等。
实现
实现防抖和节流的方法有很多,可以使用setTimeout、setInterval、requestAnimationFrame等方法来实现。比较常用的是使用setTimeout来实现防抖和节流,具体实现方式如下:
防抖
function debounce(fn, delay) {
let timer = null;
return function() {
clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, arguments);
}, delay);
} }
节流
function throttle(fn, delay) {
let timer = null;
return function() {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, arguments);
timer = null;
}, delay)
}
}
}
说说你对作用域链的理解?
定义
作用域链(Scope Chain)是指在JavaScript中,每个函数都有一个作用域链,用于解析变量和函数的引用。
作用域链是由当前函数的变量对象和所有外层函数的变量对象组成的,它的顶端是全局对象(Global Object)。
当函数执行时,会先在当前函数的变量对象中查找变量和函数,如果找不到,则会沿着作用域链向上查找,直到找到为止。如果在全局对象中还找不到,则会抛出ReferenceError错误。
作用域链的形成是在函数定义时确定的,而不是在函数调用时确定的。每个函数都有自己的作用域链,它们之间是相互独立的,互不影响。
作用域链的重要性在于它决定了变量和函数的可见性和生命周期。如果变量或函数在当前函数的作用域链中,则可以被访问和使用,否则就会出现引用错误。同时,作用域链也决定了变量和函数的生命周期,当函数执行完毕后,它的作用域链会被销毁,其中的变量和函数也会被释放,以便回收内存。
说说你对原型和原型链的理解?
原型属性
显示原型和隐式原型
- 每个函数function都有一个prototype,即显式原型(属性)
- 每个实例对象都有一个
__proto__
,可称为隐式原型(属性) 在浏览器中展示的是 [[Prototype]] - 实例对象的隐式原型的值为其对应构造函数的显式原型的值–构造函数的原型对象
<script>
function Animal() {
}
// console.log(Animal.prototype.constructor === Animal) // true
Animal.prototype = { // 添加 原型方法
run : function() {
console.log('在奔跑')
}
}
new Animal().run()
let s1 = new Animal(); // 在奔跑
console.log(s1.__proto__ === Animal.prototype) // true
</script>
原型链
显示原型和隐式原型
- 每个函数function都有一个prototype,即显式原型(属性)
- 每个实例对象都有一个
__proto__
,可称为隐式原型(属性) 在浏览器中展示的是 [[Prototype]] - 实例对象的隐式原型的值为其对应构造函数的显式原型的值–构造函数的原型对象
实例对象和原型之间的连接 就称为原型链
原型模式的执行流程(原型链的查找过程) :
- 首先在实例上查找 找到后就返回
- 再去在构造函数的原型上查找 找到后就返回
- 继续去 Object.prototype 上查找 找到后就返回
- Object的原型对象是原型链尽头
<script>
function Animal(){
// this.name = "大黄"
this.run = function(){
console.log("大跑");
}
}
// Animal.prototype.name = "小黄"
Object.prototype.name = "二哈"
Object.prototype.run = function(){
console.log("小跑");
}
let a1 = new Animal();
// console.log( Animal.prototype === a1 );//false
// console.log( Animal.prototype === a1.__proto__ ); //true
// console.log( a1.name );
// console.log(a1);
a1.run();
</script>
Vue的生命周期和含义有哪些?
Vue的生命周期可以分为8个阶段,分别是:
- beforeCreate:实例刚刚被创建,数据观测和事件机制都未初始化,无法访问data、computed、methods等属性和方法。
- created:实例已经完成了数据观测和事件机制的初始化,可以访问data、computed、methods等属性和方法,但无法访问DOM。
- beforeMount:模板编译完成,但尚未挂载到DOM上。
- mounted:实例已经挂载到DOM上,可以进行DOM操作,如修改DOM节点、添加事件监听器等。
- beforeUpdate:数据更新之前,DOM尚未重新渲染。
- updated:数据更新之后,DOM已经重新渲染。
- beforeDestroy:实例销毁之前,可以进行一些清理工作,如取消定时器、解绑事件监听器等。
- destroyed:实例已经销毁,所有的事件监听器和子组件也都被销毁。
Vue的生命周期可以帮助我们了解Vue实例在不同阶段的状态和行为,从而更好地进行开发和调试。在实际开发中,我们可以利用生命周期钩子函数来进行一些初始化、清理、异步请求等操作,以及与第三方库的集成等。
Vue自定义指令的钩子函数有哪些?
Vue自定义指令的钩子函数有5个,分别是:
- bind:指令第一次绑定到元素时调用,只调用一次。
- inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。
- update:被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。
- componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
- unbind:指令与元素解绑时调用,只调用一次。
这些钩子函数可以用来在指令的不同生命周期中执行一些操作,比如绑定事件、添加样式、操作DOM等。其中,bind和unbind钩子函数是必须实现的,其他钩子函数可以根据需要选择实现。
Javascript本地存储有哪些?区别和使用场景?
JavaScript本地存储有以下几种:
-
Cookie:Cookie是一种小型的文本文件,可以存储在客户端的浏览器中。Cookie的大小有限制,一般为4KB左右,且每个域名下的Cookie数量也有限制。Cookie可以设置过期时间,可以在浏览器和服务器之间传递数据,但是不太安全,容易被篡改。
-
localStorage:localStorage是HTML5中新增的本地存储方式,可以存储5MB左右的数据,不会随着HTTP请求发送到服务器端,只能通过JavaScript访问。localStorage可以设置过期时间,但是只能手动清除,不太安全,容易被恶意攻击。
-
sessionStorage:sessionStorage也是HTML5中新增的本地存储方式,与localStorage类似,但是数据只能在当前会话中使用,会话结束后数据会被清除。sessionStorage也可以设置过期时间,但是只能手动清除,不太安全,容易被恶意攻击。
-
IndexedDB:IndexedDB是HTML5中新增的客户端数据库,可以存储大量的结构化数据,支持事务和索引,可以通过JavaScript进行操作。IndexedDB比localStorage和sessionStorage更安全,但是使用起来比较复杂。
使用场景
这些本地存储方式各有优缺点,适用于不同的场景。 -
Cookie适用于存储少量的数据,如用户登录信息、购物车信息等
-
localStorage和sessionStorage适用于存储较大的数据,如用户个性化设置、表单数据等
-
IndexedDB适用于存储大量的结构化数据,如离线应用数据、日志数据等。在使用本地存储时,需要注意数据的安全性和隐私保护,避免敏感信息泄露。