值类型和引用类型有什么区别
基本数据类型:string,number,null,Boolean,undefined,symbol
引用数据类型: Object,Array,Function
区别:基本数据类型保存在栈里面,可以直接访问他的值,引用数据类型保存在堆里面,栈里面保存的是地址,通过栈里面的地址去访问堆里面的值
函数传参的时候,传值类型和引用类型有什么区别?
传值类型, 修改形参,不会影响实参
传引用类型, 修改形参自己不会影响实参, 修改形参内部的数据就会影响实参
数组常用10个方法
增: 返回新数组长度
arr.push(...元素) : 往数组后面添加元素 , 返回数组长度
arr.unshift(...元素) : 往数组前面添加元素 , 返回数组长度
let arr = [10, 20, 30, 40, 50]
// arr.push(...元素) : 往数组后面添加元素 , 返回数组长度
let arr1 = arr.push(60, 70, 80)
console.log(arr1)//8
// arr.unshift(...元素) : 往数组前面添加元素 , 返回数组长度
let arr2 = arr.unshift(7, 8, 9)
console.log(arr2)//11
删: 返回删除的那个元素
arr.pop() : 删除数组最后一个元素, 返回删除的那个元素
arr.shift() : 删除数组第一个元素, 返回删除的那个元素
arr.splice(开始下标,删除几个元素,...在删除位置插入元素)
let arr = [10, 20, 30, 40, 50]
// arr.pop() : 删除数组最后一个元素, 返回删除的那个元素
console.log(arr.pop()) //50
// arr.shift() : 删除数组第一个元素, 返回删除的那个元素
console.log(arr.shift())//10
// arr.splice(开始下标,删除几个元素,...在删除位置插入元素)
console.log(arr.splice(0, 1, 21));//20
console.log(arr);//[21,30,40]
查: 返回查询到的元素数组
arr.slice(起始下标,结束下标) : 查询指定范围的元素
// 查: 返回查询到的元素数组
// arr.slice(起始下标,结束下标) : 查询指定范围的元素
let arr = [10, 20, 30, 40, 50]
console.log(arr.slice(0,3));//[10, 20, 30, 40]
join
arr.join('分隔符') : 把数组元素拼接成字符串
// arr.join('分隔符') : 把数组元素拼接成字符串
console.log(['张三', '李四'].join('&'))//张三&李四
concat
arr.concat( 数组 ) : 连接数组
// 5. arr.concat( 数组 ) : 连接数组
// 应用场景: 移动端列表 上拉加载更多
const newArr1 = arr.concat([60,70,80])
console.log(newArr1);//[10, 20, 30, 40, 50, 60, 70, 80]
reverse
arr.reverse() : 翻转数组
let arr = [10, 20, 30, 40, 50]
// 3. arr.reverse() : 翻转数组
// 有的页面列表可以反向排列
console.log(arr.reverse());// [50, 40, 30, 20, 10]
sort
arr.sort( (a,b)=>a-b ) // 用于排序
// 4. arr.sort( (a,b)=>a-b )
let Arr = [
{ name: '张三', age: 18 },
{ name: '李四', age: 15 },
{ name: '王五', age: 22 },
]
//根据年龄排序 a和b就是数组中相邻的元素
Arr = Arr.sort((a, b) => a.age - b.age)
console.log(Arr);//age值由小到大排序
另外遍历数组的方法也属于是数组的方法, 在此不谈
function和箭头函数区别
箭头函数本身是为了简化代码, 增加代码可读性发明的
1.写法不同
function fn(a, b){
return a + b;
}
//arrow function
var foo = (a, b)=>{ return a + b };
2.使用function定义的函数,this的指向随着调用环境的变化而变化的,而箭头函数中的this指向是固定不变的,一直指向的是定义函数的环境。
//使用function定义的函数
function foo(){
console.log(this);
}
var obj = { aa: foo };
foo(); //Window
obj.aa() //obj { aa: foo }
//使用箭头函数定义函数
var foo = () => { console.log(this) };
var obj = { aa:foo };
foo(); //Window
obj.aa(); //Window
3.function是可以定义构造函数的,而箭头函数不可以。
//使用function方法定义构造函数
function Person(name, age){
this.name = name;
this.age = age;
}
var lenhart = new Person(lenhart, 25);
console.log(lenhart); //{name: 'lenhart', age: 25}
//尝试使用箭头函数
var Person = (name, age) =>{
this.name = name;
this.age = age;
};
var lenhart = new Person('lenhart', 25);
//Uncaught TypeError: Person is not a constructor
4.由于js的内存机制,function的级别最高,而用箭头函数定义函数的时候,需要var(let const定义的时候更不必说)关键词,而var所定义的变量不能得到变量提升,所以箭头函数一定要定义于调用之前
foo(); //123
function foo(){
console.log('123');
}
arrowFn(); //Uncaught TypeError: arrowFn is not a function
var arrowFn = () => {
console.log('456');
};
小结:
(1)写法不同
(2)this指向不同
(3)箭头函数不能作为构造函数
(4)箭头函数不能修改this指向
原型链
原型链是 js 对象一种查找机制,遵循就近原则。当我们访问一个对象中的成员的时候,会优先访问自己的,如果自己没有就访问原型的,如果原型也没有就会访问原型的原型,直到原型链的终点 null. 如果还没有,此时属性就会获取 undefined,方法就会报错 xxx is not a function。一般原型链主要是用来实现面向对象继承的。
原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain),它解释了为何一个对象会拥有定义在其他对象中的属性和方法
在对象实例和它的构造器之间建立一个链接(它是__proto__
属性,是从构造函数的prototype
属性派生的),之后通过上溯原型链,在构造器中找到这些属性和方法
下面举个例子:
function Person(name) {
this.name = name
this.age = 18
this.sayName = function () {
console.log(this.name)
}
}
// 第二步 创建实例
var person = new Person('person')
根据代码,我们可以得到下图
下面分析一下:
-
构造函数
Person
存在原型对象Person.prototype
-
构造函数生成实例对象
person
,person
的__proto__
指向构造函数Person
原型对象 -
Person.prototype.__proto__
指向内置对象,因为Person.prototype
是个对象,默认是由Object
函数作为类创建的,而Object.prototype
为内置对象 -
Person.__proto__
指向内置匿名函数anonymous
,因为 Person 是个函数对象,默认由 Function 作为类创建 -
Function.prototype
和Function.__proto__
同时指向内置匿名函数anonymous
,这样原型链的终点就是null
localStorage与sessionStorage区别
Web 存储对象 localStorage
和 sessionStorage
允许我们在浏览器上保存键/值对。
相同点:
- 存储的内容为键值对,键和值都必须是字符串,我们可以使用JSON来存储对象
- 存储大小限制为 5MB+,具体取决于浏览器。
- 它们不会过期。
- 数据绑定到源(域/端口/协议)。
不同点:
- localStorage会一直存在浏览器中,即使浏览器关闭也不会消失,sessionStorage页面刷新后数据仍然保留(但标签页关闭后数据则不再保留)
localStorage
在同源的所有标签页和窗口之间共享数据,sessionStorage
在当前浏览器标签页中可见,包括同源的 iframe
localStorage存储在硬盘中,sessionStorage存储在内存中
(1)大小不同
(2)生命周期不同
(3) localStorage可以跨页面使用, sessionStorage只能在当前窗口使用
BFC
我是这样理解的:BFC 的中文意思是块级格式化上下文,是用于布局块级盒子的独立渲染区域,一个创建了新的 BFC 的盒子是独立布局的,盒子内元素的布局 不会影响盒子外面的元素。简单来说就是 BFC 就是 css 的一个布局概念,是一个独立的区域(容器) 满足下列条件之一就可以触发 BFC:
- HTML 根元素
- position 为 absolute 或 fixed
- float 属性不为 none(常用)
- overflow 不为 visible(常用)
- display 为 inline-block, table-cell, table-caption, flex(常用)
可以解决什么问题:margin 重叠,清除浮动,自适应布局.
举个栗子:
当一个容器具备了 BFC 之后, 我们就可以利用BFC
的特性,解决很多问题
防止 margin 重叠(塌陷)
<style>
p {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align: center;
margin: 100px;
}
</style>
<body>
<p>Haha</p>
<p>Hehe</p>
</body>
页面显示如下:
两个p
元素之间的距离为100px
,发生了margin
重叠(塌陷),以最大的为准,如果第一个 P 的margin
为 80 的话,两个 P 之间的距离还是 100,以最大的为准。
前面讲到,同一个BFC
的俩个相邻的盒子的margin
会发生重叠
可以在p
外面包裹一层容器,并触发这个容器生成一个BFC
,那么两个p
就不属于同一个BFC
,则不会出现margin
重叠
<style>
.wrap {
overflow: hidden; // 新的BFC
}
p {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align: center;
margin: 100px;
}
</style>
<body>
<p>Haha</p>
<div class="wrap">
<p>Hehe</p>
</div>
</body>
这时候,边距则不会重叠:
call;bind;apply的区别
传参方式不同 :
call和bind是 以参数列表方式传参。 apply是以数组/伪数组方式传参
执行方式不同 :
call和apply会立即执行, bind()不会立即执行,而是得到一个修改this之后的新函数
深拷贝浅拷贝的区别
浅拷贝:拷贝基本数据类型为他的值,拷贝引用数据类型为地址,生成新的数据,修改新的数据会影响原数据,实际开发常用的方法有:object.assgin,扩展运算符等等
深拷贝:在内存中开辟一个新的栈空间保存新的数据,修改新数据不会影响到原数据,开发中常用的方法有:loadsh 中的_.cloneDeep()方法,JSON.stringify()
推荐使用导入loadsh的方式实现深拷贝
const _ = require('lodash')
const obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3],
}
const obj2 = _.cloneDeep(obj1)
console.log(obj1.b.f === obj2.b.f) // false