文章目录
-
-
-
- 一.JS数据类型
- 二、判断数据类型的方法
- 三.new操作符具体做了什么?
- 三、dom.onclick 和 dom.addEventListener的区别?
- 四、JS内置属性和方法
- 五、逻辑与 && 和 逻辑或 ||
- 六、作用域和作用域链
- 七、预解析和变量提升
- 八、改变this的指向的函数的三个方法(bind / call / apply)
- 九 ...args剩余参数(扩展运算符)和 arguments对象之间的区别?
- 十、遍历方法
- 十一、JavaScript NaN 属性
- 十二、null 和 undefined?
- 十三、 = = = 和 = = 的区别
- 十四、0.1+0.2 为什么不等于 0.3?
- 十五、JS语言类型
- 十六、JavaScript 中日期时间格式转换 && 封装一个倒计时函数
- 十七、函数的 length 是多少?
- 十八、 DOM事件流
- 十九、构造函数
- 二十、原型和原型链
- 二十一、中文是多少长度?
- 二十二、简述cookie/session记住登录状态机制原理
- 二十三、cookies,session,sessionStorage,localStorage 的区别?
- 二十四、charCodeAt() 方法
- 二十五、for-in和for-of的区别
- 二十六、事件流有三个阶段:
- 二十七、常见的事件:
- 二十八、JS严格模式
- 二十九、 ~~字符
- 三十、Map和object之间的区别
- 三十一、位运算符
- 三十二、delete删除的性能
- 三十三、浏览器缓存各个文件的具体缓存配置
- 三十四、Var 和 Let 以及 Const
- 三十五、 Const 的进一步认识
- 三十六、**将值不可修改即使是引用类型**
- 三十七、 箭头函数和普通函数
- 三十七、 symbol类型
- 三十八、promise
- 三十九、..args剩余参数(扩展运算符)
- 四十、 ArrayBuffer
-
-
以下是四十个常见的JS面试题,大家开始冲!
一.JS数据类型
undefined、symbol、string、number、null、boolean、bigInt、object
1.种类
- 原始(基本)数据类型7种:number、string、boolean、null、undefined、symbol、bigInt(栈中存储,大小固定)
- 引用(复杂)数据类型:object、array、函数(堆中存储,大小不固定)
2.概念 - 基本:简单的数据段,表示不能再细分下去的基本类型
- 复杂:有对个值构成的对象,是存储多个属性的容器,对象值得存储是引用地址,操作相应的值会改变值
3.内存 - 基本:原始数据类型特点是占据空间小,大小固定,属于被频繁使用的数据,在内存中是存储在栈区
- 复杂:复杂数据类型特点是占据空间大,大小不固定。在内存中只在栈中存储是会影响程序的运行,因此在内存中使用的栈区+堆区,栈区存放指针,指针是指向实体的内存地址,实体则存放在堆中
补充
在操作系统中内存分为: - 栈区:编译器自动分配存放参数变量(类似数据结构的栈)
- 堆区:开发者分配,如果不主动释放,则程序结束后收回
二、判断数据类型的方法
1.typeof
- 一般用来 判断基本数据类型,
- 目前能返回string,number,boolean,symbol,bigint,unfined,object,function这八种判断类型,但是注意 null 和数组返回的是 Object 。而且对于引用类型返回的是 object 因为所有的对象的原型最终都是 Object。
- 面试题:为什么typeof null 是 Object?
- 答:因为在JavaScript中,不同的对象都是使用二进制存储的,如果二进制前三位都是0的话,系统会判断为是Object类型,而null的二进制全是0,自然也就判断为Object
补充
这个bug是初版本的JavaScript中留下的,扩展一下其他五种标识位: - 000 对象
- 1 整型
- 010 双精度类型
- 100字符串
- 110布尔类型
2.instanceof(根据原型链判断)
- 判断引用数据类型的,判断基本数据类型无效
- instanceof 也可以判断一个实例是否是其父类型或者祖先类型
- instanceof原理实际上就是查找目标对象的原型链(判断构造函数的prototype属性是否出现在某个实例对象上的原型链上,且原型链的尽头是null)
[] instanceof Array ; //true
手写实现instanceof
function myInstance(L,R){
//获取判断对象隐式原型
var LP = L._proto_
//判断类型的显示原型
var RP = R.prototype
while(true){
if(LP == null) return false
if(LP == RP) return true
LP = LP._proto_
}
console.log(myIntance({
},object))
}
3.对象的构造器:constructor
- 与 instanceof 相似,但是对于 instanceof 只能再检测引用类型, 而 constructor 还可以检测基本类型,因为 constructor是原型对象的属性指向构造函数。
注意 - null和undefined是无效的对象,因此是不会有 constructor 存在的,所以无法根据 constructor 来判断。
- JS对象的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype 后,原有的 constructor 会丢失,constructor 会默认为Object
- 类继承的也会出错,因为 Object 被覆盖了,检测结果就不对了
4.对象原型链判断:Object.prototype.toString.call
- toString 是Object 原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString运行时this指向的对象类型, 返回的类型格式为[object,xxx],xxx是具体的数据类型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument… 基本上所有对象的类型都可以通过这个方法获取到。
- 必须通过 Object.prototype.toString.call 来获取,而不能直接 new Date().toString(), 从原型链的角度讲,所有对象的原型链最终都指向了Object,按照JS变量查找规则,其他对象应该也可以直接访问到Object的 toString 方法,而事实上,大部分的对象都实现了自身的 toString 方法,这样就可能会导致 Object 的 toString 被终止查找,因此要用 call 来强制执行 Object 的 toString 方法。
- 缺点:不能细分为谁谁的实例
1 Object.prototype.toString.call("a")
"[object String]"
2 Object.prototype.toString.call(undefined)
"[object Undefined]"
3 Object.prototype.toString.call(null)
"[object Null]"
4 Object.prototype.toString.call(new Date())
"[object Date]"
三.new操作符具体做了什么?
new操作符通过构造函数创建的实例,可以通过访问构造函数的属性和方法,也将实例和构造函数通过原型链连接起来
1.创建一个新对象,并且在内存中创建一个新的地址
let obj = new Obect()
2.设置创建对象的原型链继承构造函数的原型
obj._proto_ = 构造函数的.prototype
3.绑定构造函数的this的指向,将构造函数的this指向创建的对象,并且执行函数体
let result =Fn.call(创建的对象);
4.判断构造函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象
return result instanceof Object? result: obj;
三、dom.onclick 和 dom.addEventListener的区别?
1.基本概念
- dom.onclick:onclick 事件会在元素被点击时发生,可以在 HTML 和 JavaScript 中使用,所有的浏览器都支持 onclick 事件。
- dom.addEventListener:document.addEventListener() 方法用于向元素添加事件。具有三个参数,分别是事件,触发执行的回调函数,以及是否在在捕获或冒泡阶段执行,IE8以及IE8之前的老版本不支持,以前通过attachEvent()方法来监听绑定方法
2.主要区别
dom.onclick:
- 可以内联标签上事件监听,但是只能添加一个事件,绑定多个后者会覆盖前者
- 潜在安全问题XXS跨站脚本攻击
- 不能选择DOM事件流
- 内联的时候不能分离文档结构和逻辑
dom.addEventListener
- 不考虑性能的情况下,可以添加多个事件绑定到钙元素上都会执行
- 不能再HTML标签中使用,只能在script中使用
- 可以通过useCpature参数,选择事件流
- 分离文档结构,大型项目中更加便于维护
四、JS内置属性和方法
JS中常用的内置对象:Array对象、Date对象、正则表达式对象、string对象、Global对象
方法:
这些内置对象中的一些方法
各方法详情
五、逻辑与 && 和 逻辑或 ||
属于短路运算符(例如第一个操作数决定了结果,就不会对第二个操作数求值)
- 只要“&&”前面是false,无论“&&”后面是true还是false,结果都将返“&&”前面的值;
- 只要“&&”前面是true,无论“&&”后面是true还是false,结果都将返“&&”后面的值;
- 只要“||”前面为false,不管“||”后面是true还是false,都返回“||”后面的值。
- 只要“||”前面为true,不管“||”后面是true还是false,都返回“||”前面的值。
补充
- 真值:除了假值都是真值
- 假值6个:“ ”、false、undefined、null、NaN、0 在逻辑运算和隐式转换中会被转换为false
六、作用域和作用域链
作用域
- 变量和函数的可访问的范围,即作用域控制这变量的可见性和生命周期
- 全局作用域:变量,函数在整个全局中都能被访问到,它的生命周期和页面生命周期的等同
- 局部作用域:函数,{}内部声明的变量和函数
作用域链
上下级之间的不同作用域构成作用域链
- 寻找一个变量的值和方法时现在当前作用域范围(自身内部)中找不到时,就会往他的上一级寻找有没有,直到全局都没有的,返回 undefined。
- 内部函数访问外部函数函数变量就是采取的是作用域链查找
七、预解析和变量提升
JS引擎在执行代码的时候1.预解析2.执行代码
预解析:JS引擎将JS所有以Var声明的变量和全局的function都提升到作用域的最前面
变量提升:将所有的变量声明提升到当前作用域的最前面,无赋值操作
八、改变this的指向的函数的三个方法(bind / call / apply)
作用都是用来重新定义 this 这个对象的!
- 相同:都能改变 this 的指向,都是挂载在 Function. prototype 上
- 不同:call 和 apply 是使用后马上执行,而 bind 是返回一个新的函数,调用回调函数才会执行目标函数。并且 call 和 bind 的参数格式是一样的,第一个参数是 this 的指向对象,其余参数用逗号,apply 是参数需要放到数组中。
//调用父级的同时将父级函数里面的this指向子函数里面的this,使子函数可使用父函数的里面的方法和属性
father.myFun.call(son,'成都','上海');
father.myFun.apply(son,['成都','上海']);
father.myFun.bind(son,'成都','上海')();
九 …args剩余参数(扩展运算符)和 arguments对象之间的区别?
1.剩余参数(拓展运算符)只包含那些没有对应形参的实参,而 arguments (对应传递给函数参数的类数组对象)包含了传给函数的所有实参。
2.arguments对象不是一个真正的数组,而剩余参数是真正的 Array实例,也就是说你能够在它上面直接使用所有的数组方法,比如 sort,map,forEach或pop。
3.arguments对象还有一些附加的属性 如callee属性)。
十、遍历方法
详情:http://t.csdn.cn/xe0dd
一、遍历数组的方法
- 1.for循环 --使用变量将数组长度缓存起来
- 2.forEach() -ES5语法,对数组的每个元素执行一次提供的函数,不能使用break、return
arr.forEach(function(item,index,arr){
console.log("元素:"+item+" 索引:"+index+" 整个数组:"+arr);
- 3.map() --ES5语法,创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果
arr.map(function(val,index){
console.log("元素:"+val+" 索引:"+index);
return val*val;
- 4.for of (可迭代的对象都可遍历)
for(let item of arr){
console.log("元素:"+item);
二、遍历对象的方法
- 1.for…in 以任意顺序遍历一个对象自有的、继承的、可枚举的、非Symbol的属性名,对于每个不同的属性,语句都会被执行
let obj1 = {
a:"A",
b:"B",
c:"C"
}
for(let ch in obj1){
console.log(ch); a b c
}
这个方法遍历字符串的话
let str = “abcdefj”
- 2.Object.keys() --返回一个由一个给定对象的自身可枚举属性名组成的数组,数组中属性名的排列顺序和使用for…in循环遍历该对象时返(区别在于 for-in 循环枚举原型链中的属性)回的顺序一致
let obj1 = {
a:"A",
b:"B",
c:"C"
}
console.log(Object.keys(obj1)); //(3) ['a', 'b', 'c']
这个方法遍历字符串的话
let str = “abcdefj”
- 3