18-数学对象和定时器

第十八章.数学对象和定时器

1. Math对象

JS中的计算只能取到合理近似值(误差很小),请理性看待,合理使用

.1+.2;//0.30000000000000004

Math是一个JavaScript内置对象,在window对象下的一个属性

Math === window.Math

数学中我们常用的计算以及参数都会保存在Math对象中。

圆周率π和自然常数e

Math.PI;//3.1415926...
//计算面积,概率都会用到
Math.E;//2.71828182...
//计算指数对数都会用到
  • 算术平方根Math.sqrt

计算开方结果

Math.sqrt(2)*Math.sqrt(2);//2.0000000000000004约等于2
  • pow指数
Math.pow(2,3);//2的3次方
  • floor和ceil和round和trunc(向下取整,向上取整,四舍五入,删除小数部分)
  • 三角函数,反三角函数

计算相对位置,角度,游戏中常用到的边界碰撞判断等。

弧度制:弧度是一个角的张开程度,单位rad通常省略。有正负。

规定平面内一条线段绕端点旋转一周回到初始位置所扫过的角度为Math.PI*2,对应360deg,逆时针为正,顺时针为负数。

正弦:Math.sin

某一角度的计算值。此角度(0,Math.PI/2)形成直角三角形对边除以斜边的值

Math.sin(Math.PI/6);//0.49999999999999994约等于0.5

余弦:Math.cos

某一角度的计算值。此角度(0,Math.PI/2)形成直角三角形邻边比斜边的值

Math.cos(Math.PI/3);//0.5000000000000001约等于0.5

正切:Math.tan

某一角度的计算值。此角度(0,Math.PI/2)形成直角三角形对边比邻的边的值

Math.tan(Math.PI/4);//0.9999999999999999约等于0.5
  • 反三角 asin/acos/stan,根据正弦值余弦值正切值返回对应的弧度
  • 返回随机数Math.random,返回[0,1)的随机数
let rdm = Math.random();//
rdm = Math.random();
rdm = Math.random();

自行封装的随机数生成大于n小于m的随机数

let myRandom = (n = 0,m = 1)=>(Math.random()*(m-n)+n)

思考: 投出一个色子,6的概率为50%,1的概率3%,怎么实现?

  • 求不超过n的最大整数,取整
Math.floor(3.15);//3
Math.floor(-2.3);//-3
  • 绝对值Math.abs
  • 求一组数的最大值Math.max与最小值Math.min
let arr = [1,3,4,99,0]
Math.max(...arr);//0
Math.min(...arr);//99
Math.max.apply(null, arr)
  • parseInt和parseFloat

    解析传入的字符串,返回一个符合要求的10进制数,解析不出来返回NaN

    paseInt 返回整数

    传入两个参数: 第一个是需要解析的字符串,必填

    第二个是进制基数2-36(0-9,a-z),当前传入的字符串的进制是多少,不填默认是10

    parseInt("1123.asdasd");//1123
    parseInt("a123");//NaN
    parseInt("Infinity");//NaN
    parseInt("123",16);//以16进制识别123,值为1*16*16+2*16^1+3
    parseInt("zzz",36);//以36进制识别zzz,值为35*36*16+35*36+35
    parseInt(123,2);//123转字符串"123",2进制识别1 转2进制 1*Math.pow(2,0)
    

    paseFloat返回带小数点的浮点类型

    返回整数或者小数,支持科学记数法,解析不出来返回NaN

    parseFloat("123.231");//123.231
    parseFloat({toString(){return 1}});//1 底层是对传入的参数使用toString方法,或者valueOf方法
    parseFloat([1,23,5])// 1 
    parseFloat("asd");//NaN
    parseFloat("2e-3");//0.003
    parseFloat("2.32E3");//2320
    parseFloat("0x13");//0
    

    保留小数点: (num).toFixed(n)

    或者用正则: (num).toString().match(/.*…{3}/)

2. 指数运算符(**) 指数赋值运算符

指数运算公式 ** :(es6新出,支持赋值)

Math.pow(3,4);//81
3**4//81
let a = 2;
a**=3;//8
//等同于 a=a**3;

3. 定时器

JS的代码是什么时候执行的?除了触发执行,代码都是在页面加载的时候瞬间执行完了。

我们需要控制在某个固定的时刻往进程中添加代码执行。

setTimeout执行之后返回一个正整数,是定时器的编号,可以用这个编号清除定时器,不同的定时器编号会累加

  • 在某段时间之后执行代码setTimeout,

