Web前端开发面试之JavaScript篇

1、原型对象,构造函数,实例之间的关系?

(1)每个构造函数都有一个 prototype 属性,指向这个构造函数的原型对象。
(2)原型对象有一个 constructor 属性,指向原型对象的构造函数。
(3)实例通过 new 一个构造函数创建,实例通过 proto 可以找到构造函数的原型对象。
(4)每个原型对象都有 proto 属性,指向原型对象的上一级原型对象。

2、介绍一下原型链?(js的原型和原型链)

答:原型:所有的函数都有一个特殊的属性prototype(原型),prototype属性是一个指针,指向的是一个对象(原型对象),原型对象中的方法和属性都可以被函数的实例所共享。所谓的函数实例是指以函数作为构造函数创建的对象,这些对象实例都可以共享构造函数的原型的方法。

原型链:原型链是用于查找引用类型(对象)的属性,查找属性会沿着原型链依次进行,如果找到该属性会停止搜索并做相应的操作,否则将会沿着原型链依次查找直到结尾。常见的应用是用在创建对象和继承中。

原型链:原型对象上的属性和方法是被构造函数创建的实例所共有的,当访问一个实例的属性或方法的时候,在这个实例上本身上没有找到这个属性或方法,往原型对象上找,(通过__proto__),如果在上一级原型对象上还没找到这个属性或方法,会在这个原型对象的基础上,沿着__proto__继续往上一级原型对象查找,依次类推,直到找到一个名字匹配的属性或方法或到达原型链的末尾:null。

扩展:介绍一下作用域链?
作用域:作用域的特点就是,先在自己的变量范围中查找,如果找不到,就会沿着作用域往上找。

3、map 和 set

  • Map是一组键值对的结构,具有极快的查找速度 。
  • Set 和 Map 类似,也是一组 key 的集合,但不存储 value。由于 key 不能重复,所以,在 Set 中,没有重复的 key。
set:不重复的值得集合【let set = new Set([1, 2, 2, 3]) // [1, 2, 3]
add(value):添加某个值,返回 Set 结构本身。
delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
has(value):返回一个布尔值,表示该值是否为Set的成员。
clear():清除所有成员,没有返回值。—
keys():返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器
forEach():使用回调函数遍历每个成员
weakSet:成员只能是对象

4、JS继承?JS继承有哪几种方法,各自优缺点是?

https://blog.csdn.net/xuedan1992/article/details/83515342
https://www.cnblogs.com/humin/p/4556820.html

继承实现的原理?
通过原型链实现继承。

(1)借用构造函数实现继承(构造继承)
原理: 通过在子类的构造函数里面执行父类的构造函数,父类构造函数里的属性和方法就都挂载到子类的实例上面了,等于是复制父类的实例属性给子类(没用到原型)。

特点: 解决了子类实例共享父类引用属性的问题;创建子类实例时,可以向父类传递参数;可以实现多继承(call多个父类对象)

缺点: 实现部分继承。父类原型链上的属性和方法并没有被子类所继承,子类继承的只是父类构造函数里面的属性和方法。

缺点: 实例并不是父类的实例,只是子类的实例;只能继承父类的实例属性和方法,不能继承原型属性/方法;无法实现函数复用,每个子类都有父类实例函数的副本,影响性能。

(2)原型链继承
原理: 将父类的实例赋值给子类的原型对象。

特点: 非常纯粹的继承关系,实例是子类的实例,也是父类的实例;父类新增原型方法/原型属性,子类都能访问到;简单,易于实现。

缺点: 问题主要在包含引用值的原型上,一个实例改变会导致原型上内容的改变。
缺点: 要想为子类新增属性和方法,不能放到构造器中;无法实现多继承;来自原型对象的所有属性被所有实例共享;创建子类实例时,无法向父类构造函数传参。

(3)组合继承(伪经典继承,实际开发中最常用的方法)
核心: 通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用
原理: 是将原型链和借用构造函数组合到一起的一种继承模式,主要思路就是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。

特点:

  • 可以继承实例属性/方法,也可以继承原型属性/方法
  • 既是子类的实例,也是父类的实例;
  • 不存在引用属性共享问题 可传参;
  • 函数可复用

缺点: 可以看出在这个过程中父类的构造函数使用了两次,一次在创建子类原型的时候,另一次是在子类构造函数内部,但是使用过程中,子类的实例属性会屏蔽原型属性,也就是说某些原型属性其实是用不上的,这造成了内存的浪费。

