拓展题
写一个方法,返回10个不重复的正整数
方式一:
function num(){
let obj= {}
for(let i=0;i<10;i++){
let x=Math.round(Math.random()*100);
// 当数据不存在
if(obj.x===undefined){
obj[x]=x
}else{
// 当数据已存在,重新赋值
let newx=Math.round(Math.random()*100)
obj[newx]=newx
}
}
return Object.values(obj)
}
console.log( num() );
//[16, 18, 22, 33, 54, 62, 63, 70, 76, 95]
方式二
function num(){
const list=new Set()
while(list.size<10){
list.add(Math.round(Math.random()*100))
}
//将set对象转化成数组
return [...list]
}
console.log(num())
// [70, 40, 33, 61, 84, 20, 44, 21, 34, 51]
Set
对象允许你存储任何类型的唯一值,无论是[原始值]或者是对象引用
给数组随机排序
简洁版:
var s=[1,2,3,4,5,6,7] ;
s.sort(()=>Math.random()>0.5?-1:1) ;
console.log(s)
//(7) [2, 1, 4, 6, 5, 3, 7]
常规版:
h=(arr)=>{
let len=arr.length
for(var i=0;i<len-1;i++){
var index=parseInt(Math.random()*(len-i)); //len-i 的作用是限制index的大小不能超出范围
var temp=arr[index];
arr[index]=arr[len-i-1];
arr[len-i-1]=temp;
}
return arr
}
var arr=[1,2,3,4,5,6,7,8]
console.log(h(arr))
//(8) [3, 2, 8, 6, 5, 7, 4, 1]
算数乘法表:
document.write("<table border='1'>");
for(i=0;i<10;i++){
document.write("<tr>")
for(j=0;j<10;j++){
if(j<=i){
document.write("<td>")
document.write(`${i}*${j}=${i*j}`)
document.write("</td>")
}else{
}
}
document.write("</tr>")
}
document.write("</table>");
js中如何检测一个变量是string类型?
方式一:
var str='hhhhhhh'
console.log(str.constructor===String)
// true
方式二:
Object.prototype.toString.call(str).slice(8,-1)
// "String"
方式三:
typeof str
// "string"
类型比较
{ } == { } //false
[ ] == [ ] //false
//在js中,数组和对象属于引用类型数据,==两边是引用类型数据的地址,每当创建一个新的数据时,地址 不同,所以为false
浏览器控制台上会打印什么?
var a=10 ;
(()=>{
console.log(a)
var a=100
})()
// undefined
// 原因: 声明 var a 在console.log()之前,赋值 a=100在console.log()之后,所以打印a的时候是undefined;
// 解析之后是这样的
var a=10 ;
(()=>{
var a
console.log(a)
a=100
})()
如果把var换成let 或者const ,会输出10
"newarr"中有哪些元素?
var arr=[]
for(i=0;i<3;i++){
arr.push(()=>i)
}
var newarr = arr.map(
el=>el()
)
console.log(newarr)
// (3) [3, 3, 3]
解析: arr: [ ()=>i, ()=>i, ()=>i ]
for循环头部 用var定义变量i,会为该变量创建单向的存储空间,三个箭头函数体中的每个'i'
都指向相同的绑定,循环结束之后i为3
如果使用 let 声明一个具有块级作用域的变量,则为每个循环迭代创建一个新的绑定
每个'i'指的是一个新的的绑定,并保留当前的值,因此每个箭头函数返回一个不同的值。
// 使用ES6块级作用域
var array = [];
for (let i = 0; i < 3; i++) {
// 这一次,每个'i'指的是一个新的的绑定,并保留当前的值。
// 因此,每个箭头函数返回一个不同的值。
array.push(() => i);
}
var newArray = array.map(el => el());
console.log(newArray); // [0, 1, 2]
解决这个问题的另一种方法是使用[闭包](http://dmitrysoshnikov.com/ecmascript/chapter-6-closures/)。
let array = [];
for (var i = 0; i < 3; i++) {
array[i] = (function(x) {
return function() {
return x;
};
})(i);
}
const newArray = array.map(el => el());
console.log(newArray); // [0, 1, 2]
如果我们在浏览器控制台中运行'foo'函数,是否会导致堆栈溢出错误?
function foo() {
setTimeout(foo, 0); // 是否存在堆栈溢出错误?
};
解析:
JavaScript并发模型基于“事件循环”。 当我们说“浏览器是 JS 的家”时我真正的意思是浏览器提供运行时环境来执行我们的JS代码。
浏览器的主要组件包括调用堆栈,事件循环****,任务队列和Web API。 像setTimeout
,setInterval
和Promise
这样的全局函数不是JavaScript的一部分,而是 Web API 的一部分。 JavaScript 环境的可视化形式如下所示:
[图片上传失败...(image-78bfc4-1566531357288)]
JS调用栈是后进先出(LIFO)的。引擎每次从堆栈中取出一个函数,然后从上到下依次运行代码。每当它遇到一些异步代码,如setTimeout
,它就把它交给Web API
(箭头1)。因此,每当事件被触发时,callback
都会被发送到任务队列(箭头2)。
事件循环(Event loop)不断地监视任务队列(Task Queue),并按它们排队的顺序一次处理一个回调。每当调用堆栈(call stack)为空时,Event loop获取回调并将其放入堆栈(stack )(箭头3)中进行处理。请记住,如果调用堆栈不是空的,则事件循环不会将任何回调推入堆栈。
现在,有了这些知识,让我们来回答前面提到的问题:
步骤
- 调用
foo()
会将foo
函数放入调用堆栈(call stack)。 - 在处理内部代码时,JS引擎遇到
setTimeout
。 - 然后将
foo
回调函数传递给WebAPIs(箭头1)并从函数返回,调用堆栈再次为空 - 计时器被设置为0,因此
foo
将被发送到任务队列<Task Queue>(箭头2)。 - 由于调用堆栈是空的,事件循环将选择
foo
回调并将其推入调用堆栈进行处理。 - 进程再次重复,堆栈不会溢出。
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2
//输出所有数字都在0到n-1的范围内的数字
fit=(n)=>{
let num=Math.round(Math.random()*10)
if(num<n){
return num
}else{
//这里需要加return 否则输出undefined
return fit(n);
}
}
fn=(n)=>{
let arr=[];
while(arr.length<n){
arr.push(fit(n))
}
//生成数组arr
let objs={}
console.log("arr",arr)
arr.map(p=>{
if(objs[p]===undefined){
objs[p]=1
}else{
objs[p]=1+ objs[p]
}
})
// objs储藏每个数字出现的次数
return objs
}
fn(7);
// arr (7) [5, 4, 1, 4, 5, 6, 1]
// {1: 2, 4: 2, 5: 2, 6: 1}
//简洁版: 输出所有数字都在0到n-1的范围内的数字
Math.floor(Math.random() * n)
可以代替fit()函数的功能