JS面试题
1.1 JS数据类型
基本数据类型
:string number boolean undefined null symbol引用数据类型
:Object
1.2 检测数据类型的方法
Object.prototype.toString.call()
:准确的检测是什么数据类型typeof
:能区分基本数据类型,不能区分 array object 这种引用数据类型instanceof
: 比如 a instanceof b,准确的说是用来检测 a 是不是 b 的实例对象(查找原型)
1.3 判断数组的方式有哪些
Array.isArray
(ES6的)Object.prototype.toString.call
最准确的- 通过原型链去判断
1.4 null 和 undefined 的理解
- null 和 undefined 都是基本数据类型
- null可以理解为
空对象
- (实际项目里面可以定义一个空对象 const a = null),
- undefined可以理解为
未定义
- (实际项目里面直接使用一个未定义的变量报错:console.log(a.play()),但是 a 没定义,就会报错
- typeof null 会得到
object
,因为 null 和 object 的二进制开头一样
1.5 instanceof 的实现原理
其实就是去遍历原型链
// a 是实力对象,b是某个函数
const myInstanceof(a, b) {
let A = a.__proto__ // 隐式原型
let B = b.prototype // 显式原型
//遍历原型链查找
while(1) {
// object.prototype.__proto__ === null
if (A === Null) {
return false
}
if (A === B) {
return true
}
A = A.__proto__
}
}
1.6 == 操作符的强制类型转换规则是什么
- 1.判断是不是
相同类型
,如果不是,进行类型转换 - 2.转换规则
- 如果是
null
和undefined
比较,return true - 如果是
string
和number
比较,string ----> number 再比较 - 如果有一方是
boolean
,会把 boolean ---> number 再比较 - 如果一方是
object
,一方是string number symbol
,会把 object 转 原始类型"[object Object]"
再比较
- 如果是
1.7 JS的包装类型
JS 的基本数据类型是没有属性和方法的,但是为了方便使用,在调用基本数据类型的属性和方法时,JS会对基本数据类型自动做一层包装
const a = 'abc' //string 没有属性和方法
// 但是可以调用属性
// JS的操作是 String('abc')
console.log(a.length) // 3
1.8 this的指向问题
分为5种情况
指向window
:函数 a 不是对象身上的方法时, 调用 a(),此时 this 指向 window
// a 是某个全局函数
const a = () => {
console.log(this); //指向 window
}
a() // window
指向对象
:函数 a 是 A 对象身上的方法时,调用 a(),此时 this 指向对象 A\
const A = {
a: function() {
console.log(this);
}
}
A.a() //指向 A,即 {a: f}
call(x, args) apply(x, [args]) bind(x, args或者[args])
:this 指向 x
function a() {
console.log(this.play())
}
const b = {
play: function() {
console.log('111')
}
}
a.call(b) // 111
new
: const b = new B(),this 指向 b (不多说)箭头函数的this
:指向当前这个箭头函数所处上下文中的那个 this
// 处在全局执行上下文中,this就继承全局执行上下文的 this,即 window
const a = () => {
console.log(this)
}
a() // window
// 处在某个对象的方法中
const b = {
play: () => {
console.log(this)
}
}
b.play() // 箭头函数处在对象b的环境里,b是处在全局部执行上下文,所以 this 指向 window
1.9 JSON的理解
不说多的,就一个,一种数据交换的格式
,实际项目中常见于前后端传参取值
JSON.stringify
:将传入的某种数据格式转换为一个 JSON 字符串。如果传入的数据结构不符合 JSON 格式,那么在序列化的时候会对这些值进行对应的特殊处理,使其符合规范JSON.parse()
:这个函数用来将 JSON 格式的字符串转换为一个 js 数据结构。如果传入的字符串不是标准的 JSON 格式,将会抛出错误
1.10 let、const、var的区别
不需要说很多,了解即可
- var 可以先用再定义,但是 let const 不能
- let var 可以重新赋值,const 不行
- let const 是块级作用域,var 是全局作用域
1.11 new 的实现原理
- 创建一个空对象 obj
- 空对象的原型指向构造函数的显示原型
Object.setPrototypeOf(obj, constructor.prototype)
- 执行构造函数(拿到结果
result
),且构造函数的 this 指向 这个空对象, - 判断
result 类型
,如果 result 是对象,则返回 result,否则返回 obj
function myNew(constructor, ...args) {
// 创建空对象
let obj = {}
// 空对象的原型指向构造函数的显示原型
Object.setPrototypeOf(obj, constructor.prototype)
// 构造函数的 this 指向空对象,执行构造函数
const result = constructor.apply(obj, args)
// 如果 result 是对象,则返回 result,否则返回 obj
return result instanceof Object ? result : obj;
}
1.12 原型与原型链
原型:
- 每个实例对象都有一个隐士原型
__proto__
- 每个函数都有一个显示原型
prototype
原型链:
- 实力对象的隐士原型指向构造函数的显示原型
a.__proto__ === A.prototype
- 而构造函数的显示原型也是个对象,同理也指向它的原型对象
需要注意的是:
构造函数原型对象的 constructor 指向构造函数本身
,也就是:A.prototype.constructor === A
原型链的终点:Object.prototype.proto ---> Null
1.13 作用域与作用域链
作用域分为两类:
- 全局作用域:在
任意区域
都能访问到 - 局部作用域:在
固定区域
才能访问
作用域链:
- 其实就是
作用域的集合
function father() {
let result = 2
function child () {
console.log(result)
}
child()
}
father()
比如上面的例子中,child 处于局部作用域,它要访问 result 变量,那么它访问的过程是:
- child里面有没有变量 result,如果没有,向上找
- father里面有没有变量 result,如果没有,想上找(例子这里找到了,就输出 2)
- 全局里面找有没有变量 result,如果没有,输出 undefined,如果有,则输出对应值
前端JavaScript面试题323道