(4)实例继承
核心:为父类实例添加新特性,作为子类实例返回
特点:不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果
缺点:实例是父类的实例,不是子类的实例;不支持多继承

(5)拷贝继承
特点:支持多继承
缺点:效率较低,内存占用高(因为要拷贝父类的属性)

(6)寄生组合继承
核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

5、Promise ,没有 Promise 怎么办

ES6之Promise对象

Promise 对象是 CommonJS 工作组提出的一种规范,目的是为异步编程提供统一接口。每一个异步任务返回一个 Promise 对象,该对象有一个 then 方法,允许指定回调函数。
f1().then(f2);

一个 promise 可能有三种状态:等待(pending)、已完成(resolved,又称fulfilled)、已拒绝(rejected)。

promise 必须实现 then 方法(可以说,then 就是 promise 的核心),而且 then 必须返回一个 promise,同一个 promise 的 then 可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致。

then 方法接受两个参数,第一个参数是成功时的回调,在promise由“等待”态转换到“完成”态时调用,另一个是失败时的回调,在promise由“等待”态转换到“拒绝”态时调用。同时,then 可以接受另一个 promise 传入,也接受一个“类then”的对象或方法,即 thenable 对象。

没有 promise,可以用回调函数代替。

6、知道哪些ES6,ES7的语法

promise,await/async,let、const、块级作用域、箭头函数

let,const,箭头函数,promise,class,解构赋值,export,模版字符串,(…扩展符)

promise 和 await/async 的关系

都是异步编程的解决方案

7、 js 加载过程阻塞,解决方法

指定 script 标签的 async 属性。

如果async="async",脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)。

如果不使用 async 且 defer="defer":脚本将在页面完成解析时执行。

8、 js对象类型,基本对象类型以及引用对象类型的区别

分为基本对象类型引用对象类型

(1)基本数据类型:按值访问,可操作保存在变量中的实际的值。基本类型值指的是简单的数据段。
基本数据类型有这六种:undefined、null、string、number、boolean、symbol。

(2)引用类型:当复制保存着对象的某个变量时,操作的是对象的引用,但在为对象添加属性时,操作的是实际的对象。引用类型值指那些可能为多个值构成的对象。

引用类型有这几种:Object、Array、RegExp、Date、Function、特殊的基本包装类型(String、Number、Boolean)以及单体内置对象(Global、Math)。

9、 JavaScript中的轮播实现原理?假如一个页面上有两个轮播,你会怎么实现?

图片轮播的原理就是图片排成一行,然后准备一个只有一张图片大小的容器,对这个容器设置超出部分隐藏,在控制定时器来让这些图片整体左移或右移,这样呈现出来的效果就是图片在轮播了。

如果有两个轮播,可封装一个轮播组件,供两处调用。

10、class

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。

11、口述数组去重

法一:indexOf 循环去重,建一个空数组,循环目标数组,判断新数组中是否有当前单参数,没有就push,有就跳过

法二:ES6 Set 去重;Array.from(new Set(array))

法三:Object 键值对去重;把数组的值存成 Object 的 key 值,比如 Object[value1] = true,在判断另一个值的时候,如果 Object[value2] 存在的话,就说明该值是重复的。

12、数组的常用操作

concat() 连接两个或更多的数组,并返回结果。
join() 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。
pop() 删除并返回数组的最后一个元素
push() 向数组的末尾添加一个或更多元素,并返回新的长度。
reverse() 颠倒数组中元素的顺序。
shift() 删除并返回数组的第一个元素
slice() 从某个已有的数组返回选定的元素
sort() 对数组的元素进行排序
splice() 删除元素,并向数组添加新元素。
toSource() 返回该对象的源代码。
toString() 把数组转换为字符串,并返回结果。
toLocaleString() 把数组转换为本地数组,并返回结果。
unshift() 向数组的开头添加一个或更多元素,并返回新的长度。
valueOf() 返回数组对象的原始值。

13、箭头函数和 function 有什么区别

箭头函数根本就没有绑定自己的 this,在箭头函数中调用 this 时,仅仅是简单的沿着作用域链向上寻找,找到最近的一个 this 拿来使用。

14、new 操作符原理

  1. 创建一个类的实例:创建一个空对象 obj,然后把这个空对象的 proto 设置为构造函数的 prototype。

  2. 初始化实例:构造函数被传入参数并调用,关键字 this 被设定指向该实例 obj。

  3. 返回实例 obj。

15、bind(),apply(),call() 3种方法的区别

