javascript 数据类型+变量声明

昨天写了本身这三个月以来的面试总结,收到了许多人的喜欢,其实我更多的是把此次找工做看成一个全面复习巩固的过程,复习资料的获取一方面是本身总结,另外一方是查看其余人总结的比较全面的内容,另外若是时间容许的状况下,仍是很喜欢看书的;javascript

       数据类型判断以及变量声明在js中是最基础的了,在基础内容中,我会标注一些你们容易忽略的点;java

javascript数据类型

图1 数据类型脑图

类型区分

基本类型

  • number 数字类型 包含整数和浮点数
  • string 字符串类型
  • boolean 布尔类型
  • null 表示空值,一般是已声明的变量未有明确的值的含义
  • undefined 未定义,使用var声明了变量,但未给变量初始化值,那么这个变量的值就是undefined
  • symbol js新增类型,键值对存储方式,具备惟一性

引用类型

引用类型的大类可分为Object类型,进行细分能够分为Object、Array、Date、Function等;面试

数据存储方式

正式由于数据存储方式,因此才会有了引用类型的身拷贝和浅拷贝;
在js的存储中,js有两种的数据存储方式,基本类型是存储在栈中,引用类型是存储在堆中;数组

栈内存

基本数据类型存储在栈内存中,是按照值进行访问的;浏览器

var a = '1'; //变量对象
var b = 3 //变量对象
var str = '我是变量'
复制代码
图2 基础类型存储方式

当访问a的时候,会直接进行值的访问
当变量的值修改的时候,系统会从新为其赋值,开辟了一个新的空间存储值,变量名直接等于变量值,而被修改的原始变量值,会在内存回收中进行回收;markdown

堆存储

引用类型的值保存在堆内存中的对象,值的大小不固定,栈内存中存放地址,指向堆内存只可以的对象,按照引用进行访问;函数

var obj = {
  a:2,
  b:33
}
var arr = [
  2,3,4
]
复制代码

js不容许直接访问堆内存中的位置,所以咱们不能直接操做对象的堆内存空间。在操做对象时,其实是在操做对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的。oop

图3 堆内存存储数据方式

所以 当咱们访问引用类型的时候,是先找到当前存储值的地址,而后在经过地址访问到数据的值;post

值的复制

基本类型

变量中的数据发生拷贝的时候,系统会自动为新的变量分配一个值,最后这些变量都是相互不影响的;测试

var name ='mfy'
var editName = name;
editName = 'yyy'
复制代码
图4 基本类型值的复制

复制后的值是系统从新分配的,不会影响到原始被复制的值;

引用类型复制

引用类型的复制又分为深复制和浅复制; 此时咱们只说浅复制;

var personalMsg ={
  name:'mfy',
  age:22,
  offer:'fy'
}

var clonePer = personalMsg;
personalMsg.name = 'yyy'
复制代码
图5 引用类型值的复制

深拷贝仍是浅拷贝

  • 当咱们改变子对象(复制出来的新对象)时,父对象(被拷贝的对象)也会跟着改变的拷贝,称为浅拷贝。也就是说,子对象和父对象在浅拷贝的时候他们指向同一个内存的对象。
  • 深度拷贝就是把父对象拷贝到子对象上,并且二者的内存和之后的操做都互不影响的拷贝!

类型转换

当咱们在使用某些数据变量时候,会自动发生一些类型的转换;js自己为弱类型,一般在使用的时候,不当心就会出现类型转换;

运算符号的隐式转换

所有都是+号

  • 包含+ - 操做的时候进行转换
  • 字符串两边存在+的时候,相邻均被转换成string类型
1+'2' // '12'
1+3+'3' // '43'
'3'+1+2 //'312'
2+1+false // 3
2+1+true  // 4 
3+1+{a:2} // 4[object Object]
复制代码
  • 保持从前向后的运算顺序
  • 存在字符串的时候,会将先后两个进行类型转换String
  • 若是+号存在则会将false 转化成0 true转化成1
  • 存在引用类型,会将其转化为toString格式,在进行相加

存在-号时候

+在字符串使用会当成连接符号,而-则是直接进行类型转换

1-'2' // -1
1+3-'3' //1 
'3'+1-2 // 29
2+1-false // 3
2+1-true  // 2
3+1-{a:2} // NaN
复制代码
  • 存在-的时候会将两边非数字类型转化为数字类型
  • 从前日后计算模式

==比较

  1. x、y均为number

1 == 1 //true 2. x 、y 类型不相同

1=='1' //true
1==true  //true
复制代码
  • boolean的时候会被转化成 0/1

3.存在对象比较时候

1 =={a:3}  //false
1 == {valueOf:()=>{return 1}} //true
复制代码
  • 存在对象时候,若是对象无valueOf属性,则直接比较
  • 存在valueOf的时候,则会比较valueOf内容的值;

判断类型的方式

typeof

主要用于基本数据类型比较,包含基本数据类型

图6 typeof判断数据类型

对于null 是浏览器一直存在的这个问题

typeof null //"object"
复制代码

typeof判断引用类型,判断引用类型的时候失效了

图7 typeof判断引用类型失效

Object.prototype.toString.call(XXX) 引用类型判断

console.log(
  Object.prototype.toString.call(null),'\n', //[object Null] 
  Object.prototype.toString.call(11),'\n', // [object Number]
  Object.prototype.toString.call(false),'\n', // [object Boolean]
  Object.prototype.toString.call('333'),'\n',  // [object String]
  Object.prototype.toString.call([3,4,2,2]),'\n', // [object Array]
  Object.prototype.toString.call({a:3,b:44}),'\n', // [object Object]
  Object.prototype.toString.call(new RegExp('.*?')),'\n',  //[object RegExp] 
  Object.prototype.toString.call(new Promise((resolve,reject)=>{resolve(2)})),'\n', //[object Promise]
)
复制代码

