JS知识点回顾——运算符

127 阅读6分钟

前置知识

函数基础知识:普通函数调用时,this指向的是调用函数的对象,但是到底是谁调用了函数呢

let name = "let的name";
const person = {
  name:"person的name",
  getName(){
    return this.name;
  }
}
const getName = person.getName;
console.log(person.getName()); 
console.log(getName());
console.log((person.getName)());
console.log((0,person.getName)());

console.log(person.getName())

这里是person调用的getName所以this指向person,打印"person的name"

console.log(getName())

这里调用getName的是window,window上没有name所以返回undefined,外面是let定义的所以不在window上,使用var定义才会被打印

console.log((person.getName)())

这里就看(person.getName)这里面指向是谁,主要看()运算符会不会计算值并赋值给谁

引用的概念:内部引用数据类型不是语言数据类型;用于解释诸如delete、typeof和赋值等操作符的行为;例如,赋值的左操作数应该产生一个引用记录

var num = 10;这里的num可以说是一个标识符也可以说是一个引用

10=10是不能赋值成功的,因为左边的10不是一个引用

赋值操作其实是一个取值和赋值的过程

GetValue(v):取值操作,返回的是确定的值

PutValue(v,w):设置值,对某个引用设置,要求v一定是一个引用

理解v=v

可以理解为 v=GetValue(v)

v作为左手端的时候它是引用,在右边的时候它是值

image.png

image.png

一些赋值操作

image.png

分组运算符:()里面可以是表达式也可以是字面量的值,此算法不将GetValue应用于Expression(表达式)的结果,因为像delete和typeof等操作符可以应用于括号表达式,意思就是分组运算符不计算值

所以(person.getName)没有产生getValue操作,没有发生取值就没有赋值,所以this还是指向的是person

console.log((0,person.getName)()) 逗号运算符,它会对每个操作数求值,并返回从左到右的最后一个操作数的值;所以this指向window

typeof 在非严格模式下不报错,是因为引用不可达就返回undefined

image.png

var num = 10;
function evalCode(){
  eval(`var num = 20`)
}
function evalCode2() {
  (0,eval)(`var num = 30`)
}
console.log(num) // 10
evalCode()
console.log(num)// 10
evalCode2()
console.log(num)// 30

第一个是10,没有疑问

第二个是10,因为执行函数,num变量是在函数内部,不在window,所以num还是10

第三个是30,应该是逗号运算符会计算所以返回值了

delete到底在删除什么

delete的返回值是Boolean,true不一定删除成功,只是删除没有发生异常,false表示一定没有删除成功;delete删除原型上的属性,delete不会去遍历原型链,可以使用delete Foo.prototype.bar删除

delete不能删除的属性

1、任何var声明的属性不能从全局作用域或者函数作用域删除

2、任何let和const声明的属性不能从其作用域删除

3、不可配置的(configurable)属性不能被删除

4、undefined在window上是不可配置的,所以也不能从window上删除

本质:操作表达式的结果

1、对于字面量、值,不操作直接返回true

2、对于引用不可达的也是直接返回true

3、引用类型,删除引用,比如删除数组的某个下标,该下标的值会变成空

image.png

严格模式下报错类型

SyntaxError:语法错误,删除变量、函数名、函数参数时报错

TypeError:删除不可配置的属性

ReferenceError:引用错误

console.log(delete null) // truenull是常量,返回true
console.log(delete 11) // true11是常量直接返回true
console.log(delete undefined) // false,undefined是window上的属性,且不可配置,返回false
a={c:12}
console.log(delete a) // true,不使用var声明的可配置
var b=12;
console.log(delete b) // false,使用var声明的变量不可配置
console.log(delete xxxxx) // true,不可达直接返回true
console.log(delete ({}).toString) // true,没有错误但是没有真正删除

位运算符

操作数必须是32位的整数,如果不是自动转为整数,速度很快

按位与(&)

两个操作数为1则为1,否则为0