(1) apply:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.apply(A, arguments);即 A 对象应用 B 对象的方法。

(2)call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即 A 对象调用 B 对象的方法。

(3)bind:除了返回是函数以外,它的参数和 call 一样。

16、arguments,箭头函数获取 arguments

arguments 是类数组对象,有 length 属性,不能调用数组方法 。

可用Array.from()转换。

箭头函数可用…rest参数获取。

17、闭包

闭包函数: 声明在一个函数中的函数,叫做闭包函数。

闭包: 内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。

闭包的特点:

  1. 让外部访问函数内部变量成为可能
  2. 局部变量会常驻内存中
  3. 可以避免使用全局变量,防止全局变量污染
  4. 会造成内存泄露(有一块内存被长期占用,得不到释放)

缺点:易造成内存泄漏不会被垃圾回收机制回收

闭包的应用:
6. 模仿块级作用域。
7. 保存外部函数的变量。
8. 封装私有变量

(1)什么是闭包:

闭包是指有权访问另外一个函数作用域中的变量的函数。

闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。闭包就是就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配。当在一个函数内定义另外一个函数就会产生闭包。

(2)为什么要用:

匿名自执行函数:我们知道所有的变量,如果不加上var关键字,则默认的会添加到全局对象的属性上去,这样的临时变量加入全局对象有很多坏处,比如:别的函数可能误用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。除了每次使用变量都是用var关键字外,我们在实际情况下经常遇到这样一种情况,即有的函数只需要执行一次,其内部变量无需维护,可以用闭包。

结果缓存:我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留。

18、事件委托(事件代理)

DOM事件流:事件捕获,目标阶段,事件冒泡
addEventListener(‘click’,function(event){触发事件}, false)默认在事件冒泡阶段触发,默认值false
事件委托:event.currentTarget:事件绑定的元素(绑定在父级元素)
event.target:触发事件的源头(所点击的子元素)
target:事件目标

事件委托利用了事件冒泡和event.target,当有一系列子元素都需要绑定事件时,只需要将事件绑定在父元素即可 。

事件委托是利用事件的冒泡原理来实现的,就是把一个元素响应事件的函数委托到另一个元素,一般是把一组元素的事件委托到他的父元素上。
委托的优点是:减少内存消耗,节约效率,动态绑定事件。

事件代理是利用事件的冒泡原理来实现的,何为事件冒泡呢?
就是事件从最深的节点开始,然后逐步向上传播事件

举个例子:页面上有这么一个节点树,div>ul>li>a;,比如给最里面的 a 加一个 click 点击事件,那么这个事件就会一层一层的往外执行,执行顺序a>li>ul>div,有这样一个机制,那么我们给最外面的 div 加点击事件,那么里面的ul,li,a做点击事件的时候,都会冒泡到最外层的 div 上,所以都会触发,这就是事件代理,代理它们父级代为执行事件。

事件冒泡,就是元素自身的事件被触发后,如果父元素有相同的事件,如onclick事件,那么元素本身的触发状态就会传递,也就是冒到父元素,父元素的相同事件也会一级一级根据嵌套关系向外触发,直到document/window,冒泡过程结束。

19、Eventloop (js运行机制)

在 js 中,任务分为宏任务(macrotask)和微任务(microtask),这两个任务分别维护一个队列,均采用先进先出的策略进行执行。同步执行的任务都在宏任务上执行。

宏任务主要有:script(整体代码)、setTimeout、setInterval、I/O、UI 交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)。

微任务主要有:Promise.then、 MutationObserver、 process.nextTick(Node.js 环境)。

具体的操作步骤如下:

  1. 从宏任务的头部取出一个任务执行;
  2. 执行过程中若遇到微任务则将其添加到微任务的队列中;
  3. 宏任务执行完毕后,微任务的队列中是否存在任务,若存在,则挨个儿出去执行,直到执行完毕;
  4. GUI 渲染;
  5. 回到步骤 1,直到宏任务执行完毕;

这 4 步构成了一个事件的循环检测机制,即我们所称的eventloop。

  • JavaScript 单线程,任务需要排队执行。
  • 同步任务进入主线程排队,异步任务进入事件队列排队等待被推入主线程执行。
  • 定时器的延迟时间为 0 并不是立刻执行,只是代表相比于其他定时器更早的被执行。
  • 以宏任务和微任务进一步理解js执行机制
  • 整段代码作为宏任务开始执行,执行过程中宏任务和微任务进入相应的队列中。
  • 整段代码执行结束,看微任务队列中是否有任务等待执行,如果有则执行所有的微任务,直到微任务队列中的任务执行完毕,如果没有则继续执行新的宏任务。
  • 执行新的宏任务,凡是在执行宏任务过程中遇到微任务都将其推入微任务队列中执行。
  • 反复如此直到所有任务全部执行完毕。

