1、JavaScript有哪些数据类型,它们的区别?

可以分为堆和栈

2、数据类型检测的方式有哪些

2 instanceof Number
true instanceof Boolean
(2).constructor === Number
(true).constructor === Boolean
var a = Object.prototype.toString;

console.log(a.call(2));

3、 判断数组的方式有哪些

Object.prototype.toString.call(obj).slice(8, -1) === "Array"

Array.isArray(obj)

obj.__proto__ === Array.prototype

obj instanceof Array

Array.prototype.isPrototypeOf(obj)

4、 null和undefined区别

5、typeof null 的结果是什么,为什么?

object,前三个低位(其实是就是后3位)为000会被判断为obj,所以null全是0,所以就是obj

6. intanceof 操作符的实现原理及实现

递归、proto、prototype。
instanceof会递归L的__proto__原型链,查看是否存在右侧的prototype原型。

function myInstanceOf(left, right){
	if(typeof left !== 'object' || left === null || typeof right !== "function"){
		return false;
	}

	let proto = Object.getPrototypeOf(left)
	let prototype = right.prototype
	while(true){
		if(!proto) return false;
		if(proto===prototype) return true;
		proto = Object.getPrototyoeOf(proto)
	}
}

7. 为什么0.1+0.2 ! == 0.3,如何让其相等

js的小数位是2的53次方,一共是52+符号为。一共是53位,而0.1和0.2的二进制是无限循环的小数,所以在进制转换过程中精度损失了,在计算的过程中对介运算也精度损失了,所以精度损失可能出现在进制转换和对阶运算过程中。
怎么解决

function add(num1, num2){
	const num1Digits = (num1.toString().split(".")[1] || "").length;
	const num2Digits = (num2.toString().split(".")[1] || "").length;
	const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits));
	return (num1 * baseNUm + num2 * baseNum) / baseNum;
}
function numberepsilon(arg1, arg2){
	return Math.abs(arg1 - arg2) < Number.EPSILON;
}
console.log(numberepsilon(0.1 + 0.2, 0.3));

8. typeof NaN 的结果是什么?

Number

9. isNaN 和 Number.isNaN 函数的区别?

函数isNan接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的都会返回true,因此非数字值传入也会返回true,会影响Nan的判断。
函数Number.isNan会首先判断传入参数是否为数字,如果是数字再继续判断是否为NaN,不会进行数据类型的转换,这种方法对于NaN的判断更为准确。

10. == 操作符的强制类型转换规则?

==在进行对比时,也会先进行类型转换。

判断流程:

11. 其他值到字符串的转换规则?

类型 字符串转换
null null
undefined undefined
true true
false false
number 极大极大会用指数形式
symbol 显式类型转换

12. 其他值到数字值的转换规则?

类型 转换为
Undefined NaN
Null 0
Boolean true1,false0
String 包含非数字值,NaN。空字符串0
Symbol 报错
对象 转换为基本类型,根据以上规则转换

13. 其他值到布尔类型的值的转换规则?

14. Object.is() 与比较操作符 ===,== 的区别?

15. JavaScript 中如何进行隐式类型转换?

js中隐式类型转换是指在某些操作中,js会自动将一个数据类型转换为另一个数据类型,以完成表达式的计算或操作。

16. let、const、var的区别

特性 let const var
作用域 块级作用域 块级作用域 函数级作用域
重新赋值 不可
初始化 在使用前 在使用权 自动初始化为undefined
提升 不提升 不提升 提升到函数或全局作用域的顶部
暂时性死区TDZ 如果在初始化之前访问,抛出referenceError 如果在初始化之前访问,抛出referenceError 可以访问,是undefined
重新声明 不可 不可

17. const对象的属性可以修改吗

不可以,但是引用类型可以,因为引用类型指向的是指针,包括对象和数组

18. 如果new一个箭头函数的会怎么样

不能new,因为箭头函数没有prototype,也没有this,也没有arguments,所以不能new

19. 箭头函数与普通函数的区别

20. 箭头函数的this指向哪⾥?

捕获上下文的this

21. Proxy 可以实现什么功能?

proxy可以自定义对象中的操作

22. 对 rest 参数的理解

扩展运算符被用在函数形参上,可以把分离的参数整合成一个数组:

function mutiple(...args){
	console.log(args)
}
mutiple(1, 2, 3, 4) // [1, 2, 3, 4]

23. ES6中模板语法与字符串处理

模板语法

my name is ${name}

字符串方法:

24. new操作符的实现原理

function Person(name, age){
	this.name = name;
	this.name = age;
}

var person1 = new Person("Alice", 30);

var person2 = Object.create(Person.prototype)l
Person.call(person2, "Bob", 25);

25. map和Object的区别

比较类型 Object Map
存储键值对的方式 键是字符串或符号,值可以是任意类型字符 键值对都可以任意类型
键的顺序 无需 有序
键 的数量 Object.keys(),Object.entries() size()
迭代 for in , Object.keys(),Object.values(), Object.entries() Map.prototype.keys(), Map.prototype.values(), Map.prototype.entries()
键的比较 是基于字符串的比较 使用严格相等运算符

26、map和weakMap的区别

比较类型 Map WeakMap
类型 任意数据类型,包括原始类型和对象 只能是对象
引用计数 不影响键的引用计数 不会阻止键被垃圾回收
键的可枚举类型 可枚举 不可枚举
遍历顺序 有序 无序
回收机制 不会影响键的垃圾回收 键是弱引用,不会阻止键被回收
内存泄露 可能会导致内存泄露 不会导致
使用场景 键值对的存储 私有数据存储

27. JavaScript脚本延迟加载的方式有哪些?

28. JavaScript 类数组对象的定义?

一个拥有length属性和若干索引属性的对象就可以被称为类数组对象,类数组对象和数组类似,但是不能调用数组的方法。厂家的类数组对象有arguments和DOM方法的返回结果,还有一个函数也可以看作是类数组对象,因为它含有length属性值,代表可以接收的参数个数。

Array.prototype.slice.call(arrayLike);
Array.prototype.splice.call(arrayLike, 0)
Array.prototype.concat.apply([], arrayLike)

29. 为什么函数的 arguments 参数是类数组而不是数组?如何遍历类数组?

30. 什么是 DOM 和 BOM?

31. 对类数组对象的理解,如何转化为数组

splice.call() slice.call() concat.apply()

32. 对AJAX的理解,实现一个AJAX请求

ajax是asynchronous javascript and xml的缩写,指的是通过js的异步通信,从服务器获取xml文档中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。

步骤:

const server_url = "/server";
let xhr = new XMLHttpRequest();
xhr.open("GET", url, true);

xhr.onreadystatechange = function(){
	if(this.readyState !== 4) return;
	if(this.status === 200){
		handle(this.response);
	} else{
		console.error(this.statusText);
	}
}
xhr.onerror = function(){
	console.error(this.statusText);
}
xhr.responseType = "json";

xhr.setRequestHeader("Accept", "application/json")
xhr.send(null)

使用promise封装ajax

function getJSON(url){
	let promise = new Promise(function(resolve, reject){
		let xhr = new XMLHttpRequest();
		xhr.open("GET", url, true);
		xhr.onreadystatechange = function(){
			if(this.readyState !== 4) return;
			if(this.status === 200) = function(){
				resolve(this.response);
			}else{
				reject(new Error(this.statusText))
			}
		}
	})
	return promise;
}

33.JavaScript为什么要进行变量提升,它导致了什么问题?

34.ES6模块与CommonJS模块有什么异同?

特性 es6模块 commonjs模块
语法 使用import和export 使用require()和module.exports
加载时机 编译时加载 运行时加载
作用域 每个模块都有自己的作用域 变量添加到模块的闭包中
循环依赖处理 可以自然处理循环依赖 可能出现问题,需要特殊处理
静态导入和到处 必须位于最顶层 可以在运行时根据条件导入或导出
默认到处和命名导出 支持 不支持
静态分析
编译时优化

35.常见的DOM操作有哪些

//获取
getElementById
getElementByTagName
getElementByClassName
querySelectorAll //按照css

36.for...in和for...of的区别

37.如何使用for...of遍历对象

for(var k of obj){
	console.log(k)
}
obj[Symbol.iterator] = function(){
	var keys = Object.keys(this);
	var count = 0;
	return {
		
	}
}

38.ajax、axios、fetch的区别

特性 ajax axios fetch
语法 原生js或使用库 promise-based api promise-based api
浏览器支持 手动处理兼容性 支持主流浏览器 部分浏览器支持
http方法 get、post、put、delete等
数据格式 接发json、xml、html、文本 默认json
请求取消 手动实现 内置 手动实现
拦截器 不支持 支持请求响应拦截器 不支持
csrf保护 手动处理 内置支持 手动处理
并发 不支持 支持 支持

39.数组的遍历方法有哪些

40.forEach和map方法有什么区别

41.对原型、原型链的理解

每个元素都有一个prototype属性,它指向另一个对象或null。当访问一个对象的属性和方法时,如果这个对象没有,就会顺着原型链向上查找,直到找到这个属性或者方法为止。

42.原型修改、重写

function Person(name){
	this.name = name;
}
Person.prototype.getName = function(){}
var p = new Person("hello")
console.log(p.__proto__ === Person.prototype)
console.log(p.__proto__ === p.constructor.prototype)

Person.prototype = {
	getName: function(){}
}

var p = new Person("hello")
console.log(p.__proto__ === Person.prototype) //true
console.log(p.__proto__ === p.constructor.prototype) //false

Person.prototype = {
	getName: function(){}
}

var p = new Person("hello")
p.constructor = Person
console.log(p.__proto__ === Person.prototype)
console.log(p.__proto__ === p.constructor.prototype)

43.原型链指向

p.__proto__  // Person.prototype
Person.prototype.__proto__  // Object.prototype
p.__proto__.__proto__ //Object.prototype
p.__proto__.constructor.prototype.__proto__ // Object.prototype
Person.prototype.constructor.prototype.__proto__ // Object.prototype
p1.__proto__.constructor // Person
Person.prototype.constructor  // Person

44.原型链的终点是什么?如何打印出原型链的终点?

// null

console.log(Object.prototype.__proto__)

45.如何获得对象非原型链上的属性?

用hasOwnProperity()方法

46.对闭包的理解

闭包实现了外部访问函数内部变量的功能,让这些变量的值始终可以保存在内存当中。

var a = 1;
function foo(){
	var a = 2;
	function baz(){
		console.log(a);
	}
	bar(baz)
}
function bar(fn){
	fn();
}
foo();  //输出2而不是1

47.对作用域、作用域链的理解

48.对执行上下文的理解

49.对this对象的理解

this是执行上下文的一个属性,它指向最后一次调用这个方法的对象。在实际开发中,this的指向可以通过4种调用模式来判断。

50.call() 和 apply() 的区别?

作用一样,区别在于传入参数不同

51.实现call、apply 及 bind 函数

//call
/**
- 判断调用的对象是不是一个函数,即使是定义在函数原型上的,也有可能出现使用call等方式调用的情况
- 截取除第一个外的剩余参数,并判断context上下文对象是否存在,不存在则设置window
- 将函数作为上下文对象的一个方法,添加在上下文对象上
- 调用该上下文对象的方法,并把参数传进去
- 删除该上下文的对象方法属性
- 返回调用结果
*/
Function.prototype.myCall = function (ctx, ...args){
	if(typeof this !== "function") return
	ctx = ctx || window
	const fn = Symbol()
	ctx[fn] = this
	const result = ctx[fn](...args)
	delete ctx[fn]
	return result
}

//apply
/**
- 判断调用对象是不是一个函数,即使定义在原型 
*/
Function.prototype.myApply = function(ctx, args){
	if(typeof this !== "function") return
	ctx = ctx || window
	const fn = Symbol()
	ctx[fn] = this
	const result = ctx[fn](...args)
	delete ctx[fn]
	return result
}

//bind
Function.prototype.myBind = function(ctx, ...args1){
	if(typeof this !== "function") return
	const fn = this
	return function(...args2){
		const allArgs = [...args1, ...args2]
		if(new.target){
			return new fn(...allArgs)
		}else{
			return fn.apply(ctx, allArgs)
		}
	}
}

52.异步编程的实现方式?

53.setTimeout、Promise、Async/Await 的区别

54.对Promise的理解

Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作消息,避免了回调地狱。

55.Promise的基本用法

操作成功返回resolve,操作失败返回reject,

56.Promise解决了什么问题

回调地狱

// 之前
let fs = require('fs')
fs.readFile('./a.txt','utf8',function(err,data){
  fs.readFile(data,'utf8',function(err,data){
    fs.readFile(data,'utf8',function(err,data){
      console.log(data)
    })
  })
})

//之后
let fs = require('fs')
function read(url){
  return new Promise((resolve,reject)=>{
    fs.readFile(url,'utf8',function(error,data){
      error && reject(error)
      resolve(data)
    })
  })
}
read('./a.txt').then(data=>{
  return read(data)
}).then(data=>{
  return read(data)
}).then(data=>{
  console.log(data)
})

57.Promise.all和Promise.race的区别的使用场景

59.await 到底在等啥?

等待一个async的返回值

60.async/await的优势

61.async/await对比Promise的优势

62.async/await 如何捕获异常

try,catch

63.什么是回调函数?回调函数有什么缺点?如何解决回调地狱问题?

返回一个函数,容易写出回调地狱。

解决方法:

64.setTimeout、setInterval、requestAnimationFrame 各有什么特点?

65.对象创建的方式有哪些?

function createPerson(name){
 var o = new Object();
 o.name = name;
 o.getName = function(){
	 //...
 }
 return o;
}
function Person(name){
	this.name = name;
	this.getName = function(){
		//...
	}
}
var person1 = new Person("kjk")
function Person(name){
	Person.prototype.name = 'k';
	Person.prototype.getName = function(){
		console.log(this.name);
	}
	var person1 = new Person();
}
function Person(name){
	this.name = name;
}
Person.prototype = {
	constructor: Person,
	getName: function(){
		console.log(this.name)
	}
}

var person1 = new Person();
function Person(name){
	this.name = name;
	if(typeof this.getName != "function"){
		Person.prototype.getName = function(){
			console.log("...")
		}
	}
}
var person2 = new Person();
function Person(name){
	var o = new Object();
	o.name = name;
	o.getName = function(){
		console.log(this.name)
	}
	return o;
}
var person1 = new Person("kkk");
console.log(person1 instanceof Person);
console.log(person2 instanceof Object);

66.对象继承的方式有哪些?

67.浏览器的垃圾回收机制

68.哪些情况会导致内存泄漏

69.请说一说this指向