2019前端面试题

来深圳面试了10多家公司,总结一些面试题。

MVC,MVVC,MVVM模式的理解

1.MVC(Model-View-Controller)
Model(模型):数据层,负责存储数据。
View(视图):展现层,用户所看到的页面
Controller(控制器):协调层,负责协调Model和View,根据用户在View上的动作在Model上作出对应的更改,同时将更改的信息返回到View上。
三者之间的关系
Controller可以直接访问Model,也可以直接控制View,但是Model和View不能相互通信,相当于COntroller就是介于这两者之间的协调者。

2,MVVM(Model-View-ViewModel)

Model(模型):数据层,负责存储数据。
View(控制器):就是ViewController层,他的任务就是从ViewModel层获取数据,然后显示。
ViewModel(视图模型):就是View和Model层的粘合剂,封装业务逻辑处理,封装网络处理,封装数据缓存。就是把原来ViewController层的业务逻辑和页面逻辑等剥离出来放到ViewModel层。

3,MVVC(Model-View-View-Controller)
Model(模型):数据层,负责存储数据。
View(视图):展现层,创建需求创建cell
View(视图):定义数组,用来接收控制中的数据。处理回调(比如:刷新回调、点击cell回调、加载更多回调、动态视图高度回调等等)

Controller(控制器):加载网络数据懒加载

4. Vue 有哪些指令?

v-html、v-show、v-if、v-for等等

5. v-if 和 v-show 有什么区别?

v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;而v-if会控制这个 DOM 节点的存在与否。当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。

6. 简述Vue的响应式原理

当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。

每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

7. 简述Vue的生命周期

它可以总共分为8个阶段:

beforeCreate(创建前),

created(创建后),

beforeMount(载入前),

mounted(载入后),

beforeUpdate(更新前),

updated(更新后),

beforeDestroy(销毁前),

destroyed(销毁后)

8.vue中Computed 和 Watch的使用和区别

1、计算属性computed适用的情形

我们可能会有这样的需求,一个数据属性在它所依赖的属性发生变化时,也要发生变化,这种情况下,我们最好使用计算属性。

例如在下面这个例子中,如果我们使用监听函数,代码就会变得有点冗余。

2、监听器watch适当的情形

watch函数适用于,当数据发生变化时,执行异步操作或较大开销操作的情况。

8.vue 与 react优缺点对比

vue
API设计上简单,语法简单,学习成本低
构建方面不包含路由和ajax功能,使用vuex, vue-router
指令(dom)和组件(视图,数据,逻辑)处理清晰
性能好,容易优化
基于依赖追踪的观察系统,并且异步队列更新
独立触发
v-model 实时渲染
适用于:模板和渲染函数的弹性选择
简单的语法及项目搭建
更快的渲染速度和更小的体积
react
利用jsx创建虚拟dom
是一种在内存中描述dom数状态的数据结构
函数式的方法描述视图
使用虚拟dom作为模板
程序片段
不好控制dom
生命周期
服务端渲染:react的虚拟dom的生成可以在任何支持js的环境生成的,所以可以在node环境生成,直接转为string,然后插入到html文件中输出浏览器便可
适用于:大型应用和更好的可测试性;同时适用于web端和原生app;更大的生态圈
优点
React伟大之处就在于,提出了Virtual Dom这种新颖的思路,并且这种思路衍生出了React Native,有可能会统一Web/Native开发。在性能方面,由于运用了Virtual Dom技术,Reactjs只在调用setState的时候会更新dom,而且还是先更新Virtual Dom,然后和实际Dom比较,最后再更新实际Dom。这个过程比起Angularjs的bind方式来说,一是更新dom的次数少,二是更新dom的内容少,速度肯定快
ReactJS更关注UI的组件化,和数据的单向更新,提出了FLUX架构的新概念,现在React可以直接用Js ES6语法了,然后通过webpack编译成浏览器兼容的ES5,开发效率上有些优势.
React Native生成的App不是运行在WebView上,而是系统原生的UI,React通过jsx生成系统原生的UI,iOS和Android的React UI组件还是比较相似的,大量代码可以复用
维护UI的状态,Angular 里面使用的是 $scope,在 React 里面使用的是 this.setState。 而 React 的好处在于,它更简单直观。所有的状态改变都只有唯一一个入口 this.setState(),
同构的JavaScript
单页面JS应用程序的最大缺陷在于对搜索引擎的索引有很大限制。React对此有了解决方案。
React可以在服务器上预渲染应用再发送到客户端。它可以从预渲染的静态内容中恢复一样的记录到动态应用程序中。
因为搜索引擎的爬虫程序依赖的是服务端响应而不是JavaScript的执行,预渲染你的应用有助于搜索引擎优化。
缺点
React是目标是UI组件,通常可以和其它框架组合使用,目前并不适合单独做一个完整的框架。React 即使配上 redux 的组合,也不能称之一个完整的框架,比如你想用Promise化的AJAX?对不起没有,自己找现成的库去。而且第三方组件远远不如Angular多。目前在大的稳定的项目上采用React的,我也就只知道有Yahoo的Email。React本身只是一个V而已,所以如果是大型项目想要一套完整的框架的话,也许还需要引入Redux和route相关的东西。


