你不知道的JS中卷第一部分

142 阅读9分钟

你不知道的JS(中卷)第一部分

1.类型是什么,JS中有几种类型?

在《你不知道的JS》中是这样定义类型的:对语言引擎和开发人员来说,类型是值的内部特征,它定义了值的行为,以区别于其他值。比如我们会对42和“42”进行不同的操作,一般情况下我们对前者进行的是数学上的四则运算,对后者进行的是字符串的操作。这就决定了这两个东西必须是不同的类型。

JS中共有六种类型:Undefined,Null,Boolean, Number,String,Object

2.怎样理解函数和对象,数组和对象?

函数是可以被调用的对象,函数对象的length属性是声明的形参的个数。数组的length属性是元素的个数。

示例代码如下:

function foo(a,b){
  console.log("123")
}
console.log(foo.length)//2

var arr = [1,3,4]
console.log(arr.length)//3

3.值和类型

在JS中变量是没有类型的,只有值才有类型。typeof返回的是这个变量所持有的值的类型,而不是这个变量的类型,因为这个变量可以持有所有的类型。

4.undefined和undeclared

undefined是声明了但是没有定义,undeclared是根本就没有声明。

var a
console.log(a)//undefined
console.log(b)//ReferenceError: b is not defined
console.log(typeof a)//undefined
console.log(typeof b)//undefined

typeof一个未声明的变量是不会报错的,这样做有好处也有坏处,好处是这样更安全一下,坏处就是和我们一般情况下的理解不相符,容易用错。下面看一下我们是怎么利用这个好处的。

//这个data是否存在是视情况而定的
if(typeof data === 'undefined'){
  console.log('后端没有返回数据')
}else{
  console.log('后端返回数据了') 
}
//如果我们按照原来的方式来写的话就是:
if(data){
  console.log('后端没有返回数据')
}else{
  console.log('后端返回数据了') 
}
//这样写当后端没有返回data的时候,就会报错,让程序终止运行,这样的后果显然是我们不想看到的。

5.数组和字符串

JS中的字符串是不可以改变的,数组是可以改变的,并且对字符串某个字符的访问用a[1]这种方式在之前的IE浏览器中是不被允许的,最好的方式是a.charAt(1)。字符串不可变是指字符串的成员函数不会改变其原始值,而是创建并返回一个新的字符串,数组是可变的是指,数组的成员函数都是在其原始值上进行操作。

//call 方法第一个参数也是作为函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组。
var name = 'SIPC'
console.log(Array.prototype.join.call(name,'-'))//S-I-P-C
var res = Array.prototype.map.call(name,function(v){
  return v.toLowerCase()
})
console.log(res)//[ 's', 'i', 'p', 'c' ]

许多数组函数用来处理字符串都是很方便的,比如上面的例子。

6.数字

JS中只有一种数值类型:number,没有整形和浮点型之分,所有的数字都是双精度的。默认情况下,数值都是以十进制的形式显示,特别大或者特别小的数值用指数格式显示。

var a = 5E10
console.log(a)//50000000000
console.log(a.toExponential())//5e+10

由于数字值可以使用Number对象进行封装,所以数字值可以调用封装对象中的一些方法,代码如下:

var a = 5E10
//显示小数点后几位
console.log(a.toFixed(2))//50000000000.00
//显示的有效位是几位
console.log(a.toPrecision(3))//5.00e+10

JS中的进制:

var a = 0o123//八进制
console.log(a)
var b = 0b101011//二进制
console.log(b)

7.在JS中0.1+0.2===0.3吗?

不是的,js中的0.1并不是精确的0.1,而是一个很接近0.1的数,同理0.2也是,所以他们两个的和,也是一个很接近0.3的数,并不是0.3。那么怎样来判断0.1+0.2和0.3是否相等呢?这里我们引入一个名次,叫做“机器精度”Number.EPSILON。在机器精度这个误差允许的范围内相等,我们就认为是相等的

console.log(0.1+0.2===0.3)//false
console.log(Math.abs(0.3-0.1-0.2)<Number.EPSILON)//true

8.void 0 是什么?

我们可以通过void 0来获取undefined。当然是用void true也可以,或者void 1 ,undefined都是等效的。

var a = void 0
console.log(a)//undefined

9.NAN是什么,有什么特点。

