变量类型和计算
JS中有哪些数据类型?
JavaScript共有八种数据类型,分别是 Undefined、Null、Boolean、Number、String、Object、Symbol、BigInt。
其中 Symbol 和 BigInt 是ES6 中新增的数据类型:
- Symbol 代表创建后独一无二且不可变的数据类型,它主要是为了解决可能出现的全局变量冲突的问题。
- BigInt 是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number 能够表示的安全整数范围。
值类型和引用类型的区别
这些数据可以分为原始数据类型或值类型(primitive data type)和引用数据类型(index data type):
- 栈:原始数据类型(undefined、boolean、number、string、symbol)
- 堆:引用数据类型(对象、数组、Null和函数)
null为特殊引用类型,指针指向为空地址;函数也是特殊引用类型,但不用于存储数据,所以没有“拷贝、复制函数”的说法。
两种类型的区别在于存储位置的不同:
- 原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;
let a = 100
let b = a
a = 200
console.log(b) // 100
- 引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
let a = { age: 20}
let b = a
b.age = 21
console.log(a.age) //21
堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:
- 在数据结构中,栈中数据的存取方式为先进后出。
- 堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。
在操作系统中,内存被分为栈区和堆区:
- 栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
- 堆区内存一般由开发者分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收。
typeof能判断哪些类型
- 识别所有值类型
- 识别函数
- 判断是否是引用类型(不可再细分)
null和undefined的不同点
当检测 null 或 undefined 时,注意相等(==)与全等(===)两个操作符的区别 (en-US) ,前者会执行类型转换:
typeof null // "object" (因为一些以前的原因而不是'null')
typeof undefined // "undefined"
null === undefined // false
null == undefined // true
null === null // true
null == null // true
!null //true
isNaN(1 + null) // false
isNaN(1 + undefined) // true
字符串拼接
何时使用===,何时使用==
==会自动类型转换让两者尽量相等,如0和''都可以转换成false
truly变量:!!a === true 的变量
falsely变量:!!a === false 的变量
JS中逻辑判断和if语句判断的不是true和false,而是truly变量和falsely变量。
手写深拷贝
- 注意判断值类型和引用类型
- 注意判断是数组还是对象
- 递归
原型和原型链
JS是一门基于原型继承的语言,不能和Java一样使用class继承。当然ES6推出了class语法,但只是一个语法糖,其本质还是原型继承。
class
- constructor
- 属性
- 方法
class Student {
constructor(name, number) {
this.name = name
this.number = number
}
sayHi() {
console.log(
`姓名 ${this.name},学号 ${this.number}`
)
}
}
// 通过类声明对象/实例
// new的时候会走constructor,把名字和学号赋给实例对象。
const xialuo = new Student('夏洛', 001)
继承
- extends
- super
- 扩展或重写方法
// 父类
class People {
constructor(name) {
this.name = name
}
eat() {
console.log(`${this.name} eat something`)
}
}
// 子类
class Student extends People {
constructor(name, number) {
super(name) // 不用自己处理,传给父类按父类处理
this.number = number
}
sayHi() {
console.log(
`姓名 ${this.name},学号 ${this.number}`
)
}
}
// 子类
class Teacher extends People {
constructor(name, number) {
super(name)
this.major = major
}
teach() {
console.log(`${this.name} 教授 ${this.major}`)
}
}
instanceof
原型
原型关系
- 每个class都有显示原型prototype
- 每个实例都有隐式原型__proto__
- 实例的__proto__指向对应class的prototype
基于原型的执行规则
- 获取属性xialuo.name或执行方法xialuo.sayhi()时
- 先在自身属性和方法寻找
- 如果找不到,则自动去__proto__中寻找
原型链
如何准确判断一个变量是不是数组?
手写一个简易的jQuery,考虑插件和扩展性
class的原型本质,怎么理解?