vue,react 共性:
虚拟dom实现快速渲染
轻量级响应式组件
服务端渲染易于集成路由工具,打包工具及状态管理工具


9.知道什么是vuex吗?

在SPA单页面组件的开发中 Vue的vuex和React的Redux 都统称为同一状态管理,个人的理解是全局状态管理更合适;简单的理解就是你在state中定义了一个数据之后,你可以在所在项目中的任何一个组件里进行获取、进行修改,并且你的修改可以得到全局的响应变更。

核心概念1: State

state就是Vuex中的公共的状态, 我是将state看作是所有组件的data, 用于保存所有组件的公共数据.

核心概念2: Getters

我将getters属性理解为所有组件的computed属性, 也就是计算属性. vuex的官方文档也是说到可以将getter理解为store的计算属性, getters的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

核心概念3: Mutations

我将mutaions理解为store中的methods, mutations对象中保存着更改数据的回调函数,该函数名官方规定叫type, 第一个参数是state, 第二参数是payload, 也就是自定义的参数.

核心概念4: Actions

actions 类似于 mutations,不同在于:actions提交的是mutations而不是直接变更状态actions中可以包含异步操作, mutations中绝对不允许出现异步actions中的回调函数的第一个参数是context, 是一个与store实例具有相同属性和方法的对象

10.Vue-自定义指令

v-model,v-on,v-bind这一类的指令很经常使用,但有时候也不能满足我们的需求,比如我们想要通过v-focus(这个指令是vue不提供的)实现表单的焦点获取,就会遇到无指令提供的窘况。

这个时候我们可以自定义指令,有个地方要注意下,如果使用了未定义的指令,vue会提出警告,程序依然会正常运行。

1、比如定义一个全局可用的focus实现input选中,全局的东西如JS中的全局变量,一般不会用。



2、定义局部指令,局部指令只在组件内部有效,超出组件范围则无效,类似局部变量的作用。


vue给自定义指令提供了几个函数钩子,用于实现自定义指令的功能:

bind: 指令第一次绑定到元素时调用,

inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。

update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。

componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。

unbind: 指令与元素解绑时调用。

11,组件之间的传值(父传子,子传父,非父子组件之间通信)

一、父组件向子组件传值步骤

1.创建子组件,在src/components/文件夹下新建一个Child.vue
2.Child.vue的中创建props,然后创建一个名为message的属性

3.在App.vue中注册Child组件,并在template中加入child标签,标签中添加message属性并赋值

二、子组件向父组件传值

1.在子组件中创建一个按钮,给按钮绑定一个点击事件


2.在响应该点击事件的函数中使用$emit来触发一个自定义事件,并传递一个参数

3.在父组件中的子标签中监听该自定义事件并添加一个响应该事件的处理方法

4.保存修改的文件,在浏览器中点击按钮

三,非父子组件之间通信

第一步,在main.js中新new一个Vue对象

var bus = new Vue()
export default bus
1
2
第二步:在组件中引入bus的引用