NAN是number类型的一个值,这个值是数字运算出错之后的结果,他值得一提的地方是自身和自身并不相等。

var a = 2/0
console.log(a)//Infinity
var b = 2/console.log()//NaN
console.log(b===b)//false
console.log(Number.isNaN(b))//
console.log(Object.is(b, NaN))//true用来判断一个数是不是NaN
console.log(-3*0)//-0
console.log(Object.is(0,-0))//false

10.Date()和Error()

Date()获取时间戳,当前时间,时间格式化。

var a = new Date()
console.log(a.getTime())//1609208370882 时间戳
console.log(Date.now())//1609208370891  时间戳
console.log(Date())//Tue Dec 29 2020 10:19:30 GMT+0800 (GMT+08:00)
console.log(a.getFullYear(),a.getMonth()+1,a.getDate(),a.getHours(),a.getMinutes(),a.getSeconds())
//2020 12 29 10 30 26

Error()主要是为了获得当前运行栈的上下文。栈上下文信息包括函数调用找和产生错误代码的行号,以便于调试。错误对象通常与throw一起使用。

function foo(){
  if(true){
    throw new Error('这是一个错误')
  }
}
foo()

11.强制类型转换

我们需要掌握字符串,数字,布尔值之间的类型转换的规则。

  1. ToString()和JSON.Stringify()

    console.log("xxx".toString())//xxx
    console.log(JSON.stringify("xxx"))//"xxx"
    //一下是不安全的JSON,在对象中会将其忽略,在数组中被设置为null
    console.log(JSON.stringify(function fo(){}))//undefined
    console.log(JSON.stringify(undefined))//undefined
    console.log(JSON.stringify(Symbol()))//undefined
    console.log(JSON.stringify([1,Symbol(),undefined,function fo(){}]))//[1,null,null,null]
    var obj = {
        name:"zhaohe",
        age: undefined,
        sayHello: function(){
            console.log("hello")
        },
        id: Symbol()
    }
    console.log(JSON.stringify(obj))//{"name":"zhaohe"}
    
    //下面是JSON.Stringify()的两个有用的参数
    console.log(JSON.stringify(obj,['name','age']))//{"name":"zhaohe","age":19}数组中有什么就序列化什么
    console.log(JSON.stringify(obj,function(k,v){
        if(k!=='name'){
            return v
        }
    }))//{"age":19,"Id":"20201101"}相当于过滤一下
    console.log(JSON.stringify(obj,null,3))//缩进为3
    // {
    //     "name": "zhaohe",
    //     "age": 19,
    //     "Id": "20201101"
    //  }
    console.log(JSON.stringify(obj,null,"---"))//缩进用最后一个参数的代替
    // {
    // ---"name": "zhaohe",
    // ---"age": 19,
    // ---"Id": "20201101"
    // }
    

    JSON.Stringify()和toString()的效果基本相同,只不过序列化的结果总是字符串。

    将一个数字转为字符串可以通过数字+空串的方式,或者直接String(数字),前者对于对象来说是调用的valueOf(),没有这个函数再调用toString(),后者是直接调用toString().

  2. ToNumber()

    将一个对象类型的值,转成Number时,会先调用这个对象的valueOf()方法,如果没有就调用这个对象的toString()方法,如果还是没有就会报错(TypeError)或者返回NaN.

    console.log(Number('42'))//42
    console.log(typeof +"3.14")//number
    console.log(Number([4,2]))//NaN
    console.log(Number("xxx"))//NaN
    console.log(Number([]))//0
    //重写数组的toString()方法
    var c  =[4,2]
    c.toString = function(){
        return this.join('')
    }
    console.log(Number(c))//42
    
    //Number()和parseInt()的区别
    //parseInt只针对字符串,传入true或者对象都不能处理
    console.log(Number("23xxx"))//NaN
    console.log(parseInt("23xxx"))//23
    console.log(parseInt([]))//NaN
    console.log(parseInt(true))//NaN
    

    tips:true转换为1,undefined转换为NaN,null转换为0

    将一个纯数字字符串转为数字可以通过字符串-0,来达到目的,或者字符串*1,都是一个道理。

  3. ToBoolean()

    JS中的值可以分为一下两类:

    1.可以被强制类型转换为false(有false,空串,0,undefined,NaN,null)

    2.其他(被强制类型转换成false的值)

    假值对象是什么?

    假值对象不是封装了假值的对象,而是值一个对象转为boolean后为false,这样的对象有且仅有一个就是document,all这是由DOM提供的方法,并不是JS引擎提供的。

    转换示例如下:

    var arr = []
    console.log(Boolean(arr))//true
    console.log(Boolean(''))//false
    console.log(Boolean(null))//false
    console.log(Boolean(undefined))//false
    console.log(Boolean(NaN))//false
    console.log(Boolean(false))//false
    console.log(Boolean(0))//false
    console.log(Boolean(document.all()))//false 必须在浏览器环境下运行
    
    //我们常用的类型转换方式是!!
    console.log(typeof !!"")//boolean false
    console.log(typeof !![])//boolean true
    

    我们在if()的中括号中写条件的时候,如果用到不是boolean的情况,建议用!!显示转为boolean这样可以提高代码的可读性,而不应该依赖于隐试类型转换。

