JavaScript前端面试题整合

注:如有错误请谅解,望其提出改正

!! JavaScript的数据类型都有什么?

基本数据类型:String,boolean,Number,Undefined, Null
引用数据类型:Object, Array, Function

!! 什么是window对象? 什么是document对象?

window对象是指浏览器打开的窗口。
document对象是Document对象(HTML 文档对象)的一个只读引用,window对象的一个属性。

!! null,undefined 的区别?

null :表示变量声明后赋值为null,也就是值为“空”;
undefined : 表示一个变量声明了但没有进行赋值;
undefined不是一个有效的JSON,而null是;
undefined的类型(typeof)是undefined;
null的类型(typeof)是object;

   null == undefined // true
    null === undefined // false
!! JavaScript this指针、闭包、作用域

this:指向调用上下文
闭包:内层作用域可以访问外层作用域的变量
作用域:定义一个函数就开辟了一个局部作用域,整个js执行环境有一个全局作用域。

!! 闭包是什么,有什么特性,对页面有什么影响

闭包就是能够读取其他函数内部变量的函数。
闭包的缺点:滥用闭包函数会造成内存泄露,因为闭包中引用到的包裹函数中定义的变量都永远不会被释放,所以我们应该在必要的时候,及时释放这个闭包函数

document load 和document ready的区别

Document.onload 是在结构和样式加载完才执行js
window.onload:不仅仅要在结构和样式加载完,还要执行完所有的样式、图片这些资源文件,全部加载完才会触发window.onload事件
Document.ready原生种没有这个方法,jquery中有 $().ready(function)

!! 例举3种强制类型转换和2种隐式类型转换?

强制:(parseInt,parseFloat,Number())
隐式():
1
”1”//true
null==undefined//true

!! 怎么判断一个object是否是数组(array)?

1、使用 Object.prototype.toString 来判断是否是数组

function isArray(obj){
    return Object.prototype.toString.call( obj ) === '[object Array]';
}

这里使用call来使 toString 中 this 指向 obj。进而完成判断

2、使用 原型链 来完成判断

function isArray(obj){
    return obj.__proto__ === Array.prototype;
}

基本思想是利用 实例如果是某个构造函数构造出来的那么 它的 __proto__是指向构造函数的 prototype属性。

!! WEB前端性能优化常见方法
内容优化
  1. 减少HTTP请求数:常见方法:合并多个CSS文件和js文件,利用CSS Sprites整合图像,合理设置HTTP缓存等。
  2. 减少DNS查找
  3. 避免重定向
  4. 使用Ajax缓存
  5. 延迟加载组件,预加载组件
  6. 减少DOM元素数量:页面中存在大量DOM元素,会导致javascript遍历DOM的效率变慢。
服务器优化

(1)使用内容分发网络(CDN):把网站内容分散到多个、处于不同地域位置的服务器上可以加快下载速度。
(2)GZIP压缩
(3)设置ETag:ETags(Entity tags,实体标签)是web服务器和浏览器用于判断浏览器缓存中的内容和服务器中的原始内容是否匹配的一种机制。
(4)提前刷新缓冲区
(5)对Ajax请求使用GET方法
(6)避免空的图像src

Cookie优化

(1)减小Cookie大小
(2)针对Web组件使用域名无关的Cookie

CSS优化

(1)将CSS代码放在HTML页面的顶部
(2)避免使用CSS表达式
(3)使用来代替@import

javascript优化

(1)将JavaScript脚本放在页面的底部。
(2)将JavaScript和CSS作为外部文件来引用:在实际应用中使用外部文件可以提高页面速度,
因为JavaScript和CSS文件都能在浏览器中产生缓存。
(3)缩小JavaScript和CSS
(4)删除重复的脚本
(5)最小化DOM的访问:使用JavaScript访问DOM元素比较慢。
(6)开发智能的事件处理程序

图像优化

(1)优化图片大小
(2)通过CSS Sprites优化图片
(3)不要在HTML中使用缩放图片
(4)favicon.ico要小而且可缓存