import bus from '../../main'
1
第三步:通过emit触发事件传值,在另一个组件中的mounted中用emit触发事件传值,在另一个组件中的mounted中用emit触发事件传值,在另一个组件中的mounted中用on监听事件从而获取值
组件1:

bus.$emit(‘clickPtest’,‘rrrrrrrrrrrrrr’)

组件2:

mounted () {
bus.$on(‘clickPtest’,function (msg) {
console.log(msg)
})
},


12,vue2.0中的$router 和 $route的区别

1.router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性。

举例:history对象

$router.push({path:'home'});本质是向history栈中添加一个路由,在我们看来是 切换路由,但本质是在添加一个history记录

方法:

$router.replace({path:'home'});//替换路由,没有历史记录

2.route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等

我们可以从vue devtools中看到每个路由对象的不同

13,如何优化SPA应用的首屏加载速度慢的问题?

  • 将公用的JS库通过script标签外部引入,减小app.bundel的大小,让浏览器并行下载资源文件,提高下载速度;
  • 在配置 路由时,页面和组件使用懒加载的方式引入,进一步缩小 app.bundel 的体积,在调用某个组件时再加载对应的js文件;
  • 加一个首屏 loading 图,提升用户体验

14,网页从输入网址到渲染完成经历了哪些过程?

  1. 输入网址;
  2. 发送到DNS服务器,并获取域名对应的web服务器对应的ip地址;
  3. 与web服务器建立TCP连接;
  4. 浏览器向web服务器发送http请求;
  5. web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址);
  6. 浏览器下载web服务器返回的数据及解析html源文件;
  7. 生成DOM树,解析css和js,渲染页面,直至显示完成;

15.ajax请求的过程

1、创建XMLHttpRequest对象

2,创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.

3,设置响应HTTP请求状态变化的函数.

4,发送HTTP请求.

5,获取异步调用返回的数据.

6,使用JavaScript和DOM实现局部刷新.

16,js的数组去重

思路1:先将原数组排序,在与相邻的进行比较,如果不同则存入新数组。

function unique2(arr) {
            var formArr = arr.sort()
            var newArr=[formArr[0]]
            for (let i = 1; i < formArr.length; i++) {
                if (formArr[i]!==formArr[i-1]) {
                    newArr.push(formArr[i])
                }
            }
            return newArr
        }
        console.log(unique2([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]));

思路2: 利用对象属性存在的特性,如果没有该属性则存入新数组。

        function unique3(arr) {
            var obj={}
            var newArr=[]
            for (let i = 0; i < arr.length; i++) {
                if (!obj[arr[i]]) {
                    obj[arr[i]] = 1
                    newArr.push(arr[i])
                }   
            }
            return newArr
        }
        console.log(unique2([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]));

最简单的方法就是es6

var a = [1,2,2,2,3];
 a = [...new Set(a)];
 输出 a = [1,2];

17,js数组排序

var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return b - a});

18,js的原型和原型链

1、javascript原型

JS中每个函数都存在有一个原型对象属性prototype。并且所有函数的默认原型都是Object的实例。

2、javascript原型链

每个继承父函数的子函数的对象都包含一个内部属性_proto_。该属性包含一个指针,指向父函数的prototype。若父函数的原型对象的_proto_属性为再上一层函数。在此过程中就形成了原型链。

3、特点

原型链实现了继承。

19,js实现继承的方法

  • 1,原型链继承 (有两种实现方式)
    (1)Son.prototype = Father.prototype
    弊端:Son.prototype.constructor 指向Father,需要手动更改为Son ;Son的实例化对象只能继承Father原型中的方法,无法继承Father本身的属性。
    (2)Son.prototype = new Father()
    弊端:Son.prototype.constructor 指向Father,需要手动更改为Son;Son的实例化对象共享Father自身的引用类型属性。
    2,借助构造函数继承
    弊端:Son只能继承Father自身的属性,而无法继承Father原型中的方法。
    3,组合式继承
    将原型链继承与构造函数结合起来
    弊端:通过Father.call() 和 new Father() ,父类构造函数Father被调用了两次。
    4,原型式继承
    newObj继承了obj的属性和方法,但是同样出现了共享父类中引用类型属性的问题。
    5,经典继承(Es5中的新语法:存在兼容性问题,需要做浏览器的能力检测)
    6,寄生式继承(类似于原型式继承)
    newObj继承了obj的属性和方法,但是同样出现了共享父类中引用类型属性的问题。
    7,寄生组合式继承(组合继承+寄生继承)
    优点:可以多重继承 解决两次调用 解决实例共享引用类型的问题 原型链保持不变