任务队列中,在每一次事件循环中,macrotask 只会提取一个执行,而microtask 会一直提取,直到 microsoft 队列为空为止。

也就是说如果某个 microtask 任务被推入到执行中,那么当主线程任务执行完成后,会循环调用该队列任务中的下一个任务来执行,直到该任务队列到最后一个任务为止。而事件循环每次只会入栈一个 macrotask,主线程执行完成该任务后又会检查 microtasks 队列并完成里面的所有任务后再执行 macrotask 的任务。

macrotasks(宏任务 task,也是我们常说的任务队列):
setTimeout(延迟调用),setInterval(间歇调用),setImmediate(Node 的立即调用),I/O(I/O 操作),UI rendering(UI 渲染)。

20、let、const、 var的区别 ,什么是块级作用域,如何用ES5的方法实现块级作用域(立即执行函数),ES6 呢

提起这三个最明显的区别是,var 声明的变量是全局或者整个函数块的,而 let,const 声明的变量是块级的变量,var 声明的变量存在变量提升,let,const 不存在,let 声明的变量允许重新赋值,const 不允许。

21、什么是事件监听

addEventListener() 方法,用于向指定元素添加事件句柄,它可以更简单的控制事件,语法为

element.addEventListener(event, function, useCapture);

第一个参数是事件的类型(如 “click” 或 “mousedown”).

第二个参数是事件触发后调用的函数。

第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的,默认的是冒泡,即 false,当值为 true 时,即为捕获阶段。

事件传递有两种方式,冒泡和捕获

事件传递定义了元素事件触发的顺序,如果你将 p 元素插入到 div 元素中,用户点击 p元素。

在冒泡中,内部元素先被触发,然后再触发外部元素。

捕获中,外部元素先被触发,在触发内部元素。

22、浅克隆、深刻隆

  • 浅克隆简单来说就是复制,因为引用型变量保存的是内存地址,其实后来操作的都是同一块内存,导致了数组内容都一样。
  • 深克隆就是在克隆的时候判断一下属性的类型是不是引用型变量,如果是的话就用递归方法让它一层一层进去复制自己。

23、浅拷贝、深拷贝

基本数据类型:名字和值都存在栈中。

引用数据类型:名字在栈中,值在堆中,栈内存会提供一个引用地址,指向堆内存中的值。

浅拷贝:1.for只遍历第一层 2.assign 3. =直接赋值
深拷贝:1.递归遍历所有层级
2.利用JSON对象【JSON.stringfy() JSON.parse()
3.通过jQuery的extend方法实现深拷贝
4.lodash函数库实现深拷贝
5.用slice实现对数组的深拷贝,slice() 方法可从已有的数组中返回选定的元素。
6.使用扩展运算符实现深拷贝
7.如对象的value是基本类型,可以用Object.assign来实现深拷贝,但是要把它赋值给一个空对象
assign第一层是深拷贝,第二层以后是浅拷贝
9.用concat实现对数组的深拷贝
10.直接使用var newObj = Object.create(oldObj),可以达到深拷贝的效果。
11.手动实现深拷贝

  • 简单来说,就是一个变量赋值给另一个变量,其中一个变量的值改变,两个变量的值都变了,这就叫做浅拷贝。
  • ES6语法中也给我们提供了一个浅拷贝的方法Object.assign(target, sources)
  • target:拷贝的目标 sources: 被拷贝的对象
  • 浅拷贝, 是拷贝后,新拷贝的对象内部仍然有一部分数据会随着源对象的变化而变化。
  • 深拷贝就是,拷贝后, 新拷贝的对象内部所有数据都是独立存在的,不会随着源对象的改变而改变。
  • 深拷贝的话一共有两种方式: 递归拷贝 和 利用JSON函数深拷贝JSON.parse(JSON.stringify(a))

24、设计模式:单例,工厂,发布订阅

(1)单例模式: 在它的核心结构中值包含一个被称为单例的特殊类。一个类只有一个实例,即一个类只有一个对象实例。

(2)工厂模式: 在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

(3)发布订阅模式: 在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在。同样的,订阅者可以表达对一个或多个类别的兴趣,只接收感兴趣的消息,无需了解哪些发布者(如果有的话)存在。