第一个参数是需要执行的代码或者回调函数,必须,

第二个参数是延时,不写默认为0,单位毫秒(1s = 1000ms)

第三个以后是需要执行的代码传入的参数

let foo = (x,y) =>console.log(x+y)
setTimeout(foo,1000,2,3)//返回一个正整数定时器编号
//1s之后打印出5
setTimeout(foo,1000,...[2,3])
setTimeout(()=>foo(2,3),1000)

因为

window.setTimeout === setTimeout;//true

这里不管在哪调用setTimeout的主体是window

let o = {a:1}
function foo(){
    setTimeout(function(){
        console.log(this);
    },1000)
}
foo.call(o);//这里指向window

因为是window调用的setTimeout所以不可以修改。定时器永远是浏览器调用

解决方法:

let o = {a:1}
function foo(){
    setTimeout(function(){
        console.log(this);
    }.bind(o),1000)//强行修改回调函数的this,返回的函数和原函数已经不是同一个了
}
foo();//这里指向o

或者:

let o = {a:1}
function foo(){
    setTimeout(()=>{//硬绑定到foo上下文的this中
        console.log(this);
    },1000)
}
foo.call(o);//这里指向o

清除定时器:clearInterval传入一个参数,就是定时器的序号。页面唯一。

let timer = setTimeout(function(){},5000);
clearInterval(timer);//上面那个定时器就删掉了。
  • 运行代码后每隔一段时间执行相应代码:setInterval,和setTimeout有相似性质

    第一个参数是需要执行的代码或者回调函数,必须,

    第二个参数是延时,不写默认为0,单位毫秒(1s = 1000ms)

    第三个以后是需要执行的代码传入的参数

let timer = setInterval(function(a,b){
    console.log(a+b);
},1000,2,3);//每隔1000ms打印依次5
clearInterval(timer);//通过定时器序号清除定时器
console.time()
console.timeEnd()//计时功能

4. 同步与异步

首先说一下进程和线程的概念

计算机(不止)有两个东西:cpu和内存,cpu是计算资源(能进行多少的计算),内存是运行过程中的存储数据。维持电脑正常运行cpu(或者gpu)需要分配给不同软件不同的计算资源,就是通过进程控制的。

进程:浏览器这个软件打开的时候有多个进程的,不同的进程有不同的作用(比如:插件,界面,GPU等)。单独打开一个新页面的时候是单独分配了一个进程。(单页面崩溃)

线程: 一个进程里面有多个线程运行(异步线程,JS引擎,GUI渲染等)。其中有一个js引擎,掌控了所有的JS代码运行。

所以JS是单线程运行的,换句话说,同一时刻只能做一件事情。

for(let i = 0;i < 900000000;i++){}//页面卡死一小会,无法操作

虽然JS执行和浏览器渲染虽然不是同一个线程,但是JS涉及页面元素操作,修改操作完成之前渲染会被锁死,JS完成之后才会渲染。这就是单线程的性质。

  • 什么是同步?

    当读取到JS代码的时候:代码会从上往下执行,当前面的代码执行完成返回之前,后面的代码是不会执行的。其余操作也是不会执行的。

console.log(1);
console.log(2);
for(let i = 0;i < 900000000;i++){}//页面卡死一小会,无法操作
console.log(3);//在上行代码执行完成之前是不会打印的
//1 2 等一会儿 3
  • 什么是异步?

    异步的含义是相对于同步的,某行代码的执行单独开辟线程处理,与主线程无关,返回结果传递到主线程。但是JS运行是单线程的,所以不存在真正的异步

    那么

console.log(1);
setTimeout(console.log,1000,2);
console.log(3);
//1 3 等一会儿 2

3明明在2之前执行并且定时器等了1000ms打印出了2,这不就是异步吗?

这是JS的魔法,它用了一些神奇操作实现了上述代码

这里要说一个东西:执行队列。

JS运行是单线程的,JS执行的时候会依照一个顺序执行:

先执行完同步队列----->再执行异步队列

浏览器执行同步队列里的代码,

当遇到setTimeout或者setInterval或者点击事件等,会在必要的时刻将代码标识扔到异步队列中,异步代码会返回结果表示代码执行完成,实际代码没有执行。

同步执行完成会处于空闲状态。

处于空闲状态(执行间隙)才会不停扫描异步队列,将扫描到的标识为需要执行的异步代码执行

你可能感兴趣的:(js,javascript)