12.~运算符及应用

~x = -(x+1)

~是对一个数所有位取反,包括符号位,等到的数再取补码。

console.log(~42)//-43

应用:一些函数如:indexOf()在查找失败的时候返回-1,这时候我们通过~运算符就可以将-1转为0,也就是用一个假值0代表失败的情况,其他的情况都是成功。示例代码如下:

function search(x){
    var a = 'hello'
    if(~a.indexOf(x)){
        console.log('success',a.indexOf(x))
    }else{
        console.log('fail')
    }
}
search('ol')//fail
search('lo')//success 3

13.逻辑运算符&&和||

这两个逻辑运算其实更适合叫做“选择器运算符”,因为他们的返回值不是布尔类型的,而是左右操作数中的一个!这是不同于C语言的。

&&的优先级高于||,||的优先级高于三目运算符

var a = 42
var b = 'abc'
var c = null
var d = undefined
console.log(a||b)//42
console.log(a&&b)//abc
console.log(c||b)//abc
console.log(c&&b)//null
console.log(d||d)//undefined
//所以我们在把这种表达式当成条件的时候,可能和我们原来理解的不一样
if(a||b)//将42隐试类型转换为true
{
    console.log("123")
}
if(c||d)//将undefined隐试类型转化为false
{
    console.log("456")
}

我们可以这样理解:这两个操作符返回的结果是“能够判断这个表达式真假的时候的那个值”,这句话可能有点绕,我们解释一下:||是一真则真,有一个是真的,这个表达式就已经有结果了,&&同类一假则假。console.log(a||b)当第一个数a为真的时候,这个表达式已经可以判断真假了,所以到此结束,返回a。console.log(a&&b)当第一个数为真的时候,并不能判断真假,还要看第二个数,当我们看到第二个数的时候,已经可以判断真假了,到此结束,返回第二个数。其他同理!

14.宽松相等和严格相等

宽松相等和严格相等我们一般理解他们的区别是:==检查值是否相等,===检查值和类型是否相等。而正确的解释是:==允许强制强制类型转化,而===不允许强制类型转换。

不同的基本类型之间比较的话,都会把基本类型转为number类型再比较,示例代码如下:

console.log('42'==42)//true
//解析:‘42’转为数字类型是42,42和42相等
console.log('42'==true)//false
//解析:‘42’转为数字类型是42,true转为数字类型是1,42和1不相等
console.log('42'==false)//false
//解析:‘42’转为数字类型是42,false转为数字类型是0,42和0不相等
console.log(42==true)//false
//解析: true转为数字类型是1,42和1不相等
console.log(42==false)//false
//解析: false转为数字类型是0,,42和0不相等
//以下是undefined和null的比较,undefined和null是相等的,和除了他们两个之外的值是不等的。就是说在==运算符中这两个是一类。
console.log(undefined == null)//true
console.log(undefined == '')//false
console.log(undefined == false)//false
console.log(undefined == 0)//false
console.log(null == '')//false
console.log(null == false)//false
console.log(null == 0)//false

15.逗号操作符

对它的每个操作数求值,并返回最后一个操作数的值;

var b = (3,2,4)
console.log(b)//4

应用:

1.一般在for循环中使用,比如一个循环要设置多个变量的增减情况

2.在返回值里面使用,比如要返回一个值之前需要对这个值进行加一操作

return(x++,x)