本文简介
-
前端三座大山是HTML、CSS、JS,而Javascript是前端最核心的部分。
-
一般来说,完整的JavaScript=ECMAScript+DOM+BOM
-
让我们进入JS的深入学习旅程吧
js数据类型
数据类型有哪些?有什么特点?
-
最新的 ECMAScript 标准定义了8种数据类型:
-
七种基本数据类型 「值类型」:
-
布尔值(Boolean),有2个值分别是:true 和 false.
-
null , 一个表明 null 值的特殊关键字。JavaScript 是大小写敏感的,因此 null 与 Null、NULL或变体完全不同。
-
undefined ,和 null 一样是一个特殊的关键字,undefined 表示变量未赋值时的属性。
-
数字(Number),整数或浮点数,例如:42 或者 3.14159。
-
任意精度的整数 (BigInt) ,可以安全地存储和操作大整数,甚至可以超过数字的安全整数限制。
-
字符串(String),字符串是一串表示文本值的字符序列,例如:"Howdy" 。
-
代表(Symbol) ( 在 ECMAScript 6 中新添加的类型)。一种实例是唯一且不可改变的数据类型。 补充:
typeof Symbol() === 'symbol'; // true Symbol('key') !== Symbol('key'); // true Symbol('key') === Symbol('key'); // false
-
-
一种引用类型「对象(Object)」 包括:Array Function Date
特点:
-
值类型的赋值,实际就是值的拷贝
-
引用类型的赋值,实际就是地址的拷贝
热身训练
请说出以下代码打印的结果
if (1 == true)
console.log(1)
if (1 === true)
console.log(2)
if ([])
console.log(3)
if ([] == [])
console.log(4)
if ([] === [])
console.log(5)
if (undefined == null)
console.log(6)
if ('' == null)
console.log(7)
if (NaN == NaN)
console.log(8)
-
解析:undefined == null ?两者都是无效值。js规范规定,在比较相等性之前,undefined和null不能转化成其他类型的值,且undefined和null是相等的。
-
解析:undefined === null ?两者不是同一数据类型。== 比较的是值, === 比较的是值和数据类型
typeof undefined // undefined typeof null // object
-
解析:'' == null ?
-
null: 该值声明的是一个空对象,没有指向任何的内存空间。
-
'':该字符串声明的是一个对象实例,该实例是一个长度为0的字符串
-
拓展:str = '' 放在栈内存 str = String('') 指向堆内存
-
-
解析:NaN == NaN ?
-
NaN属性(not a number)是代表非数字值的特殊值。
-
任何值和NaN做比较都是false。
-
任何数和NaN做运算,结果都为NaN。
-
NaN不和任何值相等,包括它本身
console.log(isNaN(NaN)) //true console.log(isNaN(10)) //false console.log(isNaN('20')) //false 将'20'转为数字类型20 console.log(isNaN('abc')) //true console.log(isNaN(true)) //false 将true转为1
-
浅拷贝与深拷贝
-
浅拷贝:增加了一个指针指向已存在的内存地址
-
深拷贝:增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存
-
举个栗子🌰
const a = [1,2,3]; const b = a; b[0] = 5;
a = ? // [5, 2, 3]
-
这是浅拷贝,因为a和b指向同一块内存地址。当a赋值给b时, 只是将a的数据指针赋值给b,并没有开辟属于b的内存空间。
-
如果是深拷贝,应该为b开辟独立的内存空间,并且将a的内容拷贝过来。两者互不影响。
深拷贝的实现
let obj = {
name: 'kk',
bf: ['a', 1],
a() {
console.log('d')
},
offer: null
}
function deepClone(origin, target={}) {
const toStr = Object.prototype.toString,
arrStr = "[object Array]"
for(let prop in origin) {
if(origin.hasOwnProperty(prop)) {
if(origin[prop] !== null && typeof origin[prop] === 'object') {
target[prop] = toStr.call(origin[prop]) === arrStr ? [] : {}
deepClone(origin[prop], target[prop])
} else {
target[prop] = origin[prop]
}
}
}
return target
}
let ans = deepClone(obj)
ans.offer = 'xxx'
console.log(ans, obj)
typeof 和 instanceof 的区别
-
typeof用于判断变量的类型
-
数值类型 typeof 2 返回 number
-
字符串类型 typeof 'ac' 返回 string
-
布尔类型 typeof true 返回 boolean
-
对象、数组、null, 返回 object
-
函数 typeof eval 、typeof Date 返回 function
-
不存在的变量、函数或者undefined, 返回 undefined
-
instanceof判断某个对象是否被某个函数构造
区别:
-
typeof采用引用类型存储值时出现问题,无论引用的是什么类型的对象,都会返回object
-
es引入java的instaceof解决问题
-
instanceof与typeof相似,用于识别正在处理的对象类型。
-
不同的是,instaceof要求开发者明确地确认对象为某特定类型
== 和 === 有什么区别?
-
==只判断值是否相等
-
===判断值是否相等,类型是否相同
数组、对象那些事
判断数组类型的方法
-
Array.isArray(arr) => true
-
Object.prototype.toString.call(arr) => "[object Array]"
-
arr instanceof Array => true
-
arr.constructor == Array => true **instanceof和constructor,必须在当前页面声明。如果是父页面引入iframe,也判断不出来**
函数中的 arguments 是数组吗?
-
arguments是类数组,原型(proto)指向的是Object;而真正数组指向Array。
-
document.getElementByTagName 返回的也是类数组,原型指向HTMLCollection.
如何将函数中的arguments转化为真正的数组?
-
Array.from(arguments)
-
[].slice.call(arguments)
-
扩展运算符(当数组或者对象只有一层的时候,意思是不存在数组嵌套对象,或者嵌套数组这种情况,拷贝是深拷贝。除了第一层是深拷贝,其它层都是浅拷贝) [...arguments]
-
[].concat.apply([],arguments)
-
Array.of(...arguments)
-
Array(...arguments)
Array的forEach等用法
-
forEach:遍历数组(for)
-
map: 返回一个数组,不改变原数组的内容
-
every:每个元素都符合条件,就返回true
arr.every((val, index, array)=>val=='a')
-
some: 只要有一个元素符合条件,就返回true
arr.some((val, index, array)=>val=='a')
-
filter: 返回一个数组,里面都是符合条件的元素。
arr.filter((val, index, array)=>val=='a')
-
reduce: 返回一个数 可进行递归、叠加、阶乘,从左到右 (reduceRight 从右到左)
arr.reduce((prev,cur,index,arr)=>{ // 加法 // return prev+cur // 阶乘 // return Math.pow(prev,cur) return prev**cur })
如何遍历一个对象?
-
for(let prop in obj)
-
object.keys(obj); object.values(obj)
-
object.getOwnPropertyNames(obj)
闭包与作用域
“
闭包就是能够读取其他函数内部变量的函数
”
请实现一个“有缓存功能”的加法
let add = (()=>{
let sum = 0
return n=>sum += n
})()
console.log(add(5), add(6), add(1))
什么是作用域?细分为哪些作用域?
浏览器给js的生存环境叫作用域。
-
函数作用域
-
在函数调用的时候,会创建函数作用域。调用完会摧毁
-
每一次调用函数都会创建一个函数作用域,并且相互独立
-
函数作用域可以访问全局作用域的变量,全局作用域不可以访问函数作用域的变量
-
函数内访问变量,会从自身函数作用域内找,找不到就往上一级作用域找,直到找到全局作用域。如果还是找不到,就返回ReferenceError
-
在函数作用域内要访问全局变量,可以使用window
-
-
全局作用域
-
块级作用域(下一栏目)
let、const、var的区别?
-
什么时候提出?
-
var是es5提出的,let、const是es6提出的
-
变量提升
-
var能够进行变量提升,let、const不可以
-
暂时性死区(TDZ)
-
在块级作用域内,let、const具有暂时死区,一进入作用域内,变量就已经存在,但是在变量声明前不能被访问或者调用,否则会报错 ReferenceError
-
重复声明
-
var可以重复声明
-
let、const不可以
-
是否存在块级作用域
-
var不存在(1、内部变量可能会覆盖外部变量2、用于计数的循环变量泄露为全局变量)
-
let、const存在
-
声明的变量能否被修改
-
var和let可以 const不可以,一旦声明必须立即初始化
更多精彩内容,请关注公众号。
前端交流群(群里大佬如云,会经常分享优秀的文章,前端路上,结伴同行~)