值类型和引用类型有什么区别?数组常用10个方法;function和箭头函数区别;原型链;localStorage与sessionStorage区别;BFC;call;bind;apply;深浅拷贝区别

值类型和引用类型有什么区别

基本数据类型: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

  • 构造函数生成实例对象personperson__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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值