大家注意了:因为最近陌陌改变了推送机制,经常有朋友说错过了之前删除的文章,或者一些限时福利。 如果你错过了,你就错过了。 所以建议大家加star以便尽快收到推送。
大家好,我是爱分享的“前端实验室”~
面对毕业季,相信很多同事都在找工作、背面试卷; 今天给大家分享20个JavaScript必知问题
js中的数据类型有哪些?
记住这句咒语:四基础、两空、一物
四种基数:字符串、数字、符号、布尔值、
两个空:null,未定义
对象:对象
string、number、symbol、bool、null、undefined 属于基本数据类型
Function、Object、Date、RegExp、数组、函数、日期和自定义类是引用数据类型,属于对象
如何判断数据类型?
可以使用typeof()函数来确定数据类型; 但typeof()只能判断基本数据类型; typeof 运算符将返回一个字符串,指示该值的数据类型
typeof 运算符对于空值返回“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; 否则为假
let、const 和 var 有什么区别?
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、map、for...in 之间的区别?
两者都是遍历链表或对象的方式
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:用于遍历可迭代对象中的元素。
需要注意的是,for...of循环只能用来遍历可迭代对象,比如链表、字符串、Map、Set等,不能用来遍历普通对象。
let arr = ['China', 'America', 'Korea']
for (let o of arr) {
console.log(o) //China, America, Korea
}
这指向什么样的
在普通函数中,this 指向窗口
在定时器中这指向窗口
在构造函数中,this指向当前创建的对象
在方法中,this指向调用者
如何改变这个方向
call、apply、bind的作用就是改变函数执行时的上下文,简单来说就是改变函数运行时的this点
什么是闭包以及使用场景
闭包是一个可以访问另一个函数范围内的变量的函数; 当嵌套函数引用其内部函数的变量或参数时,就会生成闭包。
应用场景:
创建私有变量
延长变量的生命周期
功能聚焦、功能节流
闭包的优点:
关闭的缺点:
类继承
ES6中的类使用extends来实现继承:
如果泛型类型有构造函数,则泛型类型必须在构造函数方法中调用super方法,否则创建新实例时会报错。 因为泛型没有自己的this对象javascript 对象空,而是继承父类的this对象。
如果不调用super函数,子类就无法获取this对象。 super()作为父类的构造函数,只能出现在泛型constructor()中; 所以super指向父类的原型对象,可以调用父类的属性和技术。
如果泛型类型没有构造函数,则默认添加一个,构造函数中调用super函数,相当于调用父类的构造函数
new关键字有什么作用?箭头函数作用域和作用域链
作用域是指程序中变量和函数的范围
全局作用域:指定义在代码块之外、函数之外、或者模块之外的变量、函数等,具有全局作用域。
局部作用域:指在代码块、函数或模块内部定义的具有局部作用域的变量、函数等。
ES6规范下,还引入了块级作用域的概念。 块级作用域可以用大括号包裹一段代码。 这段代码中定义的变量仅在本代码块内有效,超过此范围后将失效,并且不会影响其他代码块中的同名变量。
作用域链:在Javascript中使用变量时,Javascript引擎会首先尝试在当前作用域中查找该变量,如果没有找到,则在较低的作用域中查找,以此类推,直到找到该变量或已经在该变量中全球范围
原型和原型链
原型:每个函数都有一个原型属性,它是一个指向对象的指针javascript 对象空,其目的是包含可由特定类型的所有实例共享的属性和技术。
原型链:JavaScript中的所有对象都是继承自其原型对象。原型对象本身也是一个对象,它也有自己的原型对象。 这样逐层追踪产生了一个类似数组的结构,这就是原型链
承诺
Promise是异步编程的一种解决方案,代表异步操作的最终状态和返回值。
Promise有三种状态:pending(等待状态)、fulfilled(成功状态)、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;
简而言之,谁先成功,谁先失败,就被认为是比赛的成功或失败。
Promise.race([promise1, promise2]).then(success1, fail1)
异步等待和承诺有什么区别?
Promise 是使用链式调用 .then() 或 .catch() 来处理异步操作的结果,而 async/await 将异步代码转换为同步代码。 使用async/await可以让代码更加清晰易懂,并且减少回调函数的嵌套。
在 Promise 中,可以通过 .catch() 方法捕获并处理错误; 而在 async/await 中,您需要使用 try/catch 块来捕获和处理错误。
async/await可以让异步操作的程序流程更加清晰简洁,并且可以有效防止反弹地狱的问题。 不过需要注意的是,async/await 都是基于 Promise Sugar 的,所以它们之间没有本质区别。
创建函数有几种形式?