!! 防抖与节流

防抖与节流函数是一种最常用的 高频触发优化方式,能对性能有较大的帮助。
防抖 (debounce) : 将多次高频操作优化为只在最后一次执行,通常使用的场景是:用户输入,只需再输入完成后做一次输入校验即可。
节流(throttle): 每隔一段时间后执行一次,也就是降低频率,将高频操作优化成低频操作,通常使用场景: 滚动条事件 或者 resize 事件,通常每隔 100~500 ms执行一次即可。

!! 函数执行改变this

由于 JS 的设计原理: 在函数中,可以引用运行环境中的变量。因此就需要一个机制来让我们可以在函数体内部获取当前的运行环境,这便是this。
因此要明白 this 指向,其实就是要搞清楚 函数的运行环境,说人话就是,谁调用了函数。例如:
obj.fn(),便是 obj 调用了函数,既函数中的 this === obj
fn(),这里可以看成 window.fn(),因此 this === window
但这种机制并不完全能满足我们的业务需求,因此提供了三种方式可以手动修改 this 的指向:

call: fn.call(target, 1, 2)
apply: fn.apply(target, [1, 2])
bind: fn.bind(target)(1,2)
!! 如何判断一个变量是不是数组?
  1. Array.isArray :如果返回 true, 说明是数组 ;
  2. instanceof Array :如果返回true,说明是数组 ;
  3. Object.prototype.toString.call :如果值是 [object Array], 说明是数组;
  4. constructor :如果是数组,那么 arr.constructor === Array. (不准确,因为我们可以指定 obj.constructor = Array)。
function fn() {
    console.log(Array.isArray(arguments));   //false; 因为arguments是类数组,但不是数组
    console.log(Array.isArray([1,2,3,4]));   //true
    console.log(arguments instanceof Array); //fasle
    console.log([1,2,3,4] instanceof Array); //true
    console.log(Object.prototype.toString.call(arguments)); //[object Arguments]
    console.log(Object.prototype.toString.call([1,2,3,4])); //[object Array]
    console.log(arguments.constructor === Array); //false
    arguments.constructor = Array;
    console.log(arguments.constructor === Array); //true
    console.log(Array.isArray(arguments));        //false
}
fn(1,2,3,4);
!! 类数组和数组的区别是什么?
  • 拥有length属性,其它属性(索引)为非负整数(对象中的索引会被当做字符串来处理);
  • 不具有数组所具有的方法;

类数组是一个普通对象,而真实的数组是Array类型。常见的类数组有:

  • 函数的参数 arguments,
  • DOM 对象列表(比如通过 document.querySelectorAll 得到的列表),
  • jQuery 对象 (比如 $(“div”)).

类数组可以转换为数组:

//第一种方法
Array.prototype.slice.call(arrayLike, start);
//第二种方法
[...arrayLike];
//第三种方法:
Array.from(arrayLike);
//Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象。
!! == 和 === 有什么区别?
  1. === 不需要进行类型转换,只有类型相同并且值相等时,才返回 true.
  2. == 如果两者类型不同,首先需要进行类型转换。
    具体流程如下:
    首先判断两者类型是否相同,如果相等,判断值是否相等.
    如果类型不同,进行类型转换
    判断比较的是否是 null 或者是 undefined, 如果是, 返回 true .
    判断两者类型是否为 string 和 number, 如果是, 将字符串转换成 number
    判断其中一方是否为 boolean, 如果是, 将 boolean 转为 number 再进行判断
    判断其中一方是否为 object 且另一方为 string、number 或者 symbol , 如果是, 将 object 转为原始类型再进行判断
let person1 = {
    age: 25
}
let person2 = person1;
person2.gae = 20;
console.log(person1 === person2); //true,注意复杂数据类型,比较的是引用地址
!! [] == ![]

