面临毕业季,相信有很多朋友正在进行找工作,背面试题;今天就分享给大家20道JavaScript必会的问题
记住口诀:四基两空一对象
四基:string,number,symbol,bool,
两空:null,undefined
一对象:object
string,number,symbol,bool,null,undefined 属于基本数据类型
Function、Object、Date、RegExp、数组,函数,日期 和自定义类等是引用数据类型,属于object
typeof()
函数来判断数据类型;但是typeof()
只能判断基本数据类型;typeof 运算符会返回一个字符串,表明该值的数据类型typeof 运算符对于 null 值会返回 "object"。这实际上是 JavaScript 最初实现中的一个错误,然后被 ECMAScript 沿用了。
typeof(1) //number
typeof("1") //string
typeof(true) //boolean
typeof(undefined) //undefined
typeof(null) //object
instanceof
用来判断一个变量是否是某个对象的实例,所以对于引用类型可以使用instanceof来进行类型判断。它返回true或者false
var obj = {};
obj instanceof Object; //true
var arr = [];
arr instanceof Array; //true
var now = new Date();
now instanceof Date; //true
var func = function(){};
func instanceof Function; //true
Object.prototype.toString.call()
判断Object.prototype.toString().call()
可以获取到对象的不同类型
let a = [1,2,3]
Object.prototype.toString.call(a) === '[object Array]';//true
可以使用 Array.isArray()
方法来判断一个值是否为数组。Array.isArray(arr)
方法会返回一个布尔值,如果该值是数组,则返回 true;否则返回 false
var和let都是声明变量的,var有变量提升,let没有,但是let具有块级作用域
const声明常量,具有块级作用域
splice()
方法用于向数组中 插入、删除或替换元素。返 回一个新的数组对象,这一数组是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。方法会改变原始数组。
const arr = [1, 2, 3, 4, 5];
arr.splice(2, 1); // 删除从第二个位置开始的一个元素(即元素 3)
console.log(arr); // [1, 2, 4, 5]
slice()
方法用于截取数组中的一段元素,并返回这些元素组成的新数组。slice()
方法不会修改原始数组
const arr = [1, 2, 3, 4, 5];
console.log(arr.slice(2)); // [3, 4, 5]
console.log(arr.slice(1, 4)); // [2, 3, 4]
console.log(arr); // [1, 2, 3, 4, 5]
都是遍历数组或者对象的方法
forEach: 对数组的每一个元素执行一次提供的函数(不能使用return、break等中断循环),不改变原数组,无返回值
let arr = ['a', 'b', 'c', 'd']
arr.forEach(function (val, idx, arr) {
console.log(val + ', index = ' + idx) // val是当前元素,index当前元素索引,arr数组
console.log(arr)
})
map:map方法和forEach方法一模一样,但是其区别就在于,forEach方法,旨在处理单个数据,map方法,旨在整理整体数据,并返回整理后的数据。map有返回值
var a = [1,2,3,4,5,6,7,8,9,10];
var newA = a.map(function(val, index){
return val*val;
})
console.log(newA); // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
for…in: 用来遍历一个对象中的可枚举属性;
let obj = {a: '1', b: '2', c: '3', d: '4'}
for (let o in obj) {
console.log(o) //遍历的是对象的属性名称 a,b,c,d
console.log(obj[o]) //这个才是属性对应的值1,2,3,4
}
for...in 循环不仅会遍历对象自身的属性,还会遍历其原型链上的属性。因此,在使用 for...in 循环时,可以使用 hasOwnProperty() 方法来判断一个属性是否为对象自身的属性
for…of: 用来遍历一个可迭代对象(iterable object)中的元素。
需要注意的是,for...of 循环只能用于遍历可迭代对象,例如数组、字符串、Map、Set 等,而不能用于遍历普通对象。
let arr = ['China', 'America', 'Korea']
for (let o of arr) {
console.log(o) //China, America, Korea
}
call、apply、bind
作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向
apply()
的第一个参数是this的指向,在非严格模式下,第一个参数为null或者undefined时会自动替换为指向全局对象,apply()的第二个参数为数组或类数组。该方法在函数被借用时,会立即执行,call()
是apply的语法糖,作用和apply()一样,同样可实现继承,唯一的区别就在于call()接收的是参数列表,而apply()则接收参数数组。bind()
的作用与call()和apply()一样,都是可以改变函数运行时上下文,区别是call()和apply()在调用函数之后会立即执行,而bind()方法调用并改变函数运行时上下文后,返回一个新的函数,供我们需要时再调用。闭包是指有权访问另外一个函数作用域中的变量的函数;当一个嵌套函数引用了其外层函数的变量或者参数时,就形成了一个闭包。
应用场景:
闭包的优点:
闭包的缺点:
ES6中的class用extends实现继承:
如果子类有constructor,那子类必须在constructor方法中调用super方法,否则new实例时会报错。因为子类没有自己的this对象,而是继承父类的this对象。
如果不调用super函数,子类就得不到this对象。super()作为父类的构造函数,只能出现在子类的constructor()中;所以super指向父类的原型对象,可以调用父类的属性和方法。
如果子类没有constructor,则默认添加一个,并且在constrcutor中调用super函数,相当于调用父类的构造函数
作用域是指程序中变量、函数的作用范围
作用域链: 当在Javascript中使用一个变量的时候,首先Javascript引擎会尝试在当前作用域下去寻找该变量,如果没找到,再到它的上层作用域寻找,以此类推直到找到该变量或是已经到了全局作用域
原型:每个函数都有一个 prototype(原型) 属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
原型链:JavaScript 中所有的对象都是由它的原型对象继承而来。而原型对象自身也是一个对象,它也有自己的原型对象,这样层层上溯,就形成了一个类似链表的结构,这就是原型链
Promise 是异步编程的一种解决方案,表示一个异步操作的最终状态以及返回的值。
promise有三种状态:pending(等待态),fulfiled(成功态),rejected(失败态);状态一旦改变,就不会再变。
Promise.all 用法:
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。当所有的实例都成功才会调用success1
Promise.all([promise1, promise2]).then(success, fail)
Promise.race 用法:
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
promise1和promise2只要有一个成功就会调用success;
promise1和promise2只要有一个失败就会调用fail;
总之,谁第一个成功或失败,就认为是race的成功或失败。
Promise.race([promise1, promise2]).then(success1, fail1)
async/await 能够使异步操作的程序流程更加清晰、简洁,同时还能有效地避免回调地狱的问题。但是需要注意的是,async/await 是基于 Promise 的语法糖,因此它们之间并没有本质上的差别。
function Fn(x,y){
return x + y;
}
var sum = function(n1,n2){
return n1+n2;
};
var sum3=new Function('n1','n2','return n1+n2');
console.log(sum3(2,3));//5
防抖:n 秒后再执行回调,若在 n 秒内被重复触发,则重新计时;防抖的基本思想是在函数被连续调用时,只执行最后一次调用,并在指定的时间间隔内没有新的调用才执行函数。如果在时间间隔内有新的调用,则重新计时。
function debounce(func, delay) {
let timer;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
func.apply(this, args);
}, delay);
};
}
节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效;节流的基本思想是限制函数在一定时间间隔内的执行次数,例如每隔一段时间执行一次,并在该时间间隔内忽略其他的函数调用。
function throttle(func, delay) {
let timer;
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
func.apply(this, args);
timer = null;
}, delay);
}
};
}
浅拷贝:只是将数据中所有的数据引用下来,依旧指向同一个存放地址,拷贝之后的数据修改之后,也会影响到原数据的中的对象数据
function shallowCopy(obj){
var data = {};
for (var i in obj){
if(obj.hasOwnProperty(i)){ // for in 循环,也会循环原型链上的属性,所以这里需要判断一下
//hasOwnProperty的相关知识点,查看下面的:相关知识点补充
data[i] = obj[i]
}
}
return data
}
深拷贝:将数据中所有的数据拷贝下来,对拷贝之后的数据进行修改不会影响到原数据
function deepCopy(obj) {
if (typeof obj !== 'object' || obj === null) {
return obj; // 非对象类型直接返回
}
let copy = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
copy[key] = deepCopy(obj[key]); // 递归拷贝对象的每个属性值
}
}
return copy;
}
跨域是浏览器基于同源策略的一种安全手段;浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议有一个不同,都是跨域
解决跨域的方法:
CORS: 全称是跨域资源共享,是一种 ajax 跨域请求资源的方式,支持现代浏览器,IE支持10以上。当你使用XMLHttpRequest发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin(访问控制允许来源);
res.setHeader('Access-Control-Allow-Origin','指定的允许地址')
如果浏览器版本过低,则不支持CORS;此时可以使用JSOP
JSONP是通过script 标签加载数据的方式去获取数据当做 JS代码来执行 提前在页面上声明一个函数,函数名通过接口传参的方式传给后台,后台解析到函数名后在原始数据上「包裹」这个函数名,发送给前端。换句话说,JSONP需要对应接口的后端的配合才能实现。
代理(Proxy)也称网络代理,是一种特殊的网络服务,允许一个(一般为客户端)通过这个服务与另一个网络终端(一般为服务器)进行非直接的连接。一些网关、路由器等网络设备具备网络代理功能。一般认为代理服务有利于保障网络终端的隐私或安全,防止攻击
js是单线程的 ,单线程意思就是同一时间只能做一件事,按照先后顺序执行.
宏任务主要有:script代码段、setTimeout、setInterval、Promise的构造函数、setImmediate、I/O等.
微任务主要有:process.nextTick和Promise的回调
事件委托是利用事件冒泡机制,将事件处理程序添加到父元素上,以代理子元素上发生的事件。这样可以避免给子元素单独添加事件处理程序的麻烦,并且可以提高性能和代码可维护性。
事件循环(Event Loop)是 JavaScript 运行时环境(如浏览器或 Node.js)用来处理异步操作的机制。它负责管理 JavaScript 代码的执行顺序,使得异步操作能够以非阻塞的方式进行。
事件循环的主要思想是将任务分为不同的队列,然后按照特定的规则来执行这些队列中的任务。在浏览器环境中,事件循环由浏览器的主线程控制,而在 Node.js 环境中,则由 Node.js 的事件驱动模型管理。
下面是事件循环的基本步骤:
进程定义: 进程是操作系统分配资源的最小单元
线程定义: 线程是操作系统调度的最小单元。
进程与线程的区别:
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有