20,js的基本数据类型

  • 基本类型:String、Number、Boolean、Sy有mbol、Undefined、Null
  • 引用类型:Object

21,js有哪些内置对象

Math对象:Math.abs(x);//用来返回数的绝对值

Date对象:var date = new Date();// 通过new的方式创建一个日期对象;

Array对象:var arr=new Array();

字符串对象:var str=new String();

22,js操作数组的方法

join():join(separator): 将数组的元素组起一个字符串,以separator为分隔符,省略的话则用默认用逗号为分隔符,该方法只接收一个参数:即分隔符。

push()和pop():push(): 可以接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。 pop():数组末尾移除最后一项,减少数组的 length 值,然后返回移除的项。

shift() 和 unshift():shift():删除原数组第一项,并返回删除元素的值;如果数组为空则返回undefined 。 unshift:将参数添加到原数组开头,并返回数组的长度

sort():按升序排列数组项——即最小的值位于最前面,最大的值排在最后面

reverse():反转数组项的顺序。

concat():将参数添加到原数组中。这个方法会先创建当前数组一个副本,然后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。在没有给 concat()方法传递参数的情况下,它只是复制当前数组并返回副本。

slice():返回从原数组中指定开始下标到结束下标之间的项组成的新数组。slice()方法可以接受一或两个参数,即要返回项的起始和结束位置。在只有一个参数的情况下, slice()方法返回从该参数指定位置开始到当前数组末尾的所有项。如果有两个参数,该方法返回起始和结束位置之间的项——但不包括结束位置的项。

splice():splice():很强大的数组方法,它有很多种用法,可以实现删除、插入和替换。

indexOf()和 lastIndexOf() (ES5新增):indexOf():接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中, 从数组的开头(位置 0)开始向后查找。
lastIndexOf:接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中, 从数组的末尾开始向前查找。

这两个方法都返回要查找的项在数组中的位置,或者在没找到的情况下返回1。在比较第一个参数与数组中的每一项时,会使用全等操作符。

forEach() (ES5新增)forEach():对数组进行遍历循环,对数组中的每一项运行给定函数。这个方法没有返回值。参数都是function类型,默认有传参,参数分别为:遍历的数组内容;第对应的数组索引,数组本身。

map() (ES5新增)map():指“映射”,对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。

filter() (ES5新增)filter():“过滤”功能,数组中的每一项运行给定函数,返回满足过滤条件组成的数组。

every() (ES5新增)every():判断数组中每一项都是否满足条件,只有所有项都满足条件,才会返回true。

some() (ES5新增)some():判断数组中是否存在满足条件的项,只要有一项满足条件,就会返回true。

23,什么是闭包,闭包的优缺点

闭包各种专业文献的闭包定义都非常抽象,我的理解是: 闭包就是能够读取其他函数内部变量的函数。

由于在javascript中,只有函数内部的子函数才能读取局部变量,所以说,闭包可以简单理解成“定义在一个函数内部的函数“。

所以,在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

优点:
1. 逻辑连续,当闭包作为另一个函数调用的参数时,避免你脱离当前逻辑而单独编写额外逻辑。
2. 方便调用上下文的局部变量。
3. 加强封装性,第2点的延伸,可以达到对变量的保护作用。
缺点:
闭包有一个非常严重的问题,那就是内存浪费问题,这个内存浪费不仅仅因为它常驻内存,更重要的是,对闭包的使用不当会造成无效内存的产生

24,阻止时间冒泡和默认事件

1,e.stopPropagation()

2,e.preventDefault(),

3,return false

25,javascript中apply、call和bind的区别

在JS中,这三者都是用来改变函数的this对象的指向的,他们有什么样的区别呢。

在说区别之前还是先总结一下三者的相似之处:

1、都是用来改变函数的this对象的指向的。

2、第一个参数都是this要指向的对象。

3、都可以利用后续参数传参

call和apply都是对函数的直接调用,而bind方法返回的仍然是一个函数,因此后面还需要()来进行调用才可以。

call后面的参数与say方法中是一一对应的,而apply的第二个参数是一个数组,数组中的元素是和say方法中一一对应的,这就是两者最大的区别。

26,如何解决跨域的问题

1、 通过jsonp跨域

2、 document.domain + iframe跨域

3、 location.hash + iframe

4、 window.name + iframe跨域

5、 postMessage跨域

6、 跨域资源共享(CORS)

7、 nginx代理跨域

8、 nodejs中间件代理跨域

9、 WebSocket协议跨域

27,vue this.$set 给data对象新增属性,并触发视图更新

28,vue路由实现的原理

29,写一个闭包

30,HTTP中Get、Post、Put与Delete的区别

1、GET请求会向数据库发索取数据的请求,从而来获取信息,该请求就像数据库的select操作一样,只是用来查询一下数据,不会修改、增加数据,不会影响资源的内容,即该请求不会产生副作用。无论进行多少次操作,结果都是一样的。

2、与GET不同的是,PUT请求是向服务器端发送数据的,从而改变信息,该请求就像数据库的update操作一样,用来修改数据的内容,但是不会增加数据的种类等,也就是说无论进行多少次PUT操作,其结果并没有不同。

3、POST请求同PUT请求类似,都是向服务器端发送数据的,但是该请求会改变数据的种类等资源,就像数据库的insert操作一样,会创建新的内容。几乎目前所有的提交操作都是用POST请求的。

4、DELETE请求顾名思义,就是用来删除某一个资源的,该请求就像数据库的delete操作。

就像前面所讲的一样,既然PUT和POST操作都是向服务器端发送数据的,那么两者有什么区别呢。。。POST主要作用在一个集合资源之上的(url),而PUT主要作用在一个具体资源之上的(url/xxx),通俗一下讲就是,如URL可以在客户端确定,那么可使用PUT,否则用POST。

综上所述,我们可理解为以下:

1、POST /url 创建
2、DELETE /url/xxx 删除
3、PUT /url/xxx 更新
4、GET /url/xxx 查看


31,sessionStorage,localStorage,cookie 区别

  1. 都会在浏览器端保存,有大小限制,同源限制
  2. cookie 会在请求时发送到服务器,作为会话标识,服务器可修改 cookie;web storage 不会发送到服务器
  3. cookie 有 path 概念,子路径可以访问父路径 cookie,父路径不能访问子路径 cookie
  4. 有效期:cookie 在设置的有效期内有效,默认为浏览器关闭;sessionStorage 在窗口关闭前有效,localStorage 长期有效,直到用户删除
  5. 共享:sessionStorage 不能共享,localStorage 在同源文档之间共享,cookie 在同源且符合 path 规则的文档之间共享
  6. localStorage 的修改会促发其他文档窗口的 update 事件
  7. cookie 有 secure 属性要求 HTTPS 传输
  8. 浏览器不能保存超过 300 个 cookie,单个服务器不能超过 20 个,每个 cookie 不能超过 4k。web storage 大小支持能达到 5M

32,箭头函数和普通函数的区别

1,箭头函数是匿名函数,不能作为构造函数,不能使用new

2,箭头函数不绑定arguments,取而代之用rest参数...解决

3,箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值

4,箭头函数通过 call() 或 apply() 方法调用一个函数时,只传入了一个参数,对 this 并没有影响。

5,箭头函数没有原型属性

6,箭头函数不能当做Generator函数,不能使用yield关键字

33,es6新特性

  1. Let声明关键字
  2. Const声明关键字
  3. 箭头函数
  4. 默认参数
  5. For…of…循环
  6. 展开属性
  7. Map集合
  8. 静态方法
  9. Getter和Setter方法

43,常用http的http方法有哪些?

GET:用于请求访问已经被uri识别的资源,可以通过url传参给服务器.

POST:用于传输信息给服务器,主要功能GET类似,但一般推荐使用POST方式.

PUT:传输文件,报文主体中包含文件内容,保存到对应的uri位置.

HEAD:获得报文首部,与GET方法类似,只是不返回报文主体,一般用于验证uri是否有效.

DELETE:删除文件,与PUT方法相反,删除对应URI位置的文件.

OPTIONS:查询对应uri支持的http方法

35,GET和POST的区别

区别一:

GET重点从服务器上获取资源,POST重点向服务器发送数据.

区别二:

get传输数据是通过URL请求,置于URL后,并用”?”连接,多个请求数据间用”&”连接.post传输数据通过Http的post机制,将字段与对应值封存在请求实体中发送给服务器,这个过程对用户是不可见的;

区别三:

Get传输的数据量小,因为受URL长度限制,但效率较高;

Post可以传输大量数据,所以上传文件时只能用Post方式;

区别四:

get是不安全的,因为URL是可见的,可能会泄露私密信息,如密码等;

post较get安全性较高;

区别五:

get方式只能支持ASCII字符,向服务器传的中文字符可能会乱码。

post支持标准字符集,可以正确传递中文字符。

36,HTTP请求报文与响应报文格式

请求报文包含三部分:

a、请求行:包含请求方法、URI、HTTP版本信息

b、请求首部字段

c、请求内容实体

响应报文包含三部分:

a、状态行:包含HTTP版本、状态码、状态码的原因短语

b、响应首部字段

c、响应内容实体

37,理解 async/await

async/await是写异步代码的新方式,以前的方法有回调函数Promise

async/await是基于Promise实现的,它不能用于普通的回调函数。

async/await与Promise一样,是非阻塞的。

async/await使得异步代码看起来像同步代码,这正是它的魔力所在。

示例中,getJSON函数返回一个promise,这个promise成功resolve时会返回一个JSON对象。我们只是调用这个函数,打印返回的JSON对象,然后返回"done"。

使用Promise是这样的:·

const makeRequest = () =>
  getJSON()
    .then(data => {
      console.log(data)
      return "done"
    })

makeRequest()

使用Async/Await是这样的:

const makeRequest = async () => {
  console.log(await getJSON())
  return "done"
}

makeRequest()

它们有一些细微不同:

  • 函数前面多了一个aync关键字。await关键字只能用在aync定义的函数内。async函数会隐式地返回一个promise,该promise的reosolve值就是函数return的值。(示例中reosolve值就是字符串"done")
  • 第1点暗示我们不能在最外层代码中使用await,因为不在async函数内。
// 不能在最外层代码中使用await
await makeRequest()

// 这是会出事情的 
makeRequest().then((result) => {
  // 代码
})

await getJSON()表示console.log会等到getJSON的promise成功reosolve之后再执行。

38.怎样添加、移除、移动、复制、创建和查找节点?

1)创建新节点

createDocumentFragment() //创建一个DOM片段

  createElement() //创建一个具体的元素

  createTextNode() //创建一个文本节点

2)添加、移除、替换、插入

  appendChild() //添加

  removeChild() //移除

  replaceChild() //替换

  insertBefore() //插入

3)查找

  getElementsByTagName() //通过标签名称

  getElementsByName() //通过元素的Name属性的值

  getElementById() //通过元素Id,唯一性

39.谈谈垃圾回收机制方式及内存管理

回收机制方式

1、定义和用法:垃圾回收机制(GC:Garbage Collection),执行环境负责管理代码执行过程中使用的内存。

2、原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。但是这个过程不是实时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。

3、实例如下:

function fn1() {

var obj = {name: 'hanzichi', age: 10};

}

function fn2() {

var obj = {name:'hanzichi', age: 10};

return obj;

}

var a = fn1();

var b = fn2();

fn1中定义的obj为局部变量,而当调用结束后,出了fn1的环境,那么该块内存会被js引擎中的垃圾回收器自动释放;在fn2被调用的过程中,返回的对象被全局变量b所指向,所以该块内存并不会被释放。

4、垃圾回收策略:标记清除(较为常用)和引用计数。

标记清除:

  定义和用法:当变量进入环境时,将变量标记"进入环境",当变量离开环境时,标记为:"离开环境"。某一个时刻,垃圾回收器会过滤掉环境中的变量,以及被环境变量引用的变量,剩下的就是被视为准备回收的变量。

  到目前为止,IE、Firefox、Opera、Chrome、Safari的js实现使用的都是标记清除的垃圾回收策略或类似的策略,只不过垃圾收集的时间间隔互不相同。

引用计数:

  定义和用法:引用计数是跟踪记录每个值被引用的次数。

  基本原理:就是变量的引用次数,被引用一次则加1,当这个引用计数为0时,被视为准备回收的对象。

内存管理

1、什么时候触发垃圾回收?

垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨,确定垃圾回收时间间隔就变成了一个值得思考的问题。

IE6的垃圾回收是根据内存分配量运行的,当环境中的变量,对象,字符串达到一定数量时触发垃圾回收。垃圾回收器一直处于工作状态,严重影响浏览器性能。

IE7中,垃圾回收器会根据内存分配量与程序占用内存的比例进行动态调整,开始回收工作。

2、合理的GC方案:(1)、遍历所有可访问的对象; (2)、回收已不可访问的对象。

3、GC缺陷:(1)、停止响应其他操作;

4、GC优化策略:(1)、分代回收(Generation GC);(2)、增量GC

开发过程中遇到的内存泄露情况,如何解决的?

1、定义和用法:

内存泄露是指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。C#和Java等语言采用了自动垃圾回收方法管理内存,几乎不会发生内存泄露。我们知道,浏览器中也是采用自动垃圾回收方法管理内存,但由于浏览器垃圾回收方法有bug,会产生内存泄露。

2、内存泄露的几种情况:

(1)、当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在IE中不会作出恰当处理,此时要先手工移除事件,不然会存在内存泄露。

实例如下:

<div id="myDiv">

<input type="button" value="Click me" id="myBtn">

</div>

<script type="text/javascript">

var btn = document.getElementById("myBtn");

btn.onclick = function(){

document.getElementById("myDiv").innerHTML = "Processing...";

}

</script>

解决方法如下:

<div id="myDiv">

<input type="button" value="Click me" id="myBtn">

</div>

<script type="text/javascript">

var btn = document.getElementById("myBtn");

btn.onclick = function(){

btn.onclick = null;

document.getElementById("myDiv").innerHTML = "Processing...";

}

</script>

(2)、由于是函数内定义函数,并且内部函数--事件回调的引用外暴了,形成了闭包。闭包可以维持函数内局部变量,使其得不到释放。

实例如下:

function bindEvent(){

var obj=document.createElement("XXX");

obj.onclick=function(){

//Even if it's a empty function

}

}

解决方法如下:

function bindEvent(){

var obj=document.createElement("XXX");

obj.onclick=function(){

//Even if it's a empty function

}

obj=null;

}

1、Array相关的属性和方法

这里只是做了相关的列举,具体的使用方法,请参考网址。

40.Array 对象属性

constructor 返回对创建此对象的数组函数的引用。

length 设置或返回数组中元素的数目。

prototype 使您有能力向对象添加属性和方法。

Array 对象方法

concat() 连接两个或更多的数组,并返回结果。

join() 把数组的所有元素放入一个字符串。元素通过指定的分隔符进行分隔。

pop() 删除并返回数组的最后一个元素。

shift() 删除并返回数组的第一个元素

push() 向数组的末尾添加一个或更多元素,并返回新的长度。

unshift() 向数组的开头添加一个或更多元素,并返回新的长度。

reverse() 颠倒数组中元素的顺序。

slice() 从某个已有的数组返回选定的元素

sort() 对数组的元素进行排序

splice() 删除元素,并向数组添加新元素。

toSource() 返回该对象的源代码。

toString() 把数组转换为字符串,并返回结果。

toLocaleString() 把数组转换为本地数组,并返回结果。

valueOf() 返回数组对象的原始值

编辑于 06-12