我们来分析一下: [] == ![] 是true还是false?
首先,我们需要知道 ! 优先级是高于 == (更多运算符优先级可查看: 运算符优先级)
![] 引用类型转换成布尔值都是true,因此![]的是false
根据上面的比较步骤中的第五条,其中一方是 boolean,将 boolean 转为 number 再进行判断,false转换成 number,对应的值是 0.
根据上面比较步骤中的第六条,有一方是 number,那么将object也转换成Number,空数组转换成数字,对应的值是0.(空数组转换成数字,对应的值是0,如果数组中只有一个数字,那么转成number就是这个数字,其它情况,均为NaN)
0 == 0; 为true

!! 在JS中什么是变量提升?什么是暂时性死区?

变量提升就是变量在声明之前就可以使用,值为undefined。
在代码块内,使用 let/const 命令声明变量之前,该变量都是不可用的(会抛出错误)。这在语法上,称为“暂时性死区”。暂时性死区也意味着 typeof 不再是一个百分百安全的操作。

typeof x; // ReferenceError(暂时性死区,抛错)
let x;
typeof y; // 值是undefined,不会报错

暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

!! 词法作用域和this的区别。

词法作用域:是由你在写代码时将变量和块作用域写在哪里来决定的。
this: 是在调用时被绑定的,this 指向什么,完全取决于函数的调用位置。

谈谈你对JS执行上下文栈和作用域链的理解。

执行上下文就是当前 JavaScript 代码被解析和执行时所在环境, JS执行上下文栈可以认为是一个存储函数调用的栈结构,遵循先进后出的原则。

IE和DOM事件流的区别

1.执行顺序不一样、
2.参数不一样
3.事件加不加on
4.this指向问题
IE9以前:attachEvent(“onclick”)、detachEvent(“onclick”)
IE9开始跟DOM事件流是一样的,都是addEventListener

IE和标准下有哪些兼容性的写法
var ev = ev || window.event
document.documentElement.clientWidth || document.body.clientWidth
var target = ev.srcElement||ev.target
关于JS事件冒泡与JS事件代理(事件委托)
  1. 事件冒泡:
    通俗易懂的来讲,就是当一个子元素的事件被触发的时候(如onclick事件),该事件会从事件源(被点击的子元素)开始逐级向上传播,触发父级元素的点击事件。

  2. 事件委托
    就是将子元素的事件通过冒泡的形式交由父元素来执行。利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行!

  • 可以大量节省内存占用,减少事件注册
  • 可以方便地动态添加和修改元素,不需要因为元素的改动而修改时间绑定
如何阻止事件冒泡和默认事件
//阻止事件冒泡
e. stopPropagation();//标准浏览器
event.canceBubble=true;//ie9之前
// 阻止默认事件:
//为了不让a点击之后跳转,我们就要给他的点击事件进行阻止
return false 
e.preventDefault();
js延迟加载的方式有哪些?
  1. defer和async
  2. 动态创建DOM方式(用得最多)
  3. 按需异步载入js
从输入URL到页面加载发生了什么

总体来说分为以下几个过程:
DNS解析
TCP连接
发送HTTP请求
服务器处理请求并返回HTTP报文
浏览器解析渲染页面
连接结束

内存泄露
  • 意外的全局变量: 无法被回收
  • 定时器: 未被正确关闭,导致所引用的外部变量无法被释放
  • 事件监听: 没有正确销毁 (低版本浏览器可能出现)
  • 闭包: 会导致父级中的变量无法被释放
  • dom 引用: dom 元素被删除时,内存中的引用未被正确清空
get与post的区别
getpost
参数url可见url参数不可见
通过拼接url进行传递参数通过body体传输参数
get请求是可以缓存的post请求不可以缓存
get请求页面后退时,不产生影响post请求页面后退时,会重新提交请求
一般传输数据大小不超过2k-4k(根据浏览器不同,限制不一样,但相差不大)请求传输数据的大小根据php.ini 配置文件设定,也可以无限大
!! 如何解决异步回调地狱

promise、generator、async/await

说说前端中的事件流