25、ajax返回的状态

0 - (未初始化)还没有调用send()方法

1 - (载入)已调用send()方法,正在发送请求

2 - (载入完成)send()方法执行完成,已经接收到全部响应内容

3 - (交互)正在解析响应内容

4 - (完成)响应内容解析完成,可以在客户端调用了

26、实现一个 Ajax (写出原生Ajax)如果我想发出两个有顺序的ajax需要怎么做?

Ajax 能够在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页内容,实现局部刷新,大大降低了资源的浪费,是一门用于快速创建动态网页的技术,ajax 的使用分为四部分:

1、创建 XMLHttpRequest 对象 var xhr = new XMLHttpRequest();

2、向服务器发送请求,使用 XMLHttpRequest 对象的 open 和 send 方法。

3、监听状态变化,执行相应回调函数。

(1)设置请求参数(请求方式,请求页面的相对路径,是否异步)

(2)设置回调函数,一个处理服务器响应的函数,使用 onreadystatechange ,类似函数指针。

(3)获取异步对象的 readyState 属性:该属性存有服务器响应的状态信息。每当 readyState 改变时,onreadystatechange 函数就会被执行。

(4)判断响应报文的状态,若为200说明服务器正常运行并返回响应数据。

(5)读取响应数据,可以通过 responseText 属性来取回由服务器返回的数据。

var xhr = new XMLHttpRequest();
xhr.open('get', 'aabb.php', true);
xhr.send(null);
xhr.onreadystatechange = function() {
	if(xhr.readyState==4 && xhr.status==200) {
		console.log(xhr.responseText);	
	}
}

发出两个有顺序的 ajax,可以用回调函数,也可以使用 Promise.then或者 async 等。

27、JSONP的缺点

JSON 只支持 get,因为 script 标签只能使用 get 请求;

JSONP 需要后端配合返回指定格式的数据。

28、跨域(jsonp,ajax)

JSONP:ajax 请求受同源策略影响,不允许进行跨域请求,而 script 标签 src 属性中的链接却可以访问跨域的 js 脚本,利用这个特性,服务端不再返回 JSON 格式的数据,而是返回一段调用某个函数的 js 代码,在 src 中进行了调用,这样实现了跨域。

29、如何实现跨域

(1)JSONP:通过动态创建 script,再请求一个带参网址实现跨域通信。

(2)document.domain + iframe 跨域:两个页面都通过 js 强制设置document.domain 为基础主域,就实现了同域。

(3)location.hash + iframe跨域:a 欲与 b 跨域相互通信,通过中间页 c 来实现。 三个页面,不同域之间利用 iframe 的 location.hash 传值,相同域之间直接 js 访问来通信。

(4)window.name + iframe跨域:通过 iframe 的 src 属性由外域转向本地域,跨域数据即由 iframe 的 window.name 从外域传递到本地域。

(5)postMessage 跨域:可以跨域操作的 window 属性之一。

(6)CORS:服务端设置 Access-Control-Allow-Origin 即可,前端无须设置,若要带 cookie 请求,前后端都需要设置。

(7)代理跨域:起一个代理服务器,实现数据的转发 。

30、dom 是什么,你的理解?

文档对象模型(Document Object Model,简称DOM),是 W3C 组织推荐的处理可扩展标志语言的标准编程接口。在网页上,组织页面(或文档)的对象被组织在一个树形结构中,用来表示文档中对象的标准模型就称为 DOM。

31、简单介绍一下 symbol

Symbol 是 ES6 的新增属性,代表用给定名称作为唯一标识,这种类型的值可以这样创建,let id=symbol(“id”)

Symbol 确保唯一,即使采用相同的名称,也会产生不同的值,我们创建一个字段,仅为知道对应 symbol 的人能访问,使用 symbol 很有用,symbol 并不是 100% 隐藏,有内置方法。

Object.getOwnPropertySymbols(obj) 可以获得所有的 symbol。

也有一个方法 Reflect.ownKeys(obj) 返回对象所有的键,包括 symbol。

所以并不是真正隐藏。但大多数库内置方法和语法结构遵循通用约定他们是隐藏的。

32、js判断类型

判断方法:typeof(),instanceof,Object.prototype.toString.call()等

33、 如何判断一个数组(讲到typeof差点掉坑里)

Object.prototype.call.toString()
instanceof

34、数组常用方法

push(),pop(),shift(),unshift(),splice(),sort(),reverse(),map()等