此方式可以判断出不论是引用类型仍是基本类型都可以判断出来

instanceof

此方式可以判断的是原型链上的连接关系

function Super (){
  this.name = 'myyu'
}
let superNew = new Super();

console.log(superNew instanceof Super) //true

console.log(superNew instanceof Object) //true

console.log(superNew instanceof Array) //false
复制代码

比较常见的就是

写instanceof的实现

function myInstanceof(left,right){ 
  if(!right || !left) return false;  
  //左侧的实例进行查找
  let pro = left.__proto__;
  //获取右侧的原型
  let prototype = right.prototype;  
  while(pro){
    if(pro == prototype){
      return true
    }
    pro = pro.__proto__;
  }
  return false;
}
复制代码

其余方式

判断数组

Array.isArray([1,2,3]) //判断是不是数组
isNaN(333) //false 
isNaN(underfined+1) //true
复制代码

变量声明

做用域

做用域知识很是重要,内容比较多,这里只简单说起,具体的内容后续补充

变量声明的三种方式

var

可以定义在全局的变量

console.log("全局1:"+golbalA)
 var golbalA = 5;
 console.log("全局2:"+golbalA)

复制代码
图8 var变量声明

定义在函数内部

var 定义声明的变量是能够进行变量提高的,所以第一个打印出undefind

console.log("全局1:"+golbalA)
    var golbalA = 5;
    console.log("全局2:"+golbalA)
    function a (){
      console.log(golbalA)
    }
    a()
复制代码
图7 var变量声明在函数内部

全局定义的变量在函数中若是无同名的变量也能够访问;

console.log("全局1:"+golbalA)
    var golbalA = 5;
    console.log("全局2:"+golbalA)
    function a (){
      var golbalA =2222
      console.log(golbalA)
    }
    a()

复制代码
图8 var函数内部自定义的变量
  • 定义在全局的变量可以在函数做用内访问
  • 定义在函数内部的变量只能函数内部访问

let

定义在全局中

console.log("全局1"+letA)
  let letA = "global";
  console.log(letA)
复制代码

直接告诉咱们不可以进行使用,在变量未初始化以前

图9 let变量声明

定义在函数内部中

let letA = "global";
  console.log(letA) //global
  function a(){ 
    console.log(letA)//global
  }
  a()
复制代码
let letA = "global";
  console.log(letA)//global
  function a(){
    let letA = 'function'
    console.log(letA) //function
  }
  a()
复制代码
  • 定义在全局的变量可以全局访问
  • 定义在函数内部的变量外部不能访问

定义在块级做用域中

if(true){
    let globala = 'globala'
    var globalb = 'globalb'
  }
  console.log('globala',globala)
  console.log('globalb',globalb)

复制代码
图10 let变量声明

此时就是用let定义在块级做用域的变量,没法在块级之外进行修改;而var是能够的;

let的暂时性死区

暂时性死区是常常忽略的问题,

var a =222
 if(true){
   a = 33;
   let a =44
 }
复制代码
图11 let存在变量声明
- 只要块级做用域内存在 let 命令,它所声明的变量就“绑定”(binding)这个区域,再也不受外部的影响。上面的代码中,块级做用域内 let 又声明了一个局部变量 a ,致使后者绑定这个块级做用域,因此在 let 声明变量前,对 a 赋值会报错。 - ES6明确规定,若是区块中存在 let 和 const 命令,这个区块对这些命令声明的变量,从一开始就造成了封闭做用域。凡是在声明以前就使用这些变量,就会报错。

const

定义常量

const a = 3333;
  console.log(a)
  a= 444
复制代码
图12 const定义常量

由const定义的变量是没法进行更改的

定义变量

const a;
  console.log(a)
复制代码
图13 const定义常量必须赋值

修改定义的值

const定义的基础类型是没法修改的,可是定义引用数据类型的时候;

const obj ={
    a:22,
    b:444
  }
  console.log(JSON.stringify(obj) )
  obj.a = 'mayy'
  console.log(JSON.stringify(obj) )
复制代码
图14 const定义常量能够修改

const 的暂时性死区

if(true){
   a=3;
   const a=5
 }
复制代码
图15 const存在暂时性死区

const 总结

  • const 定义的基本类型常量一旦定义没法修改
  • const 声明变量必须进行定义
  • const 存在暂时性死区

变量提高

变量提高其中能够去排列组合测试下🥳🥳

  • var 存在变量提高,容许在声明前使用,let、const不可以在进行使用
  • var的变量会挂载到windos上,而let、const不会挂载;
  • let、const只能进行一次变量声明,后面不能够在进行声明同名字的变量
  • const的变量一经赋值,将不会在进行使用,除了引用类型除外;

面试常见问题总结

js数据类型

  • 基本类型和引用类型的区别
  • 存储方式 堆、栈存储区别和联系
  • nullundefined 的区别
  • 类型方式判断typeof、instanceof
  • 手写instanceof实现
  • 类型转换:隐式转换强制转换
  • 引用类型复制、拷贝、深浅拷贝

变量声明

  • 变量声明而生成的做用域
  • 暂时性死区 的含义以及生成方式
  • letconst 生成的做用域区间
  • 常见let 、const使用方式

参考文档

js隐式类型转换 《javascript 高级程序设计(第四版)》

相关文章
相关标签/搜索