HTML中与javascript交互是通过事件驱动来实现的,例如鼠标点击事件onclick、页面的滚动事件onscroll等等,可以向文档或者文档中的元素添加事件侦听器来预订事件。想要知道这些事件是在什么时候进行调用的,就需要了解一下“事件流”的概念。
什么是事件流:事件流描述的是从页面中接收事件的顺序,DOM2级事件流包括下面几个阶段。

  • 事件捕获阶段
  • 处于目标阶段
  • 事件冒泡阶段

addEventListener:addEventListener 是DOM2 级事件新增的指定事件处理程序的操作,这个方法接收3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。
IE只支持事件冒泡。
1:捕获阶段 —> 2:目标阶段 —> 3:冒泡阶段
document —> target目标 ----> document
由此,addEventListener的第三个参数设置为true和false的区别已经非常清晰了:
true表示该元素在事件的“捕获阶段”(由外往内传递时)响应事件;
false表示该元素在事件的“冒泡阶段”(由内向外传递时)响应事件。

如何让事件先冒泡后捕获

在DOM标准事件模型中,是先捕获后冒泡。但是如果要实现先冒泡后捕获的效果,对于同一个事件,监听捕获和冒泡,分别对应相应的处理函数,监听到捕获事件,先暂缓执行,直到冒泡事件被捕获后再执行捕获之间。

mouseover和mouseenter的区别

mouseover:当鼠标移入元素或其子元素都会触发事件,有一个重复触发,冒泡的过程,对应的移除事件是mouseout。
mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave。

js的new操作符做了哪些事情

new 操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象。

为什么要设计同源策略

如果没有同源策略,不同源的数据和资源(如HTTP头、Cookie、DOM、localStorage等)就能相互随意访问,根本没有隐私和安全可言。为了安全起见和资源的有效管理,浏览器当然要采用这种策略。

跨域的几种方式

同源策略/SOP(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSRF等攻击。

同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

  1. 通过jsonp跨域
    1.)原生实现:
var script = document.createElement('script');
    script.type = 'text/javascript';
    // 传参并指定回调执行函数为onBack
    script.src = 'http://www.....:8080/login?user=admin&callback=onBack';
    document.head.appendChild(script);
    // 回调执行函数
    function onBack(res) {
        alert(JSON.stringify(res));
    }
