1. JS值类型与引用类型的区别
1. 值类型/简单数据类型: string、number、boolean、undefined、null
值存在栈中 赋值拷贝也是栈数据 修改拷贝数据对原数据没有影响
代码语言:javascript复制let num1 = 10
let num2 = num1
num2 = 20
console.log(num1, num2) // 10 20
2.引用类型/复杂数据类型: Array、function、Object
栈中存储地址 堆中存储数据 赋值时拷贝的是栈地址 修改拷贝数据(堆)对原数据有影响
代码语言:javascript复制let num3 = [1,2]
let num4 = num3
num4[0] = 10
console.log(num3, num4)
3. 变量修改 栈与堆的区别
代码语言:javascript复制num4 = 10
// 只是修改了栈中数据 但地址对应的数据没有影响
console.log(num3, num4)
代码语言:javascript复制let num = 10 // 测试
function fn1() {
num = 20
}
fn1()
console.log(num) // 20
// 2.
let arr = [1,2,3]
function fn2(arr) {
arr = 100
}
fn2()
console.log(arr) // [1,2,3]
// 3.
function fn3(arr) {
arr[0] = 100
}
fn3(arr)
console.log(arr) // [100,2,3]
// 4.
function fn4() {
arr[0] = 100
}
fn4()
console.log(arr) // [100,2,3]
2. 字符串方法
代码语言:javascript复制// 1. split(,) 把字符串转换为数组 和join()相反
let n1 = 'red, blue'
console.log(n1.split(','))
// 2. replace('替换前的字符', '替换后的字符')
let n2 = '蔡徐坤'
console.log(n2.replace('蔡', '嗯'))
// 删除某个字符 把字符替换为空字符
console.log(n2.replace('蔡', ''))
// 应用场景:
// 1. 名字替换为 xx先生
console.log(n2.replace('徐坤', '先生'))
// 2. 敏感词替换
let n3 = '你是傻逼'
console.log(n3.replace('傻逼', '**'))
3. 数组的增删改查方法以及返回值
代码语言:javascript复制let arr = [1,2,3,4]
1. 新增数组
// .push 在数组最后面添加元素, 返回值是新数组的长度
// .unshift 在数组最前面面添加元素, 返回值是新数组的长度
arr.push(11, 22)
arr.unshift(0)
2. 删除数组
// .pop 删除数据的最后一个元素, 返回值是删除的那个元素
// .shift 删除数据的最前一个元素, 返回值是删除的那个元素
arr.pop()
arr.shift()
3. 查询数组
// .slice(起始下标, 结束下标), 返回 起始下标<=范围下标<结束下标 的数组
// .splice(起始下标, 删除数量, ...删除位置新增的元素)
console.log(arr.slice(1, 3))
console.log(arr.splice(1, 1))
console.log(arr)
4. 数组.join('分隔符') 将数组每一个元素用分隔符拼接成字符串
// 应用场景: 将商品标签 ['自营', '进口'] 转换为 自营|进口
// 应用场景: 将演出歌手 ['周杰伦', '周慧妹'] 转换为 周杰伦$$周慧妹
console.log(arr.join('|'))
5. 数组.reverse 翻转数组(修改原数组)
console.log(arr.reverse(arr))
// 应用场景: 翻转字符串
let a = '蔡徐坤'
console.log(a.split('').reverse('').join(''))
6. .sort 数组排序 按照ASCII编码顺序排序
console.log(arr.sort())
// 两个引用数据类型, 是不比较堆数据的, 只比较栈地址
let obj = [
{name: '华为', age: 10},
{name: '小米', age: 40},
{name: '苹果', age: 30}
]
obj.sort((a, b) => {
return a.age - b.age // 从小到大排序
})
console.log(obj)
4. 数组的遍历方法
1. 数组forEach 是没有return的也没有返回值
- 应用场景: 修改数组的每一个元素值
- 金典面试题: 如何终止forEach? (try-catch)
// forEach 用来遍历数组对象
// 加强版for循环
let arr = ['小米','苹果','华为']
arr.forEach(function (item, index) {
console.log(item) // 数组元素
console.log(index) // 数组下标
})
2. 数组map
- return 会新数组返回值
- 应用场景: 数组的转换: 根据数组的元素, 得到一个全新的数组
- 由于map创建一个新数组, 在没有使用返回的数组情况下调用它是不恰当的:
- 应该使用forEach或for…of作为代替
let arr = [1,2,3]
arr.map(i => {
console.log(i)
console.log({name: i}) // 数组的转换
})
2. 数组filter
- return true: 满足筛选条件的 放入新数组中
- return true: 不满足筛选条件的 不放入新数组
- filter方法自身返回值: 满足条件的新数组
// 1. 筛选20以上的数组
let n1 = [10, 15, 20, 30]
let fn = n1.filter(function (a, b) {
console.log(a) // 数组元素
console.log(b) // 数组下标
// 筛选20以上的数组
return a >= 20
})
// 2. 筛选完 会创建符合条件的新数组
// 不符合条件则返回空数组
console.log(fn) // [20, 30]
// 3. 箭头函数写法
let say = n1.filter(item => item >= 40)
console.log(say)
3. 数组 indexOf(): 查找元素下标(只能找值类型下标)
4. 数组 findIndex(): 查找元素下标(只能找引用类型下标)
- return true: 找到了, 循环结束, 返回当前元素下标
- return false: 没找到, 循环继续, 最终返回-1
- findIndex方法自身返回值: 元素下标 || -1
- 应用场景: 找到对象元素中 元素的下标
let arr = [
{name: '小东', age: 1},
{name: '小刚', age: 2},
{name: '小明', age: 3}
]
let n1 = arr.findIndex((item, index) => {
return item.age == 2
})
console.log(n1) // 1
5. 数组find和findIndex作用是一样的, 返回值是元素本身
- 应用场景: 修改对象数组中某一个对象属性
let n2 = arr.find((item, index) => {
return item.age == 2
console.log(item) // 所有对象
})
console.log(n2) // 返回小刚对象
console.log(n2.age *= 0.1) // 0.2
6. 数组reduce方法
代码语言:javascript复制// reduce累计器 返回累计处理的结果 用于求和..
let n4 = [1,2,3,4]
// reduce(function (上一次值, 当前值){}, 初始值
// 1. 没有初始值
let n5 = n4.reduce(function (a, b) {
return a b
})
console.log(n5)
// 2. 有初始值
let n6 = n4.reduce(function (a, b) {
return a b
}, 10) // 初始值
console.log(n6)
// 箭头函数写法
let n7 = n4.reduce((a, b) => a b, 10)
console.log(n7)
// 3. reduce 执行过程
// 01. 没有初始值
// 上一次值是数组的第一个值
// 每一次循环 就会把返回值给下一次循环的上一次值
let n8 = [1,2,3]
let n9 = n8.reduce((a, b) => a b)
console.log(n9)
// 上一次值 当前值 返回值 (第一次循环)
// 1 2 3
// 上一次值 当前值 返回值 (第二次循环)
// 3 3 6
// 02. 有初始值 把初始值做为上一次值
let n10 = [1,2]
let n11 = n10.reduce((a, b) => a b, 10)
console.log(n11)
// 上一次值 当前值 返回值 (第一次循环)
// 10 1 11
// 上一次值 当前值 返回值 (第二次循环)
// 11 13 13
5. 箭头函数和普通函数的区别
- this指向不同
1. function函数的this指向: 谁调用函数, this就指向谁
- 普通函数: fn() this指向window
- 对象方法: fn.方法名() this指向对象
- 构造函数: new 函数名 this指向实例对象
function fn() {
console.log(this)
}
fn() // window
let obj = {
a: fn
}
obj.a() // 指向obj
new fn() // 指向fn
2. 箭头函数this: 箭头函数没有this 本质是访问上级作用域this
- 箭头函数不能作为构造函数(报错)
- 箭头函数不能使用上下文修改this(call、apply、bind)
- 箭头函数不能使用arguments(报错)
let f = () => {
console.log(this)
}
f.call('你好') // 还是window
3. 经典面试题
代码语言:javascript复制let obj1 = {
name: '小明',
age() { // 等价于 age function() {}
function fn1() {
console.log(this) // 指向window
}
fn1()
let fn2 = () => {
console.log(this) // 指向obj1 fn1跟fn2平级作用域
}
fn2()
},
say: () => { // say是箭头函数 this指向上级window
function fn1() {
console.log(this) // 指向window
}
fn1()
let fn2 = () => {
console.log(this) // 指向window
}
fn2()
}
}
obj1.age()
obj1.say()
6. 原型与原型链
- 对象原型__proto__的意义是为对象成员查找机制提供一条路线
- 原型链是一个查找规则
- 可查找一些属性和方法 沿着一条路走
- 先看当前原型对象上面有没有
- 果没有再往上一层的原型对象查找
- 如果有 就可使用
- 往上查找最终找到Object为止(null)
// 1. 原型链
function fn() {
}
let n1 = new fn()
// new的实例化对象等于fn.prototype
console.log(n1.__proto__ == fn.prototype)
// 因为Object也是构造函数 那么就有prototype和constructor
// fn.protptype里的__proto__就等于 Object.constructor
// Object.constructor 在指回Obj 所以__proto__指向Object
console.log(fn.prototype.__proto__ == Object.prototype)
// Object的对象有prototype 那么protytype就一定有__proto__
// Object对象最大 所以指向null
console.log(Object.prototype.__proto__) // null
// 2. instanceof运算符用于检测构造函数prototype属性
// 是否出现在某个实例对象的原型对象上
// n1 属于 fn
console.log(n1 instanceof fn) // true
// n1 属于 Object
console.log(n1 instanceof Object) // true
// n1 不属于 Array
console.log(n1 instanceof Array) // false
// 数组 属于 Array
console.log([1,2,3] instanceof Array) // true
// 数组 属于 Object
console.log(Array instanceof Object) // true