35、说一下什么是virtual dom

用JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中 当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异 把所记录的差异应用到所构建的真正的DOM树上,视图就更新了。Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。

36、写一个函数,第一秒打印1,第二秒打印2

两个方法,第一个是用 let 块级作用域

for(let i=0;i<5;i++){
	setTimeout(function(){
		console.log(i)
	},1000*i)
}

第二个方法闭包

for(var i=0;i<5;i++){
	(function(i){
		setTimeout(function(){
			console.log(i)
		},1000*i)
	})(i)
}

37、this的指向哪几种

默认绑定:全局环境中,this默认绑定到window。
隐式绑定:一般地,被直接对象所包含的函数调用时,也称为方法调用,this隐式绑定到该直接对象。

隐式丢失:隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到window。
显式绑定:通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定。

new绑定:如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。对于this绑定来说,称为new绑定。

【1】构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值。

【2】如果构造函数使用return语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果。

【3】如果构造函数显式地使用return语句返回一个对象,那么调用表达式的值就是这个对象。

38、mouseover和mouseenter的区别

mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout 。

mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave。

39、js的new操作符做了哪些事情

new 操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象。

40、js的各种位置,比如clientHeight,scrollHeight,offsetHeight ,以及scrollTop, offsetTop,clientTop的区别?

  • clientHeight:表示的是可视区域的高度,不包含border和滚动条。
  • offsetHeight:表示可视区域的高度,包含了border和滚动条。
  • scrollHeight:表示了所有区域的高度,包含了因为滚动被隐藏的部分。
  • clientTop:表示边框border的厚度,在未指定的情况下一般为0。
  • scrollTop:滚动后被隐藏的高度,获取对象相对于由offsetParent 属性指定的父坐标(css定位的元素或body元素)距离顶端的高度。

41、px rem em vh vw之间的区别

1、px:相对长度单位。像素 px 是相对于显示器屏幕分辨率而言的。

2、em:相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。

3、rem:相对长度单位。r’是“root”的缩写,相对于根元素的字体大小。

4、vh 和 vw:相对于视口的高度和宽度,而不是父元素的(CSS百分比是相对于包含它的最近的父元素的高度和宽度)。

42、DOM操作:获取、增、删、查、改等操作

创建:
createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点
添加:appendChild()
移出:removeChild()
替换:replaceChild()
插入:insertBefore()
复制:cloneNode(true)
查找:
getElementsByTagName() //通过标签名称
getElementsByClassName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性

43、循环

(1)for:for(let i=0; i<10; i++)  i:下标     arr[i]:值

(2)for…each: arr.forEach((item,index) => {}) 遍历数组,不能使用break,contintue,return

(3)for…in:for (var i in arr){ // i是下标(索引)}
 i:下标 		arr[i]:值 
 原型链上的所有属性都将被访问 arr.hasOwnProperty(i)可以判断是否在实例上,在实例上才会被返回

(4)for…of: 只能遍历数组
(5)map: 有返回值,可以返回结果数组,不能遍历对象,只能遍历数组或对象数组
var arr = [‘星期一’, ‘星期二’, ‘星期三’];
var a = arr.map(function(item){
	console.log(item)
	return item === ‘星期二’
})
console.log(a)

44、js中的堆和栈

  • 栈(stack):简单地数据段,存放在栈中,有固定大小的内存(自动分配),自动释放。

    • 基本数据类型:number,string,boolean,undefined,null
    • 栈存储了什么:变量名,基本数据类型值,地址
    • 全局作用域,私有作用域,都属是栈内存,理论上,存储的越少,运行速度越快
    • 先进后出
    • 栈内存回收:作用域销毁(立即销毁,不销毁,不立即销毁)
      • 全局作用域销毁:一般情况不销毁,页面关闭,整个作用域销毁
      • 私有作用域销毁 :
        • 不销毁 ;销毁 ;不立即销毁
  • 堆(heap):动态分配内存,大小不定也不会自动释放

    • 引用类型:栈中存放地址,指向堆中的对象,当我们要获取(函数,数组,对象等)的时候,先从栈中获取地址,然后从堆中获取数据

    • 先进先出

    • 堆存储了什么:引用数据类型的值

    • 内存回收:GC垃圾回收机制

      • chrome:标记法,每隔一段时间对所有的空间地址检测,如果没有被占用,立即回收

      • ie和火狐:计数法,空间地址被占用一次+1,空闲一次空间地址-1,如果为0 被回收

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值