2、 document.domain + iframe跨域  
    此方案仅限主域相同,子域不同的跨域应用场景。
    1.)父窗口:(http://www.domain.com/a.html)

        <iframe id="iframe" src="http://child.domain.com/b.html"></iframe>
        <script>
            document.domain = 'domain.com';
            var user = 'admin';
        </script>
        2.)子窗口:(http://child.domain.com/b.html)
        
        <script>
            document.domain = 'domain.com';
            // 获取父窗口中变量
            alert('get js data from parent ---> ' + window.parent.user);
        </script>

    弊端:请看下面渲染加载优化

3、 nginx代理跨域
4、 nodejs中间件代理跨域
5、 后端在头部信息里面设置安全域名
typeof 是否正确判断类型? instanceof呢? instanceof 的实现原理是什么?

typeof 能够正确的判断基本数据类型,但是除了 null, typeof null输出的是对象。
但是对象来说,typeof 不能正确的判断其类型, typeof 一个函数可以输出 ‘function’,而除此之外,输出的全是 object,这种情况下,我们无法准确的知道对象的类型。
instanceof可以准确的判断复杂数据类型,但是不能正确判断基本数据类型。
instanceof 是通过原型链判断的,A instanceof B, 在A的原型链中层层查找,是否有原型等于B.prototype,如果一直找到A的原型链的顶端(null;即Object.proto.proto),仍然不等于B.prototype,那么返回false,否则返回true.

for of , for in 和 forEach,map 的区别。
JavaScript执行在单线程上,所有的代码都是排队执行。

一开始浏览器执行全局的代码时,首先创建全局的执行上下文,压入执行栈的顶部。每当进入一个函数的执行就会创建函数的执行上下文,并且把它压入执行栈的顶部。当前函数执行-完成后,当前函数的执行上下文出栈,并等待垃圾回收。
浏览器的JS执行引擎总是访问栈顶的执行上下文。全局上下文只有唯一的一个,它在浏览器关闭时出栈。

作用域链: 无论是 LHS 还是 RHS 查询,都会在当前的作用域开始查找,如果没有找到,就会向上级作用域继续查找目标标识符,每次上升一个作用域,一直到全局作用域为止。
作用域链的作用是保证执行环境里有权访问的变量和函数是有序耳朵,作用域链额变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的

!! prototype 和 proto 区别是什么?

prototype是构造函数的属性。
==proto ==是每个实例都有的属性,可以访问 [[prototype]] 属性。
实例的__proto__ 与其构造函数的prototype指向的是同一个对象。

简述创建函数的几种方式
第一种(函数声明): 
function sum1(num1,num2){
   return num1+num2;
}
第二种(函数表达式-匿名函数):
var sum2 = function(num1,num2){
   return num1+num2;
}
function(){}:只能自己执行自己

第三种(函数对象方式):
var sum3 = new Function("num1","num2","return num1+num2");
Javascript如何实现继承?
  1. 原型链继承
  2. 借用构造函数继承
  3. 组合继承
  4. 寄生式继承
  5. 寄生组合继承
创建对象的几种方式?
  1. 工厂方式
  2. 构造函数方式
  3. 原型模式
  4. 混合构造函数原型模式
  5. 动态原型方式
如何优化自己的代码?
  1. 代码重用 避免全局变量(命名空间,封闭空间,模块化mvc…) ;
  2. 拆分函数避免函数过于臃肿:单一职责原则;
  3. 适当的注释,尤其是一些复杂的业务逻辑或者是计算逻辑;
  4. 内存管理,尤其是闭包中的变量释放;
  5. 减少http请求: 小图弄成大图;
  6. 合理的设置缓存 ;
  7. 资源合并、压缩 ;
  8. 将外部的js文件置底
如何判断一个js变量是数组类型
Array.isArray() //ES5

[] instanceof Array

Object.prototype.toString.call([]); //"[object Array]"
new 操作符都干了些什么?
// new共经历了四个阶段
// 1、创建一个空对象
var obj = new Object()
// 2、设置原型链
obj.__proto__ = Func.prototype
// 3、让Func中的this指向obj,并执行Func的函数体
var result = Func.call(obj)
// 4、判断Func的返回值类型
// 如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象
// (tip: 构造函数默认 return this,不用写)
if(typeof result === 'object') {
    return result
} eles {
    return obj
}
Javascript中,有一个函数,执行时对象查找时,永远不会去查找原型,这个函数是?

hasOwnProperty

javaScript中hasOwnProperty函数方法是返回一个布尔值,指出一个对象是否具有指定名称的属性。此方法无法检查该对象的原型链中是否具有该属性;该属性必须是对象本身的一个成员。
使用方法:
object.hasOwnProperty(proName)
其中参数object是必选项。一个对象的实例。
proName是必选项。一个属性名称的字符串值。

如果 object 具有指定名称的属性,那么JavaScript中hasOwnProperty函数方法返回 true,反之则返回 false。

JSON 的了解?

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。
它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小
如:{“age”:“12”, “name”:“back”}

JSON字符串转换为JSON对象:
 var obj =eval('('+ str +')');
 var obj = str.parseJSON();
 var obj = JSON.parse(str);
 
 JSON对象转换为JSON字符串:
 var last=obj.toJSONString();
 var last=JSON.stringify(obj);
如何判断当前脚本运行在浏览器还是node环境中?(阿里)

this === window ? ‘browser’ : ‘node’;
通过判断Global对象是否为window,如果不为window,当前脚本没有运行在浏览器中.

原生Js与框架的区别,优缺点?
jqurey常用的方法和大致分类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值