1,JS中的数据类型:
- 基本数据类型
- String
- Number
- Boolean
- Undefined
- Null
- symbol
- bigint
- 引用数据类型
- object
- 普通对象
- 正则对象
- 日期对象
- Math数学函数对象
.....
- function
数据类型检测:
- object
- typeof 检测数据类型的逻辑运算符
- instanceof 检测是否为某个类的实例
- constructor 检测构造函数
- Object.prototype.toString.call 检测数据类型
let a = typeof typeof typeof [12, 23]
console.log(a) // 'string'
把其他数据类型转换为数字的方法:
- 强转换(基于底层机制转换的)
- Number()
- 弱转换(基于一些额外的方法转换)
- parseInt()
- parseFloat()
parseInt('') //NaN
Number('') // 0
isNaN('') // false isNaN走的是隐式转换,先把''转换成Number => 0 isNaN(0) => false
parseInt(null) NaN
Number(null) //0
isNaN(null) // isNaN(0) false
parseInt('12px') // 12
Number('12px') // NaN
isNaN('12px') // true
parseFloat('1.6px') + parseInt('1.2px') + typeof parseInt(null) // 1.6 + 1 + typeof NaN => 2.6 + 'number' => '2.6number'
isNaN(Number(!!Number(parseInt('0.8')))) // isNaN(0) => false
typeof !parseInt(null) + !isNaN(null) // 'boolean' + true => 'booleantrue'
0 NaN null undefined 空字符串 转换成布尔都是false
2,浏览器底层机制:堆栈内存和VO、GO等
js之所以能在浏览器中运行,是因为浏览器给js提供了执行的环境 => 栈内存
JS运行的底层机制: 浏览器之所以给JS提供运行机制,是浏览器会在计算机内存中分配一块内存,专门用来供代码执行 => 栈内存 ECStack(执行环境栈),没打开一个网页都会开辟出一块执行环境栈。
GO(全局对象),浏览器把内置的一些属性方法放到一个单独的内存中,这个内存叫堆内存;浏览器端会让window指向GO
栈内存:用来提供代码执行的环境
堆内存:存放东西(存放的是属性方法)
EC(执行上下文): 代码自己执行所在的环境
- 全局的执行上下文 EC(G)
- 函数中的代码都会在一个单独的私有的执行上下文中处理
-
块级的执行上下文
上下文执行是在栈内存中执行,进栈出栈
VO(变量对象): 在当前的上下文中,用来存放创建的变量和值的地方(每个执行上下文中都会有一个自己的变量对象,函数私有上下文中叫做AO(活动对象),也是变量对象
01.png


var a = {n: 1}
var b = a
a.x = a = {n: 2}
console.log(a.x)
console.log(b)
// undefined {n: 1, {n: 2}}
function fun (n, o) {
console.log(o)
return {
fun: function (m) {
return fun(m, n)
}
}
}
var c = fun(0).fun(1);
c.fun(2);
c.fun(3)
const定义的值能改吗?
const定义的基本类型不能改 但是定义的对象是可以通过修改对象属性改变的
const a = 10
a // 10
a = 20
VM110:1 Uncaught TypeError: Assignment to constant variable
const b = {}
b // {}
b.name = 'xiaowang'
b // {name: 'xiaowang'}
b = {}
VM110:1 Uncaught TypeError: Assignment to constant variable
js中的栈内存和堆内存
在js引擎中对变量的存储有两种位置: 栈、堆
栈内存主要存储基本类型的变量(string、number、Boolean、undefined、null)以及对象变量的指针,栈内存就像一个线性排列的空间,每个小单元大小基本相等
堆内存主要存储像object这种引用类型的变量
堆的特点是无序的key-value键值对存储方式。
当我们定义一个const对象的时候,我们说的常量其实就是指针,就是const对象对应的堆内存指向是不变的,但是堆内存中的数据本身的大小或属性是可变的,const定义的基本类型的变量,这个值相当于const对象的指针,是不可变的
js不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间,在操作对象的时候,实际上是在操作对象的引用而不是实际的对象,因此,引用类型的值都是按引用访问的,这里的引用,可以粗浅的理解为保存在栈内存中的一个地址,该地址与堆内存的实际值相关联

var a = new String('str')
var b = new String('str')
a === b //false
很明显,如果a、b存储在栈内存中,两者明显相等 这里两者不等说明他们都存储在堆内存中,指针指向不一致
3,深拷贝、浅拷贝
两者最根本的区别: 是否真正获取一个对象的复制实体,而不是引用。
B复制了A,修改A的时候看B是否发生变化,如果B发生变化,说明是浅拷贝,如果B没有发生变化,则是深拷贝。
浅拷贝只是增加了一个指针指向已存在的内存地址
深拷贝是增加了一个指针并申请了一个新的内存,使这个增加的指针指向这个新的内存;即在计算机中开辟一块新的内存地址用于存放复制的对象。
浅拷贝:
var obj = {
a: 1,
arr: [1, 2]
}
function lightCopy (v) {
var newObj = {}
for (var prop in v) {
if (v.hasOwnProperty(prop)) {
newObj[prop] = obj[prop]
}
}
return newObj
}
var obj2 = lightCopy(obj)
obj2.arr[1] = 100 // obj.arr[1] = 100 obj2.arr[1] = 100
console.log(obj, obj2) // {a: 1, arr: [1, 2])
深拷贝实例:
方法一:
var obj = {
name: 'wangyaru',
arr: [1,2,3,4,5,6,7,8,9]
}
function deepCopy(obj) {
var newObj = obj instanceof Array ? [] : {}
if (typeof obj !== 'object') {
return obj
} else {
for (var i in obj) {
newObj[i] = typeof obj[i] === 'object' ? deepCopy(obj[i]) : obj[i]
}
}
return newObj
}
方法二: 只能处理符合JSON格式的对象
var obj = {
name: 'wangyaru',
arr: [1,2,3,4,5,6,7,8,9]
}
function deepCopy (o) {
return JSON.parse(JSON.stringify(obj))
}
var obj2 = deepCopy(obj)
obj2.arr[1] = 100
console.log(obj, obj2)
// obj1: {
// arr: (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
// name: "wangyaru"
// }
// obj2: {
// arr: (9) [1, 100, 3, 4, 5, 6, 7, 8, 9]
// name: "wangyaru"
// }
深拷贝时,obj和obj2分别拥有不同的内存地址,两边的值互不影响
4,promise
function Fn() {} // Fn函数
const fn = new Fn() //Fn是构造函数 fn是实例对象简称对象
console.log(Fn.prototype) // Fn是函数对象
首先先说下同回调函数和异步回调函数
同步:
const arr = [1,2,3]
arr.forEach(i => {
console.log(i)
})
console.log('forEach之后')
// 1 2 3 forEach之后
异步:
setTimeout(_ => {
console.log('callback')
})
console.log('setTimeout之后')
error:
常见的内置错误:
1,ReferenceError 引入的变量不存在
console.log(a) // Uncaught ReferenceError: a is not defined
Uncaught => 未被处理的
2,TypeError 数据类型不正确的错误
let b = {}
b.xxx() // Uncaught TypeError: b.xxx is not a function
3, rangeError 范围(range) 数据值不在其所允许的范围内
function fn () {
fn()
}
fn() // Uncaught RangeError: Maximum call stack size exceeded
4,SyntaxError 语法错误
const c= "''" // SyntaxError: Unexpected string
除了错应该处理 捕获错误: try ... catch
抛出错误: throw error
try {
let b = {}
console.log(b.xxx() )
} catch (error) {
console.log(error)
}
promise是什么?
promise是JS中进行异步编程的新的解决方案
使用promise是解决回调地狱(函数内部嵌套函数等)的
回调地狱缺点: 不便于阅读/不便于异常处理
解决方案: promise链式调用
终极解决方案: async await
问题
从语法上说promise是一个构造函数
从功能上promise对象用来封装一个异步操作并可以获
取其结果
promise的状态改变:
pending变成 resolved 成功的
pending变成 rejected 失败的
pending(未确定的)
只有2种,且一个promise对象只能改变一次
无论变成成功还是失败 都会有一个结果数据
成功的结果数据一般成为value, 失败的结果数据一般成为女reason
pending怎么变成resolved 需要执行一个resolve函数
创建一个promise对象
const p = new Promise ((resolve, reject) _ => {
setTimeout(() => {
const time = Date.now()
if (time%2 == 0) {
resolve('成功的数据' + time)
} else {
reject('失败的数据' + time)
}
})
})
p.then(
value => {
console.log('成功的回调' + value)
},
reason => {
console.log('失败的回调' + reason)
}
)
new Promise ((resolve, reject) => {
setTimeout(() => {
resolve(''成功的数据)
reject('失败的数据')
}, 1000)
}).then(
value => {
console.log('onReveloved()', value)
}
).catch (
reason => {
console.log('onRejected()', reason)
}
)
面试题:
1,setTimeout(() => {
console.log(1)
})
Promise.resolve().then(() => {
console.log(2)
})
Promise.resolve().then(() => {
console.log(4)
})
console.log(3)
2,setTimeout(() => {
console.log(1)
})
new Promise((resolve) => {
console.log(2)
resolve()
}).then(() => {
console.log(3)
}).then(() => {
console.log(4)
})
console.log(5)
3,const first = () => (new Promise((resolve, reject) => {
console.log(3)
let p = new Promise((resolve, reject) => {
console.log(7)
setTimeout(() => {
console.log(5)
resolve(6)
}, 0)
resolve(1)
})
resolve(2)
p.then((arg) => {
console.log(arg)
})
}))
first().then((arg) => {
console.log(arg)
})
console.log(4)
4,setTimeout(() => {
console.log('0')
}, 0)
new Promise((resolve, reject) => {
console.log('1')
resolve()
}).then(() => {
console.log('2')
new Promise((resolve, reject) => {
console.log('3')
resolve()
}).then(() => {
console.log('4')
}).then(() => {
console.log('5')
})
}).then(() => {
console.log('6')
})
new Promise((resolve, reject) => {
console.log('7')
resolve()
}).then(() => {
console.log('8')
})
答案:
1, // 3 2 4 1
2, // 2 5 3 4 1
3, // 3 7 4 1 2 5
4, // 1 7 2 3 8 4 6 5 0
网友评论