变量篇
数据类型
Js数据类型分成基础类型和引用类型两大类。
下图说明了基础类型和引用类型在堆栈中的情况:

基础类型
基础类型包括:
- undefined
- null
- string
- number
- boolean
- symbol
undefined 是表示变量未赋值时,此时该变量的值默认是 undefinednull 在类型判断中是 Object ,但不是对象,没有属性和方法symbol 是 ES6 新增类型,可以创建一个独一无二的值且不是字符串。具有全局的唯一性、隐藏性。
基础类型是存于栈中。且值不可改变,因为栈中存储的是本身的值,当改变时,就是新的变量,之前将被回收。
引用类型
引用类型能指对象类型,如object,function等等。
引用类型在栈中存放的是引向堆中的内容指针。当引用类型a赋值给其它变量b时,a和b中存储的都是同一引用指针,所以变量b是跟a是指向的同一内容。
对象又分成 原生对象、宿主对象。
原生对象包括:
- Number
- Boolean
- String
- Object
- Function
- Array
- RegExp
- Error
- Date
- Math
- JSON
- Global
- Arguments
宿主对象:一般指宿主如浏览器,由宿主框架通过某种机制注册到JavaScript引擎中的对象。
- Window
- Image
类型判断
方法一:typeof
typeof 一般只能判断基础类型(null除外)。
typeof 1 // "number"typeof '1' // "string"typeof true // "boolean"typeof false // "boolean"typeof Symbol('hello') // "symbol"typeof undefined // "undefined"typeof null // "object"typeof {} // "object"typeof [] // "object"typeof NaN // "number"
方法二:instanceof
instanceof 是通过原型链来判断类型的。通过原型一层一层的往上找,直到找到为止。如果到上顶层都未找到都表示对象类型不同。
instanceof 一般用来判断对象具体是什么类型,如 object/function/array 等
对于基础类型而言,如果不是
new的那么是等于Flase的。
// 基础类型必须是new才会相同String('1') instanceof String // falsenew String('1') instanceof String // trueNumber(1) instanceof Number // falsenew Number(1) instanceof Number // true// 引用类型function Person() {}let student = new Person()student instanceof Person // true// 引用类型二function Person() {}function Student() {}Student.prototype = new Person()let xiaowang = new Student()xiaowang instanceof Student // truexiaowang instanceof Person // trueStudent instanceof Person // false
方法三: constructor
可对基础类型和引用类型使用,但不能对 undefined、null 使用,报错 TypeError: Cannot read property 'constructor' of undefined
('1').constructor === String // true(1).constructor === Number // true(true).constructor === Boolean // true(0).constructor === Boolean // false({}).constructor === Object // true([]).constructor === Array // true(new Date()).constructor === Date // true
方法四: Object.prototype.toString.call
它不能检测非原生构造函数的构造函数名,也就是自定义函数之类只能检测出是object,而不能检测出具体的的是什么对象。
Object.prototype.toString.call('1') // "[object String]"Object.prototype.toString.call(1) // "[object Number]"Object.prototype.toString.call(0) // "[object Number]"Object.prototype.toString.call(false) // "[object Boolean]"Object.prototype.toString.call({}) // "[object Object]"Object.prototype.toString.call([]) // "[object Array]"
变量提升
在编译阶段前,会对 var 声明的变量进行提升到当前作用域的最顶端。且 var 的可声明多次,后面会覆盖前面的。
console.log(a) // undefinedvar a = 'hello'// 上面代码等价于下面这种var aconsole.log(a)a = 'hello'
let 和 const 不会有变量的提升,且只能声明一次,如多次声明,将会报错。
暂时性死区:let / const 会使区块形成封闭的作用域。若在声明之前使用变量,就会报错。
const 在声明是必须同时赋值,不赋值报错。声明的是基础类型时,不可改变值内容,当声明的是引用类型时,可改变属性值。
let a = 1let a = 2 // Error Uncaught SyntaxError: Identifier 'a' has already been declaredconst b; // Error: Missing initializer in const declarationconst a = 3; // Error
let/const/var 区别
var会进行声明提升到执行上下文作用域顶端,let/const则不会。var可重复声明,后声明的覆盖前面的。let/const重复声明会报错。var/let声明是可不赋值,默认是undefined,const则必须赋值,不赋值报错。- 作用域区别,
var是当前执行上下文之内都可访问,但let/const拥有块级作用域,一般是当前的{}内的范围。