用处: 判断奇偶数

奇数:num & 1 === 1

偶数:num & 1 === 0

image.png

按位或(|)

一个操作数为1则为1

用处: 取整

x | 0;做位运算必须是整数,再|0得到的是它本身;

x|x ===x

image.png

按位非(~)

反转操作数的位,表象是对数字求负,然后减1

image.png

用处:

1、判断数组中是否包含某个元素,不存在indexOf返回-1,~-1 = -(-1)-1=0

function inArrayCompare(arr,num) {
  if(~arr.indexOf(num)){
    return true;
  }
  return false;
}

2、取整

~~x:-(-x-1)-1=x

按位异或(^)

只当一个数位是1返回1,否则返回0

image.png

特点:

1、归零律:a^a=0;自己异或自己,相同位数上的值肯定相同,所以为0

2、恒等律:a^0=a;自己异或0,自己是啥结果是啥

3、自反律:出现奇数次是自己,出现偶数次是0;a^a^a = 0^a = a

4、结合律:a^b^c === c^b^a;和顺序无关

image.png

例子: 变量值为数字,完成值的交换不添加临时变量

let a = 10;
let b = 20;
a^=b;
b^=a;
a^=b;

image.png

总结

image.png

RGB和16进制颜色转换

image.png

rgb转16进制

function rgbTohex(rgb) {
   // split的参数可以是正则
  const rgbArr = rgb.split(/[^\d]+/);
  const color = rgbArr[1]<<16 | rgbArr[2]<<8 | rgbArr[3];
  return "#"+color.toString(16)
}

image.png

image.png

16进制转rgb

function hexToRgb(hex) {
  let newHex = hex.replace("#","0x"),
  r=newHex >> 16,
  g=newHex >> 8 & 0xff, // & 0xff(255),用于丢高位
  b=newHex & 0xff;
  return `rgb(${r},${g},${b})`
}

image.png

浮点数运算

进制转换

十进制转二进制

整数部分:除2取余,逆序排列

小数部分:乘二取整,顺序排列

以9.375为例,结果为1001.011

整数部分:1001

image.png

小数部分:011

image.png

console.log((9.375).toString(2)) // 转换为二进制确实是1001.011
二进制转十进制

整数部分:从右往左,用二进制的每个数乘2的相应次方递增

小数部分:从左往右,用二进制的每个数乘2的相应负次方递减

image.png

二进制浮点数算术标准

双精度64,类似科学计数法

image.png 符号位S:1表示负数,0表示正数

指数位E:E=指数+1023(偏移码)

尾数部分M:1<=M<2,隐含的以1开头,默认存储1后面的部分

image.png

image.png

浮点数运算

1、对阶: 保证指数位数字一致

123.5+1426.00456 => 1.235102 + 1.42600456103;这里的阶指的是指数部分,分别是2和3,按照小阶对大阶的规则往3靠拢,变成0.1235103 + 1.42600456103

精度可能丢失,小阶对大阶会右移导致精度丢失;相加或者相减值可能会溢出

2、尾数运算: 尾数进行相加减,1.54950456

3、规格化: 尾数相加减可能会进位,所以需要再次规格化;右移动就会丢失精度

4、舍人处理: 如果右移超出,计算机会保留,到舍入处理的时候会再拿出来进行舍入处理

5、溢出判断: 是否超过最大整数

0.1+0.2

0.1转二进制

image.png

规格化:0.000110011(0011)n => 1.10011001(1001)n2-4

符号位S:0正数

指数E:1023 - 4 = 1019 (01111111011)

尾数M:1进0舍

image.png

image.png

image.png

然后经过之前的一系列运算得到规格化的数,然后再转为十进制

正确计算0.1+.02

1、将数字转换成没有小数位进行计算,然后再变成小数 0.110+0.210=3/10

2、使用toFixed(num):四舍五入

3、判断是否存在精度丢失:判断0.1+0.2-0.3是否小于Number.EPSILON