目录
[二.call / apply / bind 有啥区别](#二.call / apply / bind 有啥区别)
[七. js高阶中数组的常用的操作方法](#七. js高阶中数组的常用的操作方法)
[十三.构造函数 和 class的区别](#十三.构造函数 和 class的区别)
一.什么是原型,什么是原型链?
原型:
每一个构造函数,都会有一个 prototype
属性。该属性指向一个对象,该对象称之为 原型对象
,即原型。
原型链:
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的 __proto__
上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的 __proto__
中查找(即上一层构造函数的prototype),这样一层一层向上查找直到Object的prototype结束,这样就会形成一个链式结构,我们称为原型链。我们可以说:它们是继承关系
二.call / apply / bind 有啥区别
call:
call(thisObj, arg1, arg2...)
要求传入函数的参数是参数列表
apply:
apply(thisObj, [argArray])
要求传入函数的参数必须放入数组中整体传入
bind:
bind(thisObj,arg1,arg2,...)
-
共同点 : 都可以改变this指向
-
不同点:
-
-
call 和 apply会立即调用函数.bind不会立即调用函数, 需要手动调用.
-
call及bind 和 apply传递的参数不一样,call及bind传递参数使用逗号隔开,apply使用数组传递.
-
- 应用场景
-
-
call 经常做继承.
-
apply 经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值
-
bind 不调用函数,但是还想改变this指向. 比如改变定时器内部的this指向.
-
三.JS四种检测数据类型的方式
1.typeOf :只能检测基本数据类型 2.instanceOf :检测当前实例是否属于某个类的方法 3.constructor: 检测当前实例的构造函数 4.Object.prototype.toString.call( ) : 最准确的方式;
四.说说继承
-
构造函数继承(在子类的构造函数中执行父类的构造函数,并为其绑定子类的this,让父类的构造函数把成员属性和方法都挂到子类的this上) 缺点:无法访问原型上的方法
-
原型链继承(将子构造函数的原型对象指向父构造函数的实例,让constructor 重新指向子构造函数) 缺点:无法为不同的实例初始化继承来的属性
-
组合式继承(将原型链继承和构造函数继承组合到一起, 综合了原型链继承和构造函数继承的优点) 缺点:调用了两次父类构造函数
-
原型式继承(Object.create():这个方法接收两个参数:一是用作新对象原型的对象、二是为新对象定义额外属性的对象(可选参数),核心思想:使用一个中间函数,连接父类与子类的关系。借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。)
-
extends继承(class和extends是es6新增的,class创建一个类,extends实现继承)
可参照文档:JS中常用实现继承的方法(Object.create的原理)_object.create原理-CSDN博客
五.for..in和for..of和forEach的区别
- for ..in:
- 可以循环数组也能循环对象,循环遍历的值是数据结构的键值;
- 可以使用return、break、continue中断循环;
- 在有些情况下会以随机顺序遍历数组,所以最好用来遍历对象;
- for ..of:
- 可以循环可迭代对象(如数组、字符串等),循环遍历的值是数据结构的值;
- 可以使用return、break、continue中断循环;
- forEach:
- 在回调函数内部有三个参数:item、index、arr分别表示当前项、当前项的索引下标、数组本身;
- 会对数组的每一个元素执行一次提供的函数,不改变原数组、没有返回值(undefined);
六.forEach和map方法的区别
相同点
1、都是循环遍历数组中的每一项
2、forEach和map方法里每次执行匿名函数都支持3个参数,参数分别是value(当前每一项)、index(索引值)、array(原数组)
3、匿名函数中的this都是指向window
4、只能遍历数组
区别
1、forEach()返回值是undefined,
2、map()返回一个新数组
七. js高阶中数组的常用的操作方法
● arr.forEach(function(){}):遍历数组
● arr.map(function(){}):对数组遍历并操作数组元素,返回操作后元素组成的新数组
● arr.filter(function({}));对数组元素进行过滤,返回符合元素组成的新数组
● arr.find(function(){}):查找数组中符合的元素
● arr.some(function){}):对数组的元素进行判断是否有符合的元素
● arr.every(function){}):对数组的元素进行判断是否全部符合
● arr.find(function){})方法返回符合查找条件的第一个数组元素的值。
● arr.reduce(function(total,value,index,array){},initialValue):方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
八.什么是严格模式
JavaScript 除了提供正常模式外,还提供了严格模式(strict mode)。ES5 的严格模式是采用具有限制性 JavaScript变体的一种方式,即在严格的条件下运行 JS 代码。
严格模式在 IE10 以上版本的浏览器中才会被支持,旧版本浏览器中会被忽略。
设立严格模式的原因:
1、消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
2、消除代码运行的一些不安全之处,保证代码运行的安全;
3、提高编译器效率,增加运行速度;
4、为未来新版本的Javascript做好铺垫。
严格模式下的语法变化:
-
不能不声明变量直接使用
-
函数的this指向,指向undefined
-
函数的参数,不可以重名
-
构造函数如果不使用new实例化,会报错
九.什么是高阶函数?
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
只需满足以下任意一个条件,即是高阶函数:
\1. 接受一个或多个函数作为输入 \2. return 返回另外一个函数
十.闭包是什么,有什么特性,对页面有什么影响
**概念:**内部函数访问其所在的外部函数中声明的参数和变量,形成的词法环境叫闭包.
闭包有三个特性:
-
1、函数嵌套函数
-
2、函数内部访问外部函数的参数或变量
-
3、可以使函数中的变量可以长期驻扎在内存
使用闭包的好处:
-
1、变量长期驻扎在内存中
-
2、避免全局变量的污染(多人定义同样名字的全部变量冲突)
-
3、私有成员的存在
使用闭包的坏处:
-
1、常驻内存
-
2、会增大内存的使用量
-
3、使用不当会造成内存泄露
注意:内存泄露:指的是**应用程序不再用到的内存,由于某些原因,没有及时释放,就叫做内存泄漏。**
会造成内存泄漏的js操作:
1.意外的全局变量
2.未清理的DOM元素的引用
3.被遗忘的定时器或者回调函数
4.闭包
5.过多的console.log语句
十一.浅拷贝与深拷贝
深拷贝和浅拷贝是只针对Object和Array这样的引用数据类型的。
浅拷贝: 只复制指向某个对象的指针**而不复制对象本身,新旧对象还是共享同一块内存。**
Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。
深拷贝:**会另外创建一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。**
深拷贝的实现方式
1.JSON.parse(JSON.stringify())
原理: 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
2.手写递归方法
递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝;
十二.赋值(地址传递)和浅拷贝的区别
-
当我们把一个对象赋值给一个新的变量时,赋的其实是该对象的在栈中的地址,而不是堆中的数据。也就是两个对象指向的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,因此,两个对象是联动的。
-
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。即:默认拷贝构造函数只是对对象进行浅拷贝复制(逐个成员依次拷贝),即只复制对象空间而不复制资源。
十三.构造函数 和 class的区别
构造函数:
-
在 JavaScript 中,用 new 关键字来调用的函数,称为构造函数。构造函数首字母一般大写
-
功能类似对象模板,一个构造函数可以生成任意多个实例,实例对象具有相同的属性、行为特征,但不相等。
-
函数体内使用 this,引用将要生成的实例对象。
-
必需使用 new 命令调用函数,生成实例对象。
class类:
-
类不存在变量提升(hoist),
-
类的方法内部如果含有this,它默认指向类的实例,
-
类使用extends来继承,
-
类的数据类型就是函数,类本身就指向构造函数;使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致;
十四.栈内存和堆内存的区别?
栈(stack):由编译器自动分配释放,存放函数的参数值,局部变量等;
堆(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统释放。
了解以下内容
1、栈:基础变量的值是存储在栈中,而引用变量存储在栈中的是指向堆中的数组或者对象的地址,这就是为何修改引用类型总会影响到其他指向这个地址的引用变量。 优点:相比于堆来说存取速度会快,并且栈内存中的数据是可以共享的,例如同时声明了var a = 1和var b = 1,会先处理a,然后在栈中查找有没有值为1的地址,如果没有就开辟一个值为1的地址,然后a指向这个地址,当处理b时,因为值为1的地址已经开辟好了,所以b也会同样指向同一个地址。 缺点:相比于堆来说的缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
2、堆:堆内存中的对象不会随方法的结束而销毁,就算方法结束了,这个对象也可能会被其他引用变量所引用(参数传递)。创建对象是为了反复利用(因为对象的创建成本通常较大),这个对象将被保存到运行时数据区(也就是堆内存)。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收机制才会在核实的时候回收它。