插个小广告~
字节跳动前端开发工程师-番茄小说内推,校招、社招、实习均可。
欢迎加我q:2679330388,欢迎来撩~
文章目录
-
-
-
- 说一下JS的基本数据类型
- null 和 undefined 的区别?
- 介绍一下JavaScript 原型、原型链?原型链有什么特点?_
- Array 构造函数只有一个参数值时的表现?
- 说一说其他值到字符串的转换规则?toString
- 如何把对象转换成字符串/字符串和对象的相互转换。
- 其他值到布尔类型的值的转换规则?
- 其他值到数字值的转换规则?
- 相等操作符 == 比较规则
- {} 和 [] 的 valueOf 和 toString 的结果是什么?
- 判断数据类型的方法
- 判断一个变量是否为数组
- Object.prototype.toString的原理
- typeof null输出什么
- typeof NaN 的结果是什么?
- typeof的原理
- instanceof的原理
- 0.1 + 0.2 等于多少
- 我想0.1+0.2 精确的等于0.3怎么办
- 小数如何取整,或保留几位小数
- JavaScript 什么是闭包?
- 闭包的好处
- 闭包的应用场景
- !!!节流、防抖了解吗?写一下节流防抖
- Symbol类型是做什么的?
- Symbol的具体用法
- Symbol和Symbol.for的区别
- !!!列举ES6的新特性并说一下如何使用
- new发生了什么
- 什么是回调地域
- 实现一下Promise/Promise的原理
- call() 、apply() 和bind()的区别?
- 说一下this的指向
- 事件循环 Event loop
- 手写call 、apply 、bind方法
- 深拷贝和浅拷贝
- 实现浅拷贝
- 实现深拷贝
- WeakMap和Map的区别,及其应用场景
- WeakSet和Set的区别,及其应用场景
- Map与Set的区别
- Set的方法
- Map的方法
- 数组扁平化
- 实现数组拍平flat函数
- 介绍一下遍历方法
- map和foreach有什么区别
- 怎么用栈去实现队列
- attribute和property的区别
- async 和 defer 的作用是什么?有什么区别?(浏览器解析过程)
- 使用async/defer后的js脚本会阻塞文档的解析吗?
- Css会阻塞dom解析吗 为什么会阻塞渲染
- css加载会阻塞js运行吗?
- 调试JS的工具
- promise.all 和 promise.race的区别
- promise.all是并行的,怎么封装promise做串行处理
- 封装一个异步类,实现只能有两个Promise在执行,该如何实现?/限制promise的并发数/ JS 请求调度器
- 不用循环,实现abc *5的字符串的一个连接。
- 说一下Array的内置的API
- 说一下字符串的内置的API
- 事件流
- 介绍一下事件冒泡和捕获
- 事件代理/委托
- 事件代理/委托有什么作用,主要用于哪些场景
- 如何阻止冒泡
- 如何阻止默认事件
- 触发事件的方法
- 说一下鼠标事件和键盘事件有哪些?
- 对作用域的理解
- 对作用域链的理解(变量的一个搜索过程)
- js怎么实现继承,优缺点
- 写代码,输出0-4,每隔一秒输一个
- 手写数组的map函数
- 手写数组的reduce函数
- js是单线程的,为什么js能有异步任务?
- 如何查找一个对象数组
- Promise解决了什么问题?存在什么问题和优化?是最终解决方案吗?
- async函数
- async 和 await原理。
- Promise,async awit的区别
- Typescript 和 JavaScript的区别是什么
- require 和 import 引入依赖的区别
- 函数柯里化
- 如果要实现一个加法函数,但是不知道传进来的参数有多少,你会怎么做?
- 正则表达式
- 实现一个红绿灯系统,红色2s,黄灯1s,绿灯3s,promise,循环
- 数组去重的方法
- BOM 和 DOM的区别
- 引入脚本的方式有哪些
- DOMcontentload 和 load的区别
- 介绍一下懒加载和预加载。图片懒加载和图片预加载的区别?分别在什么场景下使用?
- 为什么使用懒加载
- 懒加载的原理
- 为什么使用预加载
- 实现预加载的方法
- 预加载的应用场景
- JS垃圾回收机制说一下
- 如果页面卡顿,你觉得可能是什么原因造成的?有什么办法锁定原因并解决吗?
- 请描述一下 cookies,sessionStorage 和 localStorage 的区别
- 介绍一下你了解的设计模式
- 页面性能优化
- 首屏渲染优化方式
- 介绍一下预加载的原理
- 实现div拖动效果
- js和其他语言的区别
- 为什么 Js 要设计成弱类型语言
- 为什么js是单线程但是有settimout
- JS中的数组与其他语言的数组的区别
- 红宝书的目录结构说说
- 对移动端开发有什么了解
- 前端设计组件的原则
- JS 的 sort() 是怎么实现的
- 对象去重
- 根据对象的id去重
- 手写一下发布-订阅模式
- 既然React/Vue可以用Event Bus进行组件通信,你可以实现下吗?
- 介绍一下AST
- 两个 tab 的页面之间怎么通信?
- 如何获取嵌套对象所有的Keys
-
-
说一下JS的基本数据类型
JavaScript的数据类型分为俩种,一种是基本数据类型,一种是引用数据类型
1.基本数据类型
js 一共有六种基本数据类型,分别是 Undefined、Null、Boolean、Number、String,还有在 ES6 中新增的 Symbol 类型。
Symbol 代表创建后独一无二且不可变的数据类型,它的出现我认为主要是为了解决可能出现的全局变量冲突的问题。
2.引用数据类型
引用数据类型统称为 Object 对象,主要包括对象、数组、函数、日期和正则等等。
- Symbol类型是做什么的?
null 和 undefined 的区别?
undefined 代表的含义是未定义,null 代表的含义是空对象。一般变量声明了但还没有定义的时候会返回 undefined,null主要用于赋值给一些可能会返回对象的变量,作为初始化。
当我们使用双等号对两种类型的值进行比较时会返回 true,使用三个等号时会返回 false。
介绍一下JavaScript 原型、原型链?原型链有什么特点?_
**构造函数原型:**每一个构造函数的内部都有一个 prototype 属性,这个属性时一个指针,指向另一个对象,这个对象包含了可以由该构造函数的所有实例共享的属性和方法。
**对象原型:**当我们使用构造函数新建一个对象后,在这个对象的内部将包含一个指针,这个指针指向构造函数的 prototype 属性对应的值,这个指针称为对象的原型。
原型链
当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。原型链的尽头一般来说都是 Object.prototype,然后Object.prototype.__proto _ _为null。
Array 构造函数只有一个参数值时的表现?
Array 构造函数只带一个数字参数的时候,该参数会被作为数组的预设长度这样创建出来的只是一个空数组,只不过它的 length 属性被设置成了指定的值。
说一说其他值到字符串的转换规则?toString
- null 和 undefined 类型 ,null 转换为 “null”,undefined 转换为 “undefined”,
- Boolean 类型,true 转换为 “true”,false 转换为 “false”。
- Number 类型的值直接转换,不过那些极小和极大的数字会使用指数形式。
- Symbol 类型的值直接转换,但是只允许显式强制类型转换,使用隐式强制类型转换会产生错误。
- 对象,会调用Object.prototype.toString()来返回内部属性 [[Class]] 的值,如"[object Object]"。
如何把对象转换成字符串/字符串和对象的相互转换。
对象转字符串 JSON.stringify(obj)
字符串转对象或数组 JSON.parse(str)
其他值到布尔类型的值的转换规则?
利用Boolean对象进行转换
以下这些是假值:
- undefined
- null
- 0和 NaN
- “”
假值的布尔强制类型转换结果为 false。从逻辑上说,假值列表以外的都应该是真值。
其他值到数字值的转换规则?
Number()函数的转换规则
-
null,返回 0。
-
undefined,返回 NaN。
-
布尔值,true 转换为 1,false 转换为 0。
-
数值,直接返回。
-
字符串:
- 只有数字,直接转
-
空字符串,0
- 其他情况,则返回 NaN。
-
对象,调用 valueOf()方法,并按照上述规则转换返回的值。
相等操作符 == 比较规则
1、两个简单数据类型,类型不同,转数字比较。
2、一个简单、一个复杂,复杂转简单后比较。
3、两个复杂,比地址。
{} 和 [] 的 valueOf 和 toString 的结果是什么?
valueOf()方法会将对象转换为基本类型,如果无法转换为基本类型,则返回原对象。
toString返回当前对象的字符串形式。
{} 的 valueOf 结果为 {} ,toString 的结果为 "[object Object]"
[] 的 valueOf 结果为 [] ,toString 的结果为 ""
判断数据类型的方法
基本类型判断
在 JavaScript 里 使用 typeof 来判断数据类型,只能区分基本类型,即 “ number ” , “ string ” , “ undefined ” , “ boolean ” , “ object ” ,"function"六种。
typeof ''; // string 有效
typeof 1; // number 有效
typeof true; // boolean 有效
typeof undefined; // undefined 有效
typeof null; // object 无效
typeof [] ; // object 无效
typeof new Function(); // function 有效
typeof new Date(); // object 无效
typeof new RegExp(); // object 无效
引用类型判断
区别对象、数组、函数可以使用Object.prototype.toString.call 方法。判断某个对象值属于哪种内置类型。
console.log(Object.prototype.toString.call(123)) // [object Number]
console.log(Object.prototype.toString.call('123')) // [object String]
console.log(Object.prototype.toString.call(undefined)) // [object Undefined]
console.log(Object.prototype.toString.call(true)) // [object Boolean]
console.log(Object.prototype.toString.call({})) // [object Object]
console.log(Object.prototype.toString.call([])) // [object Array]
console.log(Object.prototype.toString.call(function(){})) // [object Function]
console.log(Object.prototype.toString.call(this)); // [object Window]
对象类型判断
instanceof
运算符也常常用来判断对象类型。用法: 左边的运算数是一个object
,右边运算数是对象类的名字或者构造函数; 返回true
或false
。
[] instanceof Array; // true
[] instanceof Object; // true
[] instanceof RegExp; // false
new Date instanceof Date; // true
判断一个变量是否为数组
Array.isArray
Object.prototype.toString.call()
x instanceof Array
Object.prototype.toString的原理
在 Object.prototype.toString 方法被调用时,他会找this对象的[[Class]]属性的值,将这个值与object字符串拼接并返回。
[[Class]]是一个内部属性,所有的对象都拥有该属性。在规范中,[[Class]]的值是一个字符串值,表明了该对象的类型。
typeof null输出什么
输出“object",为什么?
因为不同的对象在底层都表示为二进制,在Javascript中二进制前三位都为0的话会被判断为Object类型,null的二进制表示全为0,自然前三位也是0,所以执行typeof时会返回"object"。
typeof NaN 的结果是什么?
typeof NaN; // “number”
NaN 意指“不是一个数字”(not a number),用于指出数字类型中的错误情况。
NaN != NaN为 true。 NaN==NaN为false
typeof的原理
typeof
原理:不同的对象在底层都表示为二进制,在Javascript中二进制低三位存储其类型信息。
- 000: 对象
- 001: 整数
- 010: 浮点数
- 100:字符串
- 110: 布尔
instanceof的原理
Instanceof 是通过原型链去查找,找到某个对象的原型对象,使用原型对象的constructor找到构造函数,看看构造函数与Instanceof后面的是否相同,不相同,继续向上查找,直到尽头,找到为True,没找到为false。
0.1 + 0.2 等于多少
0.3000000000000004。不会精确等于0.3。
首先,十进制的0.1和0.2会被转换成二进制的,二进制浮点数表示法并不能精确的表示类似0.1这样的数值,因为浮点数在转化为二进制时,会出现无限循环
0.1 -> 0.0001 1001 1001 1001...(1100循环)
0.2 -> 0.0011 0011 0011 0011...(0011循环)
两者相加之后得到二进制为再转换为十进制,会产生误差。
我想0.1+0.2 精确的等于0.3怎么办
num.toFixed(小数点位数)
先10相加 再除10
小数如何取整,或保留几位小数
可以使用toFixed方法,可把 Number 四舍五入为指定小数位数的数字。
var num = 5.56789;
var n=num.toFixed(2);
输出:
5.57
JavaScript 什么是闭包
闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,创建的函数可以访问到当前函数的局部变量。
- 闭包的用途
- 闭包的应用场景
闭包的好处
闭包有两个常用的用途。
1.可以让我们函数外部能够访问到函数内部的变量。
2.闭包函数保留了使用的变量对象的引用,保证变量对象不会被回收。
闭包有很多好处,如果我们过多的使用,就会导致大量的变量都被保存在内存中,内存消耗很大,造成网页的性能问题,且容易造成内存泄漏。解决方法是在退出函数之前,将不使用的局部变量全部删除。(至为null这样)
// 解除引用避免内存泄露
function closure(){
var div = document.getElementById('div');
var test = div.innerHTML;
div.onclick = function () {
console.log(test);
};
div = null;
}
闭包的应用场景
- 构造函数的私有属性
- 函数节流、防抖
私有属性
在函数中使用var来创建变量,这时候在函数外部就无法获取到这个变量,我们可以在函数内部提供一个特权方法来访问这个变量。
function Person(param) {
var name = param.name; // 私有属性
this.age = 18; // 共有属性
this.sayName = function () {
console.log(name);
}
}
const tom = new Person({name: 'tom'});
tom.age += 1; // 共有属性,外部可以更改
tom.sayName(); // tom
tom.name = 'jerry';// 私有属性,外部不可获取、更改
tom.sayName(); // tom
!!!节流、防抖了解吗?写一下节流防抖
函数节流
节流是指在一段时间内只允许函数执行一次。我们可以使用定时器实现节流。
函数节流会用在比input, keyup更频繁触发的事件中,如resize, touchmove, mousemove, scroll。throttle 会强制函数以固定的速率执行
// 节流
var throttle = function(func, delay){
var timer = null;
return function(){
var context = this;
var args = arguments;
if(!timer){
timer = setTimeout(function(){
func.apply(context, args);
timer = null;
},delay);
}
}
}
防抖
防抖的作用是,一个事件回调函数在一段时间后才执行,如果在这段时间内再次调用则重新计时。
实际应用场景: 搜索框,如果用户不断输入,通过防抖节约请求资源。
一般我是使用lodash的decounce进行防抖。
debounce(方法,时间)
在项目我开发一个备注搜索的时候,就是使用了防抖,避免频繁的发起请求。
原理:内部维护一个计时器timer,返回一个函数,在这个函数里清除计时器并重新计时,计时结束后执行fn函数。
// 防抖
function debounce(fn, delay){
// 维护一个 timer
let timer = null;
return function() {
// 获取函数的作用域和变量
let context = this;
let args = arguments;
clearTimeout(timer);// 清除重新计时
timer = setTimeout(function(){
fn.apply(context, args);
}, delay)
}
}
Symbol类型是做什么的?
Symbol
是 ES6
新推出的一种基本类型,它表示独一无二的值。它最大的用途就是用来定义对象唯一的属性名,就能保证不会出现同名的属性,还能防止某一个属性被不小心覆盖。
Symbol的具体用法
通过Symbol()方法可以生成一个symbol,里面可以带参数,也可以不带参数
Symbol 类型的注意点
- Symbol 函数前不能使用 new 命令,否则会报错。
- Symbol 函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
- Symbol值不能与其他类型值运算,不能转数值;可以转字符串和布尔值
- 不能用
.
运算符,要用方括号 - Symbol 作为属性名时,该属性不会出现在 for…in、for…of 循环中,也不会被 Object.keys() 返回。
- Object.getOwnPropertySymbols 方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
- Symbol.for 接受一个字符串作为参数,首先在全局中搜索有没有以该参数为名称的Symbol值。如果有,就返回这个 Symbol 值,否则就新建并返回一个以该字符串为名称的 Symbol 值。
Symbol和Symbol.for的区别
Symbol.for()
与Symbol()
这两种写法,都会生成新的 Symbol。它们的区别是,前者会被登记在全局环境中供搜索,后者不会。Symbol.for()
不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key
是否已经存在,如果不存在才会新建一个值。