typeof能判断什么类型
- 能够判断所有的值类型
- 能够判断是否为引用类型
- 不能够判断细分引用类型,如
typeof
数组只能认定为object
数据类型有哪些,对symbol有了解嘛
-
基本数据类型:
string
、number
、Boolean
、undefined
、null
-
复杂数据类型:
Object
-
ES6新增数据类型:
symbol
、Map
、Set
- 其中symbol是基本数据类型,每一个symbol都是一个全局唯一的字符串
// 在一个块级作用域里使用symbol,创造一个隐藏属性 { let a = Symbol(); let object = { name : 'okaychen', age : 3, [a] : '隐藏属性' } window.object = object }
- set是object里面的一种,set里无论原始值还是引用类型的值,重复的都只会保留一个
- Map可以允许任何类型作为对象的键,弥补了object只能使用字符串作为键(注意Map是ES6中的一种数据结构,区别于数组方法map)
值类型和引用类型有哪些区别
- 值类型: 字符串
string
,数值number
,布尔值boolean
,null
,undefined
- 引用类型: 对象
Object
,数组Array
,函数Function
值类型:
- 占用空间固定,保存在
栈
中:当一个方法执行时,每个方法都会建立自己的内存栈,也就是所谓的函数作用域,基础变量的值是存储在栈中的,而引用类型变量存储在栈中的是指向堆中的数组或者对象的"地址" - 保存与复制的是值本身
- 可以用**
typeof
**检测值类型 - 基本数据类型是值类型
引用类型:
- 占用空间不固定,保存在
堆
中:由于对象的创建成本比较大,在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用,这个运行时数据区就是堆内存 - 保存与复制的是指向对象的一个指针
- 使用**
instanceof()
**检测数据类型 - 使用
new()
方法构造出的对象是引用型
判断一个变量是否为数组
-
Array.from()
es6 语法
-
arr instanceof Array
instanceof 实际是通过原型链进行查找
实现一个instanceof
实现原理:
- 每个构造函数都有显示原型
prototype
- 每个实例对象都有隐式原型
__proto__
- 实例对象的隐式原型指向构造函数的显示原型
A instanceof B
function instanceof1(A,B){
B = B.prototype
A = A.__proto__
while(true){
if(A === B){
return true
}
if(A === null){
return false
}
A = A.__proto__
}
}
分别说一下数组中常用的方法
数组也是一种数据类型,类比数据类型的学习我们可以从其特性,增删改查,其他方法,支持的运算符七个方面来学习,可以明显提高效率
数组的方法我们除了作用以外,我们还比较关心的就是该数组方法是否改变原数组,下面就按照这个规则来分类:
// 改变原数组的方法:
pop() // 删除数组中的最后一个元素,把数组长度减 1,并且返回它删除的元素的值
push() // 该方法可把它的参数顺序添加到数组的尾部。它直接修改数组,返回后修改数组的长度
reverse() // 将数组元素倒序,改变原数组
unshift() // 可以向数组开头增加一个或多个元素,并返回新的长度
shift() // 数组的第一个元素从其中删除,并返回第一个元素的值,减少数组的长度
sort() // 在原数组上进行排序,不生成副本
splice(start,删除的个数,插入的元素) //可删除从index处开始的零个或多个元素,并且用参数列表中声明的一个或多个值来替换那些被删除的元素
// 不改变原数组:
concat() // 用于连接两个或多个数组,不改变原数组,返回一个新的数组
join() // 将数组中的所有元素都转化为字符串并拼接在一起,默认使用逗号,返回最终生成的字符串
map() // 对数组的每一项运行给定函数,返回每次函数调用的结果组成的数组,不改变原数组
indexof // 返回指定位置的元素值或字符串,通过搜索值与下标寻找
every() // 如果每一项都为true,则返回true
some() // 某一项返回true,则返回true
forEach() // 对数组的每一项运行给定函数,没有返回值
var、let、const的区别
- var是es5的语法,let 、const是es6新增的语法
- var会进行变量提升,let、cosnt不会产生变量提升
- var的作用域是全局的,let、const的作用域是作用于块级元素范围内。
实现一个深拷贝
function deepClone(obj){
if(typeof deepClone !== "object" && obj !== null){return obj}
let result
if(Array.from(obj)){
result = []
}else{
resulet = {}
}
for(let key in obj){
if(obj.hasOwnProperty(key)){
result[key] = deepClone(ojb[key])
}
}
return result;
}
什么时候用==,什么时候用===
-
因为会做隐式类型转换,所以会带来不必要的问题。所以除了null之外,其他一律使用===
if(obj.a == null){}相当于if(obj.a === null || obj.a === undefined) {}
defer和async的区别
- defer 和 async 在网络读取(下载)这块儿是一样的,都是异步的(相较于 HTML 解析)
- 它俩的差别在于脚本下载完之后何时执行(defer的执行是在所有元素解析完成之后,
DOMContentLoaded
事件触发之前完成。async不等待后续载入的文档元素读到就加载并执行),显然 defer 是最接近我们对于应用脚本加载和执行的要求的 - 关于 defer,此图未尽之处在于它是按照加载顺序执行脚本的,这一点要善加利用
- async 则是一个乱序执行的主,反正对它来说脚本的加载和执行是紧紧挨着的,所以不管你声明的顺序如何,只要它加载完了就会立刻执行
- 仔细想想,async 对于应用脚本的用处不大,因为它完全不考虑依赖(哪怕是最低级的顺序执行),不过它对于那些可以不依赖任何脚本或不被任何脚本依赖的脚本来说却是非常合适的,最典型的例子:Google Analytics