js面试题
js中let和const,var的作用
在现在js中国,let&const是创建变量的不同方式.在早期js中,使用var老创建变量.let&const是es6引入的,其目的是在js中创建俩种不同类型的变量,一种是可变的,一种是不可变的.
const:用于创建一个不可变变量(常量).不可变变量是指在程序的整个生命周期永远不会改变的变量
let:用于创建一个可变变量,可以任意次数的修改,let声明的变量只在当前代码块内有效
js的主要几类错误
加载时错误:加载web页面时出现的错误(如语法错误)称为加载时错误,它会动态生成错误
运行时错误:由于滥用html语言中的命令导致的错误
逻辑错误:这些错误是由于具有不同操作的函数执行了错误的逻辑而导致的
mul函数
将一个值为参数传递给一个函数,而该函数将返回另一个函数,将第二个值传递给该函数,然后重复继续
function mul (x) {
return function (y) { // anonymous function
return function (z) { // anonymous function
return x * y * z;
};
};
}
console.log(mul(2)(3)(4))
如何在js中动态添加/删除对象的属性?
可以使用object.property=value添加属性 用delete object.property删除属性
什么是promise
es6原生提供了Promise对象
promise对象代表了未来将要发生的事件,用来传递异步操作的消息
特点
对象的状态不受外界影响.promise对象代表一个异步操作,有三种状态
- pending:初始状态,不是成功或失败状态
- fulfiled:意味着操作成功完成
- rejected:意味着操作失败
只有异步的操作结果,可以决定当前是哪一种状态.
一旦状态改变,就不会再变,任何时候都可以得到这个结果.promise对象的状态改变,只有俩种可能:
- 从陪你搞Pending 变为resoved
- 从pending变为Rejected.
只要这俩种情况发生,情况就不会再改变了.会一直保持这个结果.这与事件event不同,就算改变已经发生了,你再对 Promise 对象添加回调函数,也会立即得到这个结果。事件的特点是,如果你错过了它,再去监听,是得不到结果的.
优点
有了promise对象,就可以将一部操作以同步的流程表达出来,避免了层层嵌套的回调函数.此外Promise对象提供统一的接口,使得一部操作更加容易
缺点:无法取消promise,一旦创建就会立即执行,无法中途取消.其次如果不设置回调函数,promise内部抛出的错误,不会反应到外部.第三,当处于pending状态 时,无法得知目前进展到哪个阶段
var myFirstPromise = new Promise(function(resolve, reject){
//当异步代码执行成功时,我们才会调用resolve(...), 当异步代码失败时就会调用reject(...)
//在本例中,我们使用setTimeout(...)来模拟异步代码,实际编码时可能是XHR请求或是HTML5的一些API方法.
setTimeout(function(){
resolve("成功!"); //代码正常执行!
}, 250);
});
myFirstPromise.then(function(successMessage){
//successMessage的值是上面调用resolve(...)方法传入的值.
//successMessage参数不一定非要是字符串类型,这里只是举个例子
document.write("Yay! " + successMessage);
});
操作
Promise.prototype.then方法:链式操作
Promise.prototype.then 方法返回的是一个新的 Promise 对象,因此可以采用链式写法。
Promise.prototype.catch方法:捕捉错误
Promise.prototype.catch 方法是 Promise.prototype.then(null, rejection) 的别名,用于指定发生错误时的回调函数。
promise对象的错误具有冒泡性质,会一直向后传递,直到被捕获位置.也就是说,错误总会被下一个catch语句捕获
js页面重定向
location.href.href="xxxx"
location.replace:windows.location.replace("xxxxxxxxxx")
undefined,null和undeclared
null
表示没有对象,即不应该有值,转为数值时为0.
undefined
表示缺少值,就是此处应该有一个值,但还没有定义,转为数值类型时为NAN.出现情况
- 变量被声明了,但没有赋值
- 调用函数时,应该提供的参数没有提供,该参数为undefined
- 对象没有赋值的属性,该属性为undefined
- 函数没有返回值时,默认返回undefined
undeclared:js语法错误,没有申明直接使用,js无法找到对应的上下文
js基本和非基本数据类型之间的区别
js有6种基本数据类型:Undefined,Null,Bollean,Number和String还有一种复杂数据类型Object,Object,Array,Function属于引用类型
- 基本数据类型是不可变的,而非基本数据类型是可变的
- 基本数据类型是不可变的,因为它们一旦创建就无法更改,但非基本数据类型刚可更改,意味着一旦创建了对象,就可以更改它。
(不可变指的是任何方法都无法改变一个基本数据类型的值,)
- 将基本数据类型与其值进行比较,这意味着如果两个值具有相同的数据类型并具有相同的值,那么它们是严格相等的。
- 非基本数据类型不与值进行比较。例如,如果两个对象具有相同的属性和值,则它们严格不相等。
js的浅拷贝与深拷贝
浅拷贝就是把父对象的属性,全部拷贝给子对象.此时子对象拷贝的是父对象的地址,子父对象相互影响
深拷贝:就是把福对象的属性中的值拷贝给子对象,此时不论对象如何改变都不会影响到子对象
深拷贝有以下方法
把原来对象的属性遍历一遍,赋给一个新的对象。
var cloneObj = function (obj) {
var newObj = {};
if (obj instanceof Array) {
newObj = [];
}
for (var key in obj) {
var val = obj[key];
//newObj[key] = typeof val === 'object' ? arguments.callee(val) : val; //arguments.callee 在哪一个函数中运行,它就代表哪个函数, 一般用在匿名函数中。
newObj[key] = typeof val === 'object' ? cloneObj(val): val;
}
return newObj;
};
//测试
var obj = {a:function(){console.log(this.b.c)},b:{c:1}},//设置一个对象
newObj = cloneObj(obj);//复制对象
newObj.b.c=2;//给新对象赋新值
obj.a();//1,不受影响
newObj.a();//2
讲对象序列化再解析回来,如果有函数则不能正确复制
var obj = {a:1,b:2}
var newObj = JSON.parse(JSON.stringify(obj));
newObj.a=3;
console.log(obj);
console.log(newObj);
针对数组对象用的方法,用数组方法concat一个空数组
var a=[1,2,3];
var b=a;
var c=[].concat(a);
a.push(4);
console.log(b);
console.log(c);
主流Object.assign() 方法用于在JS中克隆对象
var x = {myProp: "value"};
var y = Object.assign({}, x);
每秒调用一个函数
使用setInterval()在每秒内调用函数
setInterval(function (){ alert("Hello"); }, 3000);
js中的宿主对象与原生对象有何不同
宿主对象:这些是运行环境提供的对象.这意味着在不同的环境下是不同的,列入浏览器包含windows这样的对象,但node.js环境提供像nodeList这样的对象
原生对象:这些是js中内置对象.它们被称为全局对象,因为如果使用js内置对象不受运行环境影响
js的高阶函数
js的函数其实都指向某个变量.既然变量可以指向函数,函数的参数应该也能接收变量那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数
高阶函数是一个函数 ,它接收函数作为参数或酱函数作为输出范返回
function add(x,y,f){
return f(x)+f(y)
}
console.log(add(-5,6,Math.abs));
常见的高阶函数
map
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
该方法通过调用作为输入数组中每个元素的参数提供的回调函数来创建一个新数组.该map()方法将从回调函数中获取每个返回值,并使用这些值创建一个新的数组.
传递给回调函数的map方法接受三个参数element,index,array
reduce
再看reduce的用法.Array的reduce()接收俩个参数,作用是把结果继续和序列的下一个元素做响应的计算
var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
return x + y;
}); // 25
filter
filter也是一个常用操作,它用于把array的某些元素过滤掉,然后返回剩下的元素.和 map类似,array的fileter也接收一个函数.和map不同的是,filter把传入的函数一次作用于每个元素,根据返回值是true还是false决定保留还是丢弃该元素
sort
因为array的sort默认把所有元素先转换为String再排序,结果'10'排在了'2'的前面,因为字符'1'比字符'2'的ASCII码小。如果不知道sort()方法的默认排序规则,直接对数字排序,绝对栽进坑里!
幸运的是sort方法也是一个高阶函数,它可以接受一个函数来比较函数实现自定义的排序
js中==和===的区别是什么
对于String,number等基础类型,==和===有区别
- 不同系之间的比较,==比较转化成同一类型后的值看值是否相等,如果===如果类型不同,其结果就是不等
- 同类型的比较,直接比较值,俩者结果 一样
对于array,Object等高级类型,==和===没有区别
进行指针地址比较
基础与高级类型,==和===有区别
- 对于==,将高级转化为基础类型,进行值比较
- 因为类型不同,===结果为false
js的匿名函数是什么
匿名函数就是没有函数名的函数
js能否进行301重定向
js完全运行在客户端上,301是服务器作为相应发送的代码,因此js中不可能进行301重定向
js中的冒泡事件和捕获
由冒泡事件衍生出的事件委托机制,既然事件是冒泡传递的,那可以让某个父节点统一处理事件,通过判断事件的发生地(即事件产生的节点),然后做出相应的处理。就是将子元素的事件处理程序绑定到父类上,例如常见的ul>li> a列表标签的写法应用。
- 1、IE的没有事件捕获,标准有
- 2、IE的事件名前面有on,标准没有
- 3、标准会根据写的顺序正确执行,而IE低版本是倒序执行
- 4、IE的this指向window,而标准的指向触发这个事件的元素
事件捕获
在html dom pai中,有俩种时间方法,俩种是事件冒泡和事件补货.第一个方式事件冒泡将事件指向预期的目标第二方法称为事件补货,其中事件乡下到到达元素
事件冒泡
冒泡的工作原理与冒泡类似,事件由最内部的元素处理,然后传播到外部元素。
事件模型分为三个阶段
- 捕获阶段:在事件冒泡中,捕获阶段不会响应任何事件
- 目标阶段:目标阶段就是指事件的响应到触发的底层元素上
- 冒泡阶段:冒泡阶段就是时间的触发响应会从最底层目标一层一层地向外到最外层,事件代理即是利用事件冒泡机制把里层所需要响应的事件绑定到外层
事件委托
事件委托也叫事件代理,试想一下,如果有一个列表,列表中有大量的列表,我们需要在点击列表的时候响应一个事件
如果给每一个列表都绑定一个函数,那对于内存和性能消耗是非常大的
因此比较好的方法就是把这个事件绑定到父层,也就是ul上,然后在执行事件的时候再去匹配判断目标元素
如何将文件的所有导出作为对象
import * as objectname from ‘./file.js’用于将所有导出的成员导入为对象。 可以使用对象的点(.)运算符来访问导出的变量或方法,如:
什么是箭头函数
箭头函数是es6或更高版本中编写函数表达式的简明方法.
特点:
- 箭头函数this为父作用域的this,不是调用时的this
- 箭头函数不能作为构造函数,不能使用new
- 箭头函数没有arguments,caller,callee
- 箭头函数通过call和apply调用,不会改变this的指向,只会传入参数
- 箭头函数没有原型属性
- 箭头函数不能作为Generrator函数,不能使用yiled关键字
- 建调皮函数返回对象的时候要加一个小括号
- 箭头函数在ES6 class中声明的方法为实例方法,不是原型方法
- 多重箭头函数就是一个高阶函数,相当于内嵌函数
什么提升
引擎会在解析js代码之间首先进行对齐编译,编译过程中一部分的工作就找到所有的声明,并用合适的作用域将他们关联起来,这也正是词法作用域的核心内容
最简单的说就是js在代码执行前引擎会进行预编译,预编译期间会将变量声明与函数声明提升至其对应作用域的顶端
console.log(a);
var a = 3;
//预编译后的代码结构可以看做如下
var a; // 将变量a的声明提升至最顶端,赋值逻辑不提升。
console.log(a); // undefined
a = 3; // 代码执行到原位置即执行原赋值逻
变量提升
变量声明的提升是以变量所处的第一层词法作用域为单位的,即全局做鱼中声明的变量会提升至全局最顶层,
函数提升
有了上面变量提神的说明,函数提升理解起来就比较容易了,但较之变量提升,还是有区别的,函数声明之会提升函数声明,不会提升函数表达式.
js和es的关系
EXMAScrpit和javaScript的关系是,欠着是后者的规范,后者是前者的实现
什么叫use strict
use strict是es5中引入的js指令.使用use strict指令目的是强制执行严格模式下的代码.在严格模式下,不能再不声明变量的情况下使用变量