目录
8.setTimeout() 与 setInterval() 的区别
13.ajax基本步骤以及readyState的五种状态 以及ajax的原理
22.Object.is() 与比较操作符 “===”、“==” 的区别?
27.为什么函数的 arguments 参数是伪数组而不是数组?如何遍历伪数组?
31.谈谈 script标签中 defer和 async属性的区别。
39.如何遍历一个对象(Object)的所有属性并在控制台输出它们的值?
1.== 和 ===区别,分别在什么情况使用
等于操作符
等于操作符用两个等于号( == )表示,如果操作数相等,则会返回
true
我们知道
JavaScript
中存在隐式转换。等于操作符(==)在比较中会先进行类型转换,再确定操作数是否相等
1. let result = (true == 1); // true
如果任一操作数是布尔值,则将其转换为数值再比较是否相等
2. let result = ("55" == 55); // true
如果一个操作数是字符串,另一个操作数是数值,则尝试将字符串转换为数值,再比较是否相等
3. let obj = {valueof:Function(){return 1}}
let result = (obj == 1); // true
如果一个操作数是对象,另一个操作数不是,则调用对象的 valueOf() 方法取得其原始值,再根据前面的规则进行比较
4. let result = (null == undefined ); // true
null 和undefined相等
5. let result = (NaN == NaN ); // false
null 和undefined相等
6. let obj1 = {name:"xxx"}
let obj2 = {name:"xxx"}
let result = (obj1 == obj2 ); // false
如果两个操作数都是对象,则比较它们是不是同一个对象。如果两个操作数都指向同一个对象,则相等操作符返回true
等于操作符总结:
两个都为简单类型,字符串和布尔值都会转换成数值,再比较
简单类型与引用类型比较,对象转化成其原始类型的值,再比较
两个都为引用类型,则比较它们是否指向同一个对象
null 和 undefined 相等
存在 NaN 则返回 false
全等操作符
全等操作符由 3 个等于号( === )表示,只有两个操作数在不转换的前提下相等才返回
true
。即类型相同,值也需相同
1. let result1 = ("55" === 55); // false,不相等,因为数据类型不同
let result2 = (55 === 55); // true,相等,因为数据类型相同值也相同
undefined 和 null 与自身严格相等
2. let result1 = (null === null) //true
let result2 = (undefined === undefined) //true
全等操作符总结:
全等运算符不会做类型转换
null
和undefined
比较,全等为false
全等操作符和等于操作符的区别
相等操作符(==)会做类型转换,再进行值的比较,全等运算符不会做类型转换
2. 判断数据类型的方法
1.typeOf 2.instanceof 3.object.prototype.toString.call 4.constructor
//1.typeOf
let obj={
name:'dawn',
age:21
}
let fn=function() {
console.log('我是 function 类型');
}
console.log(typeof 1); //number
console.log(typeof 'abc'); //string
console.log(typeof true); //boolean
console.log(typeof undefined); //undefined
console.log(typeof fn); //function
console.log(typeof (new Date) ); //object
console.log(typeof null); //object
console.log(typeof [1,2,3]); //object
console.log(typeof obj); //object
//由结果可知typeof可以测试出number、string、boolean、undefined及function。对于null及数组、对象,typeof均检测出为object,不能进一步判断它们的类型。
//2.instanceof
let arr=[1,2,3,4,5,6,7]
let obj={
name:'dawn',
age:21
}
let fn=function() {
console.log('我是 function 类型');
}
console.log(arr instanceof Array); //true
console.log(obj instanceof Object); //true
console.log(fn instanceof Function); //true
console.log((new Date) instanceof Date); //true
//obj instanceof Object ,可以左边放你要判断的内容,右边放类型来进行JS类型判断,只能用来判断复杂数据类型,因为instanceof 是用于检测构造函数(右边)的 prototype 属性是否出现在某个实例对象(左边)的原型链上。
//3.Object.prototype.toString.call
let obj = {
name: 'dawn',
age: 21
}
let fn = function () {
console.log('我是 function 类型');
}
console.log(Object.prototype.toString.call(1)); // [object Number]
console.log(Object.prototype.toString.call('Hello tomorrow')); // [object String ]
console.log(Object.prototype.toString.call(true)); // [object Boolean]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(fn)); // [object Function]
console.log(Object.prototype.toString.call(new Date)); // [object Date]
console.log(Object.prototype.toString.call(null)); // [object Null]
console.log(Object.prototype.toString.call([1, 2, 3])); // [object Array]
console.log(Object.prototype.toString.call(obj)); // [object Object]
//在任何值上调用 Object 原生的 toString() 方法,都会返回一个 [object NativeConstructorName] 格式的字符串。每个类在内部都有一个 [[Class]] 属性,这个属性中就指定了上述字符串中的构造函数名。
但是它不能检测非原生构造函数的构造函数名。
//4.constructor
let arr = [1, 2, 3, 4, 5, 6, 7]
let obj = {
name: 'dawn',
age: 21
}
let fn = function () {
console.log('我是 function 类型');
}
console.log((9).constructor === Number); //true
console.log('hello'.constructor === String); //true
console.log(true.constructor === Boolean); //true
console.log(fn.constructor === Function); //true
console.log((new Date).constructor === Date); //true
console.log(obj.constructor === Object); //true
console.log([1, 2, 3].constructor === Array); //true
//constructor不能判断undefined和null,并且使用它是不安全的,因为contructor的指向是可以改变的
3.说说JavaScript中的数据类型?存储上的差别?
JavaScript中的数据类型分为:
基本数据类型 :Number,String,Boolean,Undefined,Null,Symbol
复杂数据类型 : Object,Array,Function,Date,RegExp,...等
存储区别:
基本数据类型存储在栈中
引用类型的对象存储于堆中
//1.基本类型
let a = 10;
let b = a; // 赋值操作
b = 20;
console.log(a); // 10值
//a的值为一个基本类型,是存储在栈中,将a的值赋给b,虽然两个变量的值相等,但是两个变量保存了两个不同的内存地址
//2.引用类型
var obj1 = {}
var obj2 = obj1;
obj2.name = "Xxx";
console.log(obj1.name); // xxx
//引用类型数据存放在内对内中,每个堆内存中有一个引用地址,该引用地址存放在栈中obj1是一个引用类型,在赋值操作过程汇总,实际是将堆内存对象在栈内存的引用地址复制了一份给了obj2,实际上他们共同指向了同一个堆内存对象,所以更改obj2会对obj1产生影响
总结:
- 声明变量时不同的内存地址分配:
- 简单类型的值存放在栈中,在栈中存放的是对应的值
- 引用类型对应的值存储在堆中,在栈中存放的是指向堆内存的地址
- 不同的类型数据导致赋值变量时的不同:
- 简单类型赋值,是生成相同的值,两个对象对应不同的地址
- 复杂类型赋值,是将保存对象的内存地址赋值给另一个变量。也就是两个变量指向堆内存中同一个对象
4.JavaScript中的操作符
//1.递增递减操作符
//使用++、--两种符号表示递增和递减,同时根据符号位置的不同,又分为前置递增递减和后置递增递减:
var num1 = 10;
var n = ++num1; // 前置递增,先执行递增计算,再对n进行赋值,所以,n=11,num1=11
var num2 = 10;
var m = --num2; // 前置递减,先执行递减计算,再对m进行赋值,所以,m=9,num2=9
var x = num2++; // 后置递增,先赋值,再执行递增计算,所以,x=9,num2=10;
//2.一元加、一元减操作符
//+表示一元加操作符,-表示一元减操作符,这两种操作符放在数值前面,相当于属数学中的正负号。
var a = 10;
console.log(-a); // -10
console.log(+a); // 10
//3.布尔操作符
//布尔操作符有三个:与、或、非
//&& 逻辑与 两边都是true,才返回true,否则返回false
//|| 逻辑或 两边只要有一个是true,就返回true,否则返回false
//! 逻辑非 用来取一个布尔值相反的值
{} && false; // false
false && {}; // {}
{na:1} && {na:2}; // {na:2}
null && false; // null
NaN && false; // NaN
undefined && false; // undefined
{} || false; // {}
1 === 2 || false; // false
{n:1} || {n:2}; // {n:1}
null || null; // null
NaN || NaN; // NaN
undefined || undefined; // undefined
//在进行||、&&操作时,如果有一个操作数不是布尔值,返回结果也不一定是布尔值:
5.var,let,const
- var定义的变量,可以预解析提前调用的结果是undefined,let定义的变量不能预解析,提前调用的结果是 报错(ReferenceError)。const定义的变量不能预解析,提前调用的结果是 报错。
- var定义的变量,变量名称可以重复,效果是重复赋值,let定义的变量不能重复,否则执行报错。const定义的变量不能重复,否则执行报错。
- var定义的变量作用域是全局/局部作用域。let定义的变量如果在{}中只能在{}中调用。
- 在循环语句中var定义的循环变量和使用let定义的循环变量。执行原理和执行效果不同。
- const 定义的变量存储的数据数值不能改变,也就是const定义的变量,不能重复赋值。
//提前使用
console.log(a) //提前调用 预解析
console.log(b) //报错
var a = 1
let b = 2
//const与let 定义的变量不能重复
var init = 11
var init = 22
let init2 = 11
let init2 = 22
console.log(init) //22 var声明的变量被重新赋值
consoloe.log(init2) //会报错
//const与let 定义的变量如果在{}中那么只能在{}中来使用
if (true) {
var a = 300;
let b = 400;
const c = 500;
// let 声明的变量 在 { } 中可以调用
console.log(b);
console.log(c);
}
console.log(a); //300
// let和const 声明的变量 在 { } 外 不能调用
console.log(c); //报错
console.log(b); //报错
//const定义的变量 不能重复赋值
const aa = 100
aa = 200
console.log(aa) //报错
const a = {
name: 'zhang',
age: '18'
}
console.log(a.name)//zhang
a.name = 'zhen';
console.log(a.name)//zhen
const b = [1, 2, 3, 4, 5]
console.log(b[0])//1
b[0] = 0;
console.log(b[0])//0
//const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
考题
下面代码输入的是什么?
function sayHi() {
console.log(name);
console.log(age);
var name = "熊大";
let age = 18;
}
A: 熊大和
undefined
B: 熊大和ReferenceError
C:ReferenceError
和 18D:
undefined
和ReferenceError
答案是:D 怎么样是否真的理解了呢?
6.深拷贝与浅拷贝的区别以及实现方法
浅拷贝:
将原对象或原数组的引用直接赋给新对象,新数组,新对象只是对原对象的一个引用,而不复制对象本身,新旧对象还是共享同一块内存
如果属性是一个基本数据类型,拷贝就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址,
深拷贝:
创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”
深拷贝就是把一个对象,从内存中完整的拷贝出来,从堆内存中开辟了新区域,用来存新对象,并且修改新对象不会影响原对象
浅拷贝的方法:
直接对象赋值
Object.assign
深拷贝的方法:
JSON.stringify转为字符串再JSON.parse转对象
深度递归遍历
写一个递归(推荐,比较完美的解决方案)封装一个DeepClone的深拷贝函数
//浅拷贝
//1.直接对象赋值
let a = [0,1,2,3,4];
b = a;
console.log(a === b);
a[0] = 1;
console.log(a, b) // a=11234 b=11234
//2. 解构赋值
var obj1 = {a: 1, b: 2}
var obj2 = {...obj1}
obj2.a = 4
console.log(obj1, obj2) //obj1 = {a:1,b:2} obj2 = {a:4,b:2}
//3.Object.assign()
let obj1 = {
a: { b: 1},
c: 2
}
let obj2 = Object.assign({},obj1)
obj2.a.b = 3; //第二层,obj1变了,是浅拷贝
obj2.c = 3; //第一层,obj1不变,是深拷贝
console.log(obj1); //{a:{b:3},c:2}
console.log(obj2); //{a:{b:3},c:3}
//严格来说,Object.assign() 既不是深拷贝,也不是浅拷贝——而是第一级属性深拷贝,第一级以下的级别属性浅拷贝。
//深拷贝
//1.封装deepClone深拷贝的方法
function DeepClone(data) {
const newData = Array.isArray(data) ? [] : {}
for (let key in data) {
if (data[key] && typeof data[key] === 'object') {
newData[key] = DeepClone(data[key])
} else {
newData[key] = data[key]
}
}
return newData
}
//调用他
const obj2 = DeepClone(obj1)
//2.JSON.stringify转为字符串再JSON.parse
//JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象
//缺点:当值为undefined、function、symbol 会在转换过程中被忽略
//3.jquery 提供一个 $.extend 可以用来做深拷贝;
var obj = {a:{name:"kaiqin",age:19}};
var obj1 = {b:{name:"wang",age:19}};
var obj2 = $.extend(true,{},obj,obj1); //true为深拷贝,false为浅拷贝,默认为false
obj2.a.name="zhang";
console.log(obj2)
//{a: {name: "zhang", age: 19},b: {name: "wang", age: 19}}
console.log(obj)
//{{a:{name:"kaiqin",age:19}}}
7.防抖与节流
防抖:防抖就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。 可用于input.change实时输入校验和window.resize事件,比如窗口缩放完成后,才会重新计算部分
DOM
尺寸节流:所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。两种方式可以实现,分别是时间戳版和定时器版。用于监听
mousemove
、 鼠标滚动等事件,通常可用于:拖拽动画、下拉加载。
//防抖
//用定时器实现防抖
function debounce(fn, wait) {
let timout = null;
return function () {
clearTimeout(timout)
timout = setTimeout(fn, wait)
}
}
//节流
//定时器实现节流
function throttle(func, wait) {
var timer = null;
return function () {
var _this = this;
var args = arguments;
if (!timer) {
timer = setTimeout(function () {
timer = null;
func.apply(_this, args)
}, wait)
}
}
}
//时间戳实现节流
function throttle(func, wait) {
//定义初始时间
var oldTime = 0;
return function () {
var _this = this;
var args = arguments;
//当前时间戳
var newTime = +new Date();
//判断用当前时间减去旧的时间,如果大于wait指定的时间就会触发
if (newTime - oldTime > wait) {
//执行触发的函数
func.apply(_this, args)
//将旧时间更新
oldTime = newTime;
}
}
8.setTimeout() 与 setInterval() 的区别
1.相同条件下,setTimeout() 只执行一次,setInterval() 则循环执行;
2.setTimeout() 延迟执行一次: setTimeout(fn, 1000); //延迟1秒,执行一次fn();
3.setInterval() 隔段时间循环执行; setInterval(fn, 1000); //每隔1秒,循环执行fn()
9.Math对象
Math.PI // 圆周率
Math.random() // 生成随机数
Math.floor() // 向下取整
Math.ceil() //向上取整
Math.round() // 取整,四舍五入
Math.abs() // 绝对值
Math.max() //求最大值
Math.min() //求最小值
Math.sin() // 正弦
Math.cos() //余弦
Math.power() // 求指数次幂
Math.sqrt() //求平方根
//求10到20的随机数
//生成 min 到 max 之间的随机数
var min = 10;
var max = 20;
console.log( parseInt(Math.random() * (max - min) + min));
10.cookies,sessionStorage 和 localStorage 的区别?
相同点:
SessionStorage, LocalStorage, Cookie这三者都可以被用来在浏览器端存储数据,而且都是字符串类型的键值对。
不同点:
SessionStorage:存放数据大小大约为5M,不参与服务器的通信,关闭当前页面或浏览器就会被清楚。
localStorage:存放数据大小大约为5M或者更大,不参与服务器的通信,永久有效,除非手动删除或者代码删除。
cookies:大小大约为4k的小型文本数据,一般服务器来生成,可以设置失效时间,没有设置关闭浏览器失效。
11.get和post区别
- get一般用于获取请求,post一般用于提交请求
- get倾向于放在url中,post倾向于放在body体内
- 从根本上来说两种请求方式都不够安全,因为http本身就是明文协议,所以安全的普遍做法是采用https密钥加密协议。而由于get是放在请求体内,所以相对来说比较安全的做法是采用post+body的做法
- get数据的长度限制其实是指url的长度限制,但http协议本身其实对url的长度并未做任何限定,实际的限制是由客户端/浏览器以及服务器限定的
12.http和https
- https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
13.ajax基本步骤以及readyState的五种状态 以及ajax的原理
//1创建对象xmlhttprequest
const xhr = new XMLHTTPRequest();
//2创建一个http请求初始化
xhr.open('GET','/api',false);
//3send发送请求
xhr.send();
//4监听状态变化
xhr.onreadystatechange = function(){
//5查看状态码判断状态
if(xhr.readyState == 4){
if(xhr.status >= 200 &&xhr.status <= 300){
}
}
}
readyState的五种状态:
- 未初始化0
- 正在载入1
- 载入完成2
- 开始解析3
- 解析完成4
ajax的原理:
ajax的原理就是浏览器让xhr(XmlHttpRequest)向服务器要数据,而浏览器去干别的事情,当服务器将数据返回给xhr后,xhr通知浏览器,浏览器将数据渲染到页面
14.延迟加载JS有哪些方式?
<script defer type="text/javascript" src='script.js'></script>
//defer : 等html全部解析完成,才会执行js代码,顺次执行js脚本。
15. null和undefined的区别?
null是一个表示"无"的对象(空对象指针),转为数值时为0;
undefined是一个表示"无"的原始值,转为数值时为NaN。
16.js宏任务和微任务
js宏任务有:setTimeout、setInterval、Ajax、DOM事件
js微任务有:process.nextTick、Promise.then catch
js宏任务和微任务谁先执行?
JS是单线程,碰见同步执行同步直到执行完毕,遇到异步放到执行队列中去,异步(宏任务和微任务),在异步中微任务是优于宏任务执行的
setTimeout(() => { console.log(4); }) new Promise(resolve => { resolve() console.log(1) }).then(_ => { console.log(3) }) console.log(2)
setTimeout市异步所以跳过,来到Promise执行里面的同步,console.log(1)。接下来是一个 then 的异步,跳过。最后一个是一段同步代码 console.log(2)。下一步,即之前我们跳过的异步的代码。从上往下,第一个是 setTimeout,还有一个是Promise.then()。
setTimeout 是宏任务的异步,Promise.then()是微任务的异步,微任务是优先于宏任务执行的,所以,此时会先跳过 setTimeout 任务,执行两个 Promise.then() 的微任务。所以此时会执行 console.log(3) 函数。最后就只剩下 setTimeout 函数没有执行,所以最后执console.log(4)。
综上分析:执行结果 1 2 3 4
17. 数组的操作方法
//数组的操作方法
push() //1.从数组末尾追加
unshift() //2.从数组前面添加
pop() //3.从数组末尾删除
shift() //4.从数组头部删除
reverse() //5.数组反转
sort() //6.数组排序
splice() //7.删除 添加 替换
//以上七种可以修改数组本身
forEach() //8.循环遍历
concat() //9.拼接数组
filter() //10.过滤数组
slice() //11.截取元素
every() //12.判断数组中是否有满足
some() //13.只要有一个满足条件返回值就是true,没有满足条件的则为false
reduce() //14.数组求和
indexO() //15.查找值 从前往后查找
lastIndexOf() //16.查找值 是从后往前查找。
toString() //17.把数组转换为字符串
join() //18.把数组转换为字符串, 可以传入不同的符号进行连接 默认用逗号连接
toLocaleString() //19.把数组转换为字符串
map() //20.指“映射”,对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。返回新数组
find() //21.返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
flat() //22.按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。此方法不会改变原数组。depth 可选 指定要提取嵌套数组的结构深度,默认值为 1。如果不确定嵌套多少层,可以使用ES10新增:BigInt 表示任意大的整数
findIndex() //23.方法返回传入一个测试条件(函数)符合条件的数组第一个元素位置。
Array.at() //24.返回指定索引处的值。
//数组的操作方法
//1.push()从数组末尾追加
//push从数组末尾添加,返回值是数组的长度,会改变原数组
var arr = [1, 2, 3, 4, 5]
console.log(arr.push(6, 7)); // 7 arr数组的长度
console.log(arr); //输出结果:[1, 2, 3, 4, 5, 6, 7]
//2.unshift()从数组前面添加
//unshift从数组前面添加,返回值是数组的长度,会改变原数组
var arr = [1, 2, 3, 4, 5]
console.log(arr.unshift(6, 7)); // 7 arr数组的长度
console.log(arr); //输出结果:[ 6, 7, 1, 2, 3, 4, 5 ]
//3.pop()从数组末尾删除
//pop 从数组末尾删除,返回值是删除的值,会改变原数组
var arr = [1, 2, 3, 4, 5]
console.log(arr.pop()); // 5 删除的值
console.log(arr); //输出结果:[ 1, 2, 3, 4 ]
//4.shift()从数组头部删除
//shift 从数组头部删除,返回值是删除的值,会改变原数组
var arr = [1, 2, 3, 4, 5]
console.log(arr.shift()); // 1 删除的值
console.log(arr); //输出结果:[ 2, 3, 4,5 ]
//5.reverse()数组反转
//reverse数组反转,返回值是反转后的数组,会改变原数组
var arr = [1, 2, 3, 4, 5]
console.log(arr.reverse()); // [5, 4, 3, 2, 1]
console.log(arr); //输出结果:[5, 4, 3, 2, 1]
//6.sort()数组排序
//sort数组排序,返回值是排序后的数组,会改变原数组
var arr = [1, 2, 3, 4, 5, 9, 8, 7, 6]
console.log(arr.sort()); //[1, 2, 3, 4, 5, 6, 7, 8, 9]
console.log(arr); //输出结果:[1, 2, 3, 4, 5, 6, 7, 8, 9]
//7.splice()删除 添加 替换
//splice(index,howmany,arr1,arr2),删除元素并添加元素,从index位置开始删除howmany个元素,
//并将arr1,arr2数据从index位置依次插入。howmany为0时,则不删除元素。
//splice数组排序,返回值是删除的数组,会改变原数组
var arr = [1, 2, 3, 4, 5]
console.log(arr.splice(0,2,111,222)); //[1, 2]
console.log(arr); //输出结果: [111, 222, 3, 4, 5]
//以上七种方法是修改原数组的
//8.forEach()循环遍历
//forEach循环遍历,没有返回值,回调函数的参数,第一个参数是数组的每一项,第二个参数是数组中每一项的下标,第三个参数是数组的本身。
var arr = [1, 2, 3, 4, 5]
arr.forEach((item,index,abc) => {console.log(item,index,abc)})
//9.concat()拼接数组
//用来拼接数组 并且 会返回一个新数组。
var arr = [1, 2, 3, 4, 5, 6];
console.log(arr.concat([7, 8, 9])); //输出结果:[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
var arr1 = [1, 2, 3, 4, 5, 6];
var arr2 = [7, 8, 9]
var arr3 = arr1.concat(arr2)
console.log(arr1); //[ 1, 2, 3, 4, 5, 6 ]
console.log(arr3); //输出结果:[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
//10.filter()过滤数组
//filter返回值是一个新的数组,filter里面可以直接 return 筛选条件
let arr = [20, 50, 80, 90]
let newArr = arr.filter((item, index, array) => {
//item:数组每一项,index:数组每一项的x下标,array:数组本身
return item >= 70
})
console.log(newArr); //返回筛选后的数组 [ 80, 90 ]
//11.slice()截取元素
//slice( ):数组元素的截取,返回一个新数组,新数组是截取的元素,可以为负值。
//从数组中截取,如果不传参,会返回原数组。如果只传入一个参数,会从头部开始删除,直到数组结束,原数组不会改变;传入两个参数,第一个是开始截取的索引,第二个是结束截取的索引,不包含结束截取的这一项,原数组不会改变。最多可以接受两个参数。
let arr = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
console.log(arr.slice(0, 2)); // 返回值是被删除的元素['a','b']
console.log(arr); //['a', 'b', 'c', 'd', 'e', 'f', 'g']
//12.every()判断数组中是否有满足
//every遍历数组 一般用于判断数组中是否有满足条件的数组元素,所有元素遍历之后,所有元素都满足条件的元素是返回值为true,若有一个不满足则返回false.
var arr = [1, 2, 3, 4, 5, 6]
console.log(arr.every(item => item > 1)); //输出结果:false
var arr = [1, 2, 3, 4, 5, 6]
console.log(arr.every(item => item > 0)); //输出结果:true
//13.some()只要有一个满足条件返回值就是true,没有满足条件的则为false
//some方法和every方法非常的类似 ,所有元素遍历之后,所有元素都满足条件的元素是返回值为true,若有一个不满足则返回false.
var arr = [1, 2, 3, 4, 5, 6]
console.log(arr.every(item => item > 6)); //输出结果:false
var arr = [1, 2, 3, 4, 5, 6]
console.log(arr.every(item => item > 3)); //输出结果:true
//14.reduce()数组求和
//1.reduce方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
//2.reduce方法可以接收两个参数,第一个参数:要执行的函数,第二个参数:函数迭代的初始值
//3.第一个参数不是函数吗?函数里面的参数如下
prev:上次调用函数的返回值
cur:当前元素
index:当前元素索引
arr:被遍历的数组
//4.array.reduce(function(prev, currentValue, currentIndex, arr), initValue) //initValue是第二个参数
//不传入函数迭代的初始值
const arr = [11, 22, 33, 44]
const sum = arr.reduce((prev, cur, index) => {
console.log(prev, cur, index);
return prev + cur
}) //没有传入函数迭代的初始值, 初始值默认是数组第一位 , prev 就是计算结束后的返回值。
console.log('sum:', sum); //110
//传入函数迭代的初始值
const arr = [11, 22, 33, 44]
const sum = arr.reduce((prev, cur, index) => {
console.log(prev, cur, index);
return prev + cur
}, 10) //传入函数迭代的初始值之后,也就是让 prev 从10开始累加,然后接着迭代累加 prev
console.log('sum:', sum); //120
//15.indexO()查找值 从前往后查找
//接受两个参数:查找的值、查找起始位置
//不存在,返回 -1 ;存在,返回位置。
var arr = [1, 2, 3, 4, 5]
console.log(arr.indexof(2,3)) //-1
//16.lastIndexOf()查找值 是从后往前查找。
//接受两个参数:查找的值、查找起始位置
//不存在,返回 -1 ;存在,返回位置。
var arr = [1, 2, 3, 4, 5]
console.log(arr.lastIndexOf(2,3)) //1
//17.toString()把数组转换为字符串
var arr = [1, 2, 3, 4, 5]
console.log(arr.toString()) //'1,2,3,4,5'
//18.join()把数组转换为字符串, 可以传入不同的符号进行连接 默认用逗号连接
var arr = [1, 2, 3, 4, 5]
console.log(arr.join('|')) //'1|2|3|4|5'
//19.toLocaleString()把数组转换为字符串
var arr = [1, 2, 3, 4, 5]
console.log(arr.toLocaleString()) //'1,2,3,4,5'
//20.map()指“映射”,对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。返回新数组
var arr = [1, 2, 3, 4, 5];
var arr2 = arr.map(function(item){
return item*item;
});
console.log(arr2); //[1, 4, 9, 16, 25]
//21.find()
//返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
// 获取数组中第一个大于10的值
const array1 = [5, 12, 8, 130, 44];
const found = array1.find(element => element > 10);
console.log(found);// expected output: 12
//22.flat()
//按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。此方法不会改变原数组。
//depth 可选 指定要提取嵌套数组的结构深度,默认值为 1。如果不确定嵌套多少层,可以使用ES10新增:BigInt 表示任意大的整数
const arr1 = [0, 1, 2, [3, 4]];
console.log(arr1.flat());// log: [0, 1, 2, 3, 4]
const arr2 = [0, 1, 2, [[[3, 4]]]];
console.log(arr2.flat(2));// log: [0, 1, 2, [3, 4]]
//23.findIndex()方法返回传入一个测试条件(函数)符合条件的数组第一个元素位置。
//IE 11 及更早版本不支持 findIndex() 方法
var arr2 = [1,18,2,99,666,44,66];
var flag2 = arr2.findIndex(item => {
return item > 50;
}); //当数组中的元素在测试条件时返回 true 时, findIndex() 返回符合条件的元素的索引位置,如果没有符合条件的元素返回 -1
console.log(flag2) // 得到: 3
//24.Array.at()返回指定索引处的值。
const list = [1, 2, 3, 4, 5];
list.at(1); // 2
list.at(-1); // 5
list.at(-2); // 4
18.字符串的方法
//字符串常用方法
charAt() //1.返回在指定位置的字符
charCodeAt() //2.返回在指定的位置的字符的 Unicode 编码。
concat() //3.连接字符串。
indexOf() //4.检索字符串。indexOf() 方法对大小写敏感。
match() //5.是用来查找字符的
includes() //6.判断字符串是否包含指定的子字符串。
repeat() //7.字符串复制指定次数
replace() //8.方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
replaceAll() //9.字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串,该函数会替换所有匹配到的子字符串。
search() //10.方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。返回与指定查找的字符串或者正则表达式相匹配的 String 对象起始位置。
slice() //11.提取字符串的某个部分,并以新的字符串返回被提取的部分。
split() //12.方法用于把一个字符串分割成字符串数组
substring() //13.方法用于提取字符串中介于两个指定下标之间的字符。
toLowerCase() //14.方法用于把字符串转换为小写。
toUpperCase() //15.方法用于把字符串转换为大写。
trim() //16.删除字符串的头尾空白符,空白符包括:空格、制表符 tab、换行符等其他空白符等
includes(), startsWith(), endsWith() //17.来确定一个字符串是否包含在另一个字符串中
//1.charAt()返回在指定位置的字符
var str="abc"
console.log(str.charAt(0))//a
//2.charCodeAt()返回在指定的位置的字符的 Unicode 编码。
var str="abc"
console.log(str.charCodeAt(1))//98
//3.concat()连接字符串。
var a = "abc";
var b = "def";
var c = a.concat(b);
console.log(c);//abcdef
//4.indexOf()检索字符串。indexOf() 方法对大小写敏感。
var str="Hello world!"
console.log(str.indexOf("Hello"))//0
console.log(str.indexOf("World"))//-1
console.log(str.indexOf("world"))///6
//5.match()是用来查找字符的
//方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。该方法类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置
var str = 'asdfghajkwyai';
var result = str.match('a'); //result = a
//如果想查找所有满足的匹配结果,就要加一个 g 才会返回所有满足匹配的结果
var str = 'asdfghajkwyai';
var result = str.match(/a/g); //result = aaa
//若没有标志 g,.match()方法就只执行一次匹配,找到结果就返回,不会接着去查找;若没有找到任何匹配文本,.match()方法将会返回nul;
//若有标志 g,.match()就会返回一个数组,数组中存放所有满足查找条件的信息;
//6.includes()判断字符串是否包含指定的子字符串。
let str = "Hello";
let s = str.includes("e");
console.log(s); //true
//语法:string.includes(searchvalue, start)
//searchvalue 必需值,要查找的字符串。
//start 可选值,设置从那个位置开始查找,默认为 0。
//7.repeat()字符串复制指定次数
let str = "Hello";
let s = str.repeat(2);
console.log(s); //HelloHello
//语法:string.repeat(count)
//count 必需,设置要复制的次数。
//8.replace()字符替换
let str = "Hello";
let s = str.replace("l", "o");
console.log(s); //Heolo
//语法:string.replace(searchvalue,newvalue)
//searchvalue 必须。规定子字符串或要替换的模式的 RegExp 对象。
//请注意,如果该值是一个字符串,则将它作为要检索的直接量文本模式,而不是首先被转换为RegExp对象。
//newvalue 必需。一个字符串值。规定了替换文本或生成替换文本的函数。
//9.replaceAll()字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串,该函数会替换所有匹配到的子字符串。
let str = "Hello";
let s = str.replaceAll("l", "o");
console.log(s); //Heooo
//语法同replace方法相同
//10.search()
//search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。返回与指定查找的字符串或者正则表达式相匹配的 String 对象起始位置。
let str = "Hello";
let s = str.search("lo");
console.log(s); //3
//语法:string.search(searchvalue)
//searchvalue 必须。查找的字符串或者正则表达式。
//11.slice()提取字符串的某个部分,并以新的字符串返回被提取的部分。
let str = "Hello";
let s = str.slice(1, 2);
console.log(s); //e
//语法:string.slice(start,end)
//start 必须。 要抽取的片断的起始下标,第一个字符位置为 0。如果为负数,则从尾部开始截取。
//end 可选。 紧接着要截取的片段结尾的下标。若未指定此参数,则要提取的子串包括 start 到原字符串结尾的字符串。如果该参数是负数,那么它规定的是从字符串的尾部开始算起的位置。slice(-2) 表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。
//12.split() 方法用于把一个字符串分割成字符串数组
let str = "Hello";
let s = str.split("e");
console.log(str); //Hello
console.log(s); //[ 'H', 'llo' ]
//语法:string.split(separator,limit)
//separator 可选。字符串或正则表达式,从该参数指定的地方分割 string Object。
//limit 可选。该参数可指定返回的数组的最大长度。如果设置了该参数,返回的子串不会多于这个参数指定的数组。如果没有设置该参数,整个字符串都会被分割,不考虑它的长度。
//13.substring() 方法用于提取字符串中介于两个指定下标之间的字符。
let str = "Hello";
let s = str.substring(1, 3);
console.log(str); //Hello
console.log(s); //el
//语法:string.substring(from, to)
//from 必需。一个非负的整数,规定要提取的子串的第一个字符在 string Object 中的位置。
//to 可选。一个非负的整数,比要提取的子串的最后一个字符在 string Object 中的位置多 1。
如果省略该参数,那么返回的子串会一直到字符串的结尾。
//14,15.toLowerCase()和toUpperCase()方法
let str = "Hello";
let s = str.toLowerCase();
let s2 = str.toUpperCase();
console.log(str); //Hello
console.log(s); //hello
console.log(s2);//HELLO
//16.trim()删除字符串的头尾空白符,空白符包括:空格、制表符 tab、换行符等其他空白符等
let str = " Hello ";
let s = str.trim();
console.log(str); // Hello
console.log(s); //Hello
//17.includes(), startsWith(), endsWith()来确定一个字符串是否包含在另一个字符串中
let s = 'Hello world!';
console.log(s.startsWith('world', 6));// true
console.log(s.endsWith('Hello', 5));// true
console.log(s.includes('Hello', 6));// false
//注意:第二个参数,表示开始搜索的位置。
字符串进行去重
var str="aahhgggsssjjj"; function removeRepeat(n){ var k=[]; var arr=n.split(""); for(var i=0;i<arr.length;i++){ if(k.indexOf(arr[i])==-1){ k.push(arr[i]); } } return k.join(""); } removeRepeat(str); //ahgsj
19.为什么0.1+0.2 ! == 0.3,如何让其相等
在开发过程中遇到类似这样的问题:
let n1 = 0.1, n2 = 0.2 console.log(n1 + n2) // 0.30000000000000004
这里得到的不是想要的结果,要想等于0.3,就要把它进行转化:
(n1 + n2).toFixed(2) // 注意,toFixed为四舍五入
toFixed(num)
方法可把 Number 四舍五入为指定小数位数的数字。
20.如何获取安全的 undefined 值?
因为 undefined 是一个标识符,所以可以被当作变量来使用和赋值,但是这样会影响 undefined 的正常判断。表达式 void ___ 没有返回值,因此返回结果是 undefined。void 并不改变表达式的结果,只是让表达式不返回值。因此可以用 void 0 来获得 undefined。
21.typeof NaN 的结果是什么?
NaN 指“不是一个数字”(not a number),NaN 是一个“警戒值”,用于指出数字类型中的错误情况,即“执行数学运算没有成功,这是失败后返回的结果”。
typeof NaN; // "number"
NaN 是一个特殊值,它和自身不相等。而 NaN !== NaN 为 true。
22.Object.is() 与比较操作符 “===”、“==” 的区别?
- 使用双等号(==)进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。
- 使用三等号(===)进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。
- 使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 是相等的。
23.const对象的属性可以修改吗
const保证的并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。对于基本类型的数据(数值、字符串、布尔值),其值就保存在变量指向的那个内存地址,因此等同于常量。
对于引用类型的数据来说,变量指向数据的内存地址,保存的只是一个指针,const只能保证这个指针是固定不变的,至于它指向的数据结构是不是可变的,就完全不能控制了。
24. 如果new一个箭头函数的会怎么样
箭头函数是ES6中的提出来的,它没有prototype,也没有自己的this指向,更不可以使用arguments参数,所以不能New一个箭头函数。
new操作符的实现步骤如下:
- 创建一个对象
- 将构造函数的作用域赋给新对象(也就是将对象的__proto__属性指向构造函数的prototype属性)
- 指向构造函数中的代码,构造函数中的this指向该对象(也就是为这个对象添加属性和方法)
- 返回新的对象
上面的第二、三步,箭头函数都是没有办法执行的。
25.箭头函数与普通函数的区别
箭头函数比普通函数更加简洁(如果没有参数,就直接写一个空括号即可,如果只有一个参数,可以省去参数的括号)
箭头函数没有自己的this
箭头函数继承来的this指向永远不会改变
call()、apply()、bind()等方法不能改变箭头函数中this的指向
箭头函数不能作为构造函数使用
箭头函数没有自己的arguments
箭头函数没有prototype
箭头函数不能用作Generator函数,不能使用yeild关键字
26.new操作符的实现原理
new操作符的执行过程:
(1)首先创建了一个新的空对象
(2)设置原型,将对象的原型设置为函数的 prototype 对象。
(3)让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性)
(4)判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
实现方式
function objectFactory() { let newObject = null; let constructor = Array.prototype.shift.call(arguments); let result = null; if (typeof constructor !== "function") {// 判断参数是否是一个函数 console.error("type error"); return; } // 新建一个空对象,对象的原型为构造函数的 prototype 对象 newObject = Object.create(constructor.prototype); // 将 this 指向新建对象,并执行函数 result = constructor.apply(newObject, arguments); // 判断返回对象 let flag = result && (typeof result === "object" || typeof result === "function"); // 判断返回结果 return flag ? result : newObject; } // 使用方法 objectFactory(构造函数, 初始化参数);
27.为什么函数的 arguments 参数是伪数组而不是数组?如何遍历伪数组?
arguments
是一个对象,它的属性是从 0 开始依次递增的数字,还有callee
和length
等属性,与数组相似;但是它却没有数组常见的方法属性,如forEach
,reduce
等,所以叫它们伪数组。三种遍历为数组的方法
第一种
function foo(){ Array.prototype.forEach.call(arguments, a => console.log(a)) } //将数组的方法应用到类数组上,这时候就可以使用call和apply方法。
第二种
function foo(){ const arrArgs = Array.from(arguments) arrArgs.forEach(a => console.log(a)) } //使用Array.from方法将类数组转化成数组
第三种
function foo(){ const arrArgs = [...arguments] arrArgs.forEach(a => console.log(a)) } //使用展开运算符将类数组转化成数组
28.对AJAX的理解,实现一个AJAX请求
AJAX是 Asynchronous JavaScript and XML 的缩写,指的是通过 JavaScript 的 异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。
创建AJAX请求的步骤:
- 创建一个 XMLHttpRequest 对象。
- 在这个对象上使用 open 方法创建一个 HTTP 请求,open 方法所需要的参数是请求的方法、请求的地址、是否异步和用户的认证信息。
- 在发起请求前,可以为这个对象添加一些信息和监听函数。比如说可以通过 setRequestHeader 方法来为请求添加头信息。还可以为这个对象添加一个状态监听函数。一个 XMLHttpRequest 对象一共有 5 个状态,当它的状态变化时会触发onreadystatechange 事件,可以通过设置监听函数,来处理请求成功后的结果。当对象的 readyState 变为 4 的时候,代表服务器返回的数据接收完成,这个时候可以通过判断请求的状态,如果状态是 2xx 或者 304 的话则代表返回正常。这个时候就可以通过 response 中的数据来对页面进行更新了。
- 当对象的属性和监听函数设置完成后,最后调用 sent 方法来向服务器发起请求,可以传入参数作为发送的数据体。
const SERVER_URL = "/server"; let xhr = new XMLHttpRequest(); // 创建 Http 请求 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"); // 发送 Http 请求 xhr.send(null);
使用Promise封装AJAX:
// promise 封装实现: function getJSON(url) { // 创建一个 promise 对象 let promise = new Promise(function(resolve, reject) { let xhr = new XMLHttpRequest(); // 新建一个 http 请求 xhr.open("GET", url, true); // 设置状态的监听函数 xhr.onreadystatechange = function() { if (this.readyState !== 4) return; // 当请求成功或失败时,改变 promise 的状态 if (this.status === 200) { resolve(this.response); } else { reject(new Error(this.statusText)); } }; // 设置错误监听函数 xhr.onerror = function() { reject(new Error(this.statusText)); }; // 设置响应的数据类型 xhr.responseType = "json"; // 设置请求头信息 xhr.setRequestHeader("Accept", "application/json"); // 发送 http 请求 xhr.send(null); }); return promise; }
29.forEach和map方法有什么区别
都是用来遍历数组的
- forEach()方法会针对每一个元素执行提供的函数,对数据的操作会改变原数组,该方法没有返回值;
- map()方法不会改变原数组的值,返回一个新数组,新数组中的值为原数组调用函数处理之后的值;
30.对Promise的理解
Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,他的出现大大改善了异步编程的困境,避免了地狱回调,它比传统的解决方案回调函数和事件更合理和更强大。
Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise的实例有三个状态:
- Pending(进行中)
- Resolved(已完成)
- Rejected(已拒绝)
Promise的实例有两个过程
- pending -> fulfilled : Resolved(已完成)
- pending -> rejected:Rejected(已拒绝)
注意:一旦从进行状态变成为其他状态就永远不能更改状态了。
31.谈谈 script标签中 defer和 async属性的区别。
区别如下。
(1) defer属性规定是否延迟执行脚本,直到页面加载为止, async属性规定脚本一旦可用,就异步执行。
(2) defer并行加载 JavaScript文件,会按照页面上 script标签的顺序执行, async并行加载 JavaScript文件,下载完成立即执行,不会按照页面上 script标签的顺序执行。
32.说说你对闭包的理解。
使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染;缺点是闭包会常驻内存,增加内存使用量,使用不当很容易造成内存泄漏。在JavaScript中,函数即闭包,只有函数才会产生作用域闭包有3个特性
(1)函数嵌套函数。
(2)在函数内部可以引用外部的参数和变量
(3)参数和变量不会以垃圾回收机制回收
33.请解释一下事件冒泡机制
事件冒泡就是在事件开始时,由最具体的元素(文档中最底层的那个节点)接受,然后逐级向上传播到最不具体的节点(文档)。比如说,在一个页面有一个div元素,加上一个点击事件,在点击事件触发的时候,它的传递过程就是由div→body→html→document(老版本暂且不谈),它会沿着DOM树逐级的传递。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> .outer{ width: 200px; height: 200px; background: red; z-index: 1; } .cent{ width: 100px; height: 100px; background: blue; position: absolute; right: 0; left: 0; bottom: 0; top: 0; margin:auto; z-index: 2; } .insert{ width: 50px; height: 50px; background: orange; position: absolute; right: 0; left: 0; bottom: 0; top: 0; margin:auto; z-index: 3; } div{ position: relative; } </style> </head> <body> <div class="outer"> <div class="cent"> <div class="insert"></div> </div> </div> </body> <script type="text/javascript"> var Outer=document.getElementsByClassName("outer")[0]; var Cent=document.getElementsByClassName("cent")[0]; var Insert=document.getElementsByClassName("insert")[0]; var aBody=document.getElementsByTagName("body")[0]; Outer.onclick=function(){ console.log("aaa") } Cent.onclick=function(){ console.log("bbb") } Insert.onclick=function(){ console.log("ccc") } aBody.onclick=function(){ console.log("我是body") } </script> </html>
点击Insert这个元素的时候会依次输出ccc、bbb、aaa、我是body,这就是事件冒泡机制。
34.阻止事件冒泡的方法
阻止事件冒泡的方法有两种:
- storpPrapagation() // 不支持IE低版本
- cancelBubble=true
兼容写法
if(event.storpPrapagation){
event.storpPrapagation();
}else{
cancelBubble=true;
}
35.什么是事件委托?它有什么好处?
事件委托指利用冒泡的原理,把事件加到父级上,触发执行效果好处如下。
减少事件数量,提高性能。
预测未来元素,新添加的元素仍然可以触发该事件。
避免内存外泄,在低版本正E中,防止删除元素而没有移除事件造成的内存溢出。
36.随机从数组中取出一个值
var arr = ['1', '2', '3'];
var index = Math.floor((Math.random() * arr.length));
console.log(arr[index]);
37.javascript禁止浏览器返回上一个页面
<script type="text/javascript">
$(function () {
if (window.history && window.history.pushState) {
$(window).on('popstate', function () {
window.history.pushState('forward', null, '#');
window.history.forward(1);
});
}
window.history.pushState('forward', null, '#'); //在IE中必须得有这两行
window.history.forward(1);
})
</script>
38.jquery移动端禁止浏览器缩放
要禁止移动端浏览器的缩放,您可以在页面初始化时为viewport
的meta
标签添加user-scalable=no
属性。这样,当用户在移动端浏览器中尝试缩放页面时,浏览器就不会响应用户的缩放操作。
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
39.如何遍历一个对象(Object)的所有属性并在控制台输出它们的值?
for (let key in obj) {
console.log(key + ": " + obj[key]);
}
40.如何通过函数获取变量的数据类型?
const getType = (value) => {
const match = Object.prototype.toString.call(value).match(/ (\w+)]/)
return match[1].toLocaleLowerCase()
}
console.log(getType());// undefined
console.log(getType({}));// object
console.log(getType([]));// array
console.log(getType(1));// number
console.log(getType('fatfish'));// string
console.log(getType(true));// boolean
console.log(getType(/fatfish/));// regexp
41.生成随机字符串
const randomString = (len) => {
let chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz123456789";
let strLen = chars.length;
let randomStr = "";
for (let i = 0; i < len; i++) {
randomStr += chars.charAt(Math.floor(Math.random() * strLen));
}
return randomStr;
};
randomString(10) // pfkMfjEJ6x
randomString(20) // ce6tEx1km4idRNMtym2S
42.生成指定范围内的随机数
const randomNum = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
randomNum(1, 10) // 6
randomNum(10, 20) // 11
43.格式化钱的方式有很多种,比如这两种方式。
格式化钱的第一种方式
const formatMoney = (money) => {
return money.replace(new RegExp(`(?!^)(?=(\\d{3})+${money.includes('.') ? '\\.' : '$'})`, 'g'), ',')
}
formatMoney('123456789') // '123,456,789'
formatMoney('123456789.123') // '123,456,789.123'
formatMoney('123') // '123'
格式化钱的第二种方式
正则表达式让我们太头疼了,不是吗?所以我们需要找到一种更简单的方法来格式化货币。
const formatMoney = (money) => {
return money.toLocaleString()
}
formatMoney(123456789) // '123,456,789'
formatMoney(123456789.123) // '123,456,789.123'
formatMoney(123) // '123'