1.数据类型
- 基本:number(包含nan) string null undefined boolean symbol bigint。基本数据类型存放在栈区
- 引用:object(包括数组和函数)。引用数据类型存放在堆区。如果再详细一点,就是引用数据类型会在栈区存放数据的引用和地址指针(指向堆区中相应的数据),数据实体则存放在堆区。
用typeof或instanceof判断数据类型
-
判断基本数据类型:typeof
typeof 42将返回"number",typeof “hello"将返回"string”。需要注意的是,typeof null将返回"object",对于数组、日期、正则表达式等类型,typeof都会返回"object",typeof还可以用于检测一个变量是否已经定义,如果变量未定义,typeof将返回"undefined"。
let a
console.log(typeof new Array());//object
console.log(Array.isArray(new Array));//true
console.log(typeof new Date());//object
console.log(typeof a);//undefined
-
判断引用数据类型 :instanceof
console.log(new Array() instanceof Array);//true
2.var let const的区别
1、var声明的变量属于函数作用域,它没有块级作用域,而let和const声明的变量属于块级作用域;(js中用{}包裹的代码称为代码块)(局部作用域分为函数作用域和块级作用域两种)
2、var声明的变量存在变量提升,而let和const没有
3、var声明的变量可以重复声明,而在同一块级作用域,let变量不能重新声明,const常量不能修改(对象的属性和方法,数组的内容可以修改)
3.call apply bind的区别和用法——可以动态指定普通函数的this指向
1.this指向问题
对于普通函数,谁调用就指向谁
对于箭头函数,函数内不存在this,沿用上一级的,过程: 向外层作用域中,一层一层查找this,直到有this的定义
2.call用法——改变this指向并且调用函数
返回值就是函数本身的返回值
let obj = {
a: 1,
b:2
}
let fun = function (x, y) {
console.log(this);//{ a: 1, b: 2 }
}
fun.call(obj,1,2)
3.apply用法——改变this指向并且调用函数
和call的区别:传入的其余参数要用数组表示
let obj = {
a: 1,
b:2
}
let fun = function (x, y) {
console.log(this);//{ a: 1, b: 2 }
}
fun.apply(obj,[1,2])
//使用场景
const arr = [1, 2, 3, 4, 5]
console.log(Math.max(...arr));//5
console.log(Math.max.apply(Math,arr));//5
4.bind用法——改变this指向但不会调用函数
和call和apply的区别:不会立即调用函数
4.创建对象的方法
// 1.利用对象字面量创建对象 {}
// var obj = {}; // 创建了一个空的对象
var obj = {
uname: '张三疯',
age: 'sha',
sex: '男',
sayHi: function () {
console.log('hi~');
}
}
//2.利用 new Object 创建对象
var obj = new Object(); // 创建了一个空的对象
obj.uname = '张三疯';
obj.age = 18;
obj.sex = '男';
obj.sayHi = function () {
console.log('hi~');
}
// 3.利用构造函数创建对象
function Star(uname, age, sex) {
this.name = uname;
this.age = age;
this.sex = sex;
this.sing = function (sang) {
console.log(sang);
}
}
var ldh = new Star('刘德华', 18, '男');
5.浏览器的垃圾回收机制
(1)引用计数法
跟踪记录被引用的次数,如果被引用了一次,那么就记录次数1,多次引用会累加 ++如果减少一个引用就减1--.如果引用次数是0,则释放内存。
(2)标记清除法
从根部扫描对象,能查找到的就是使用的,查找不到的就要回收。
6.New操作符执行过程
- 创建一个新的空对象。
- 将这个新对象的隐式原型指向构造函数的prototype对象。
- 将构造函数的this指向这个新对象。
- 执行构造函数的代码,为这个新对象添加属性。
- 判断构造函数的返回值类型,如果是基本数据类型,则返回创建的对象;如果是引用类型,则返回这个引用类型的对象。
7.对数组扁平化操作并去重
使用js内置对象中的一些方法
var arr = [[1, 2, 2], [3, 4, 5, 5], [6, 7, 8, 9, [11, 12, [12, 13, [14]]], 10]]
arr = arr.join().split(',').sort((a, b) => a - b)
arr=[...new Set(arr)]
8.()()关于闭包
let a = 1
function bar() {
let b = () => a
a = 2
return b
}
console.log(bar()());
//结果是2
分析:bar()==bar函数中return语句后面的东西==b,所以bar()()==b()==b函数中return语句后面的东西==a,所以最终的结果是打印出a。但是因为在执行bar()函数时已改变a的值为2,所以打印出的是2而不是1。
9.事件循环机制
console.log(1);//1
setTimeout(function(){
console.log(2);//7
}, 10)
setTimeout(function(){
console.log(3);//6
}, 0)
console.log(4);//2
new Promise(function (resolve) {
console.log(5);//3
resolve()
}).then(function() {
console.log(6);//5
})
console.log(7);//4
///1 4 5 7 6 3 2
- 事件循环的整体过程:
- 先清空调用栈中的同步代码
- 执行微任务队列中的微任务
- 尝试DOM渲染
- 触发事件循环反复询问回调队列中是否有要执行的语句,有则放入调用栈继续执行。
-
宏任务:由浏览器规定的
- setTimeout
- setInterval
- Ajax
- DOM事件
- 微任务:由ES6语法规定的
- Promise
- async
- await
10.作用域和this指向
var name = 'window'
var person1 = {
name: 'person1',
foo1: function () {
console.log(this.name);
},
foo2: () => {console.log(this.name);},
foo3: () => {
return function () {
console.log(this.name);
}
},
foo4: function () {
return () => {
console.log(this.name);
}
}
}
var person2 = { name: 'person2' }
person1.foo1()//person1
person1.foo2()//window
person1.foo3()()//window
person1.foo4()()//person1
person1.foo2.call(person2)//window
考察点:
1. 箭头函数不会创建自己的this,箭头函数的this是上一层作用域的this指向
2. 闭包
3. call、apply、bind 不能改变箭头函数的this,因为箭头函数本身没有this
11.变量
var fa = []
// var没有块级作用域!!!
for (var i = 0; i < 10; i++){
fa.push(
function () {
console.log(i);
}
)
}
for (var i = 0; i < 10; i++){
fa[i]()
}
fa[5]()
fa[3]()
fa[1]()
//0 1 2 3 4 5 6 7 8 9 10 10 10