undefined中文什么意思,undefined含义

  

  31.JS 单线程还是多线程,如何显示异步操作   

  

  回答:JS本身是单线程的,是依赖于浏览器的异步操作。   

  

  解析:   

  

  具体步骤,   

  

  1.主线程执行js中的所有代码。   

  

  2.主线程在执行过程中发现需要异步的任务,就扔给浏览器(浏览器创建多个线程来执行),在回调队列中创建相应的回调函数(回调函数是一个对象,包括函数是否已经执行等。).   

  

  3.主线程已经执行了所有的同步代码。开始监听回调队列。一旦浏览器中的线程完成了它的任务,它将改变回调函数的状态。当主线程看到一个函数的状态为完成时,它将执行该函数。   

  

  互动   

  

  32.JavaScript 数组的函数 map/forEach/reduce/filter   

  

  参考答案:   

  

  1 .地图   

  

  //map//函数:遍历数组。//返回值:新数组。//Change: no var arr=2,5,3,4;var ret=arr . map(function(value){返回值1;});console . log(ret);//3,6,4,5 console . log(arr);//2,5,3,42.forEach   

  

  //forEach方法//函数:遍历数组的每一项//返回值:未定义//Change: no var arr=2,5,3,4;var ret=arr . foreach(function(value){ console . log(value);//2, 5, 3, 4});console . log(ret);//undefined console . log(arr);//2,5,3,43 .减少   

  

  //reduce方法//函数:迭代数组,然后两两运算,最后返回值。//返回值:返回的结果//是否变化:no var arr=1,2,3,4;var ret=arr.reduce(function(a,b){ return a* b;});console . log(ret);//24 console . log(arr);//1,2,3,44 .过滤器   

  

  //过滤过滤//功能:过滤部分元素。//返回值:满足过滤条件的新数组。//是否改变原数组:no var arr=2,5,3,4;var ret=arr . filter(function(value){返回值3;});console . log(ret);//5,4 console . log(arr);//2,5,3,4参与互动   

  

  33.JS 块级作用域、变量提升   

  

  参考答案:   

  

  1.块级范围   

  

  JS的作用域包括全局作用域和函数作用域。没有块范围的概念。ECMAScript 6(简称ES6)有一个新的块级范围。block作用域由{}组成,if语句和for语句中的{}也属于block作用域。   

  

  2.可变促销   

  

  如果变量是在函数中声明的,则将变量声明提升到函数的开头。如果变量声明是全局变量,则将变量声明提升到全局范围的开头:   

  

  script type=' text/JavaScript“{ var a=1;console . log(a);//1 } console . log(a);//1//可以看出var定义的变量可以跨块范围访问。(函数A(){ var b=2;console . log(b);//2})();//console . log(b);//报错,//可见var定义的变量无法跨函数范围访问if(true){ var c=3;} console . log(c);//3 for(var I=0;I 4;I){ var d=5;};console.log(一);//4(循环结束时I已经是4了,所以这里I是4)console . log(d);//5//if语句和for语句中用var定义的变量可以在外部访问。//可以看出,if语句和for语句属于块作用域,不属于函数作用域。{ var a=1;设b=2;const c=3;{ console . log(a);//1子作用域可以访问父作用域的变量console . log(b);//2子作用域可以访问父作用域的变量console . log(c);//3子作用域可以访问父作用域的变量var aa=11让   

bb = 22; const cc = 33; } console.log(aa); // 11// 可以跨块访问到子 块作用域 的变量 // console.log(bb);// 报错bb is not defined // console.log(cc);// 报错cc is not defined} </script>拓展:

  

var、let、const 的区别

  

var 定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。let 定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。const 用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。同一个变量只能使用一种方式声明,不然会报错< script type = "text/javascript" > // 块作用域 { var a = 1; let b = 2; const c = 3; // c = 4; // 报错 // let a = 'a';// 报错 注:是上面 var a = 1; 那行报错 // var b = 'b';// 报错:本行报错 // const a = 'a1';// 报错 注:是上面 var a = 1; 那行报错 // let c = 'c';// 报错:本行报错 var aa; let bb; // const cc; // 报错 console.log(a); // 1 console.log(b); // 2 console.log(c); // 3 console.log(aa); // undefined console.log(bb); // undefined }console.log(a); // 1// console.log(b); // 报错// console.log(c); // 报错// 函数作用域(function A() { var d = 5; let e = 6; const f = 7; console.log(d); // 5 console.log(e); // 6 (在同一个{ }中,也属于同一个块,可以正常访问到) console.log(f); // 7 (在同一个{ }中,也属于同一个块,可以正常访问到)})();// console.log(d); // 报错// console.log(e); // 报错// console.log(f); // 报错</script>参与互动

  


  

34.null/undefined 的区别

  

参考答案:

  

null: Null 类型,代表“空值",代表一个空对象指针,使用 typeof 运算得到 “object",所以你可以认为它是一个特殊的对象值。

  

undefined: Undefined 类型,当一个声明了一个变量未初始化时,得到的就是 undefined。

  

参与互动

  


  

35.JS 哪些操作会造成内存泄露

  

参考答案:

  

1)意外的全局变量引起的内存泄露

  

function leak() { leak = "xxx"; //leak成为一个全局变量,不会被回收}2)闭包引起的内存泄露

  

function bindEvent() { var obj = document.createElement("XXX"); obj.οnclick = function() { //Even if it's a empty function };}闭包可以维持函数内局部变量,使其得不到释放。 上例定义事件回调时,由于是函数内定义函数,并且内部函数--事件回调的引用外暴了,形成了闭包。 解决之道,将事件处理函数定义在外部,解除闭包, 或者在定义事件处理函数的外部函数中,删除对 dom 的引用。

  

//将事件处理函数定义在外部function onclickHandler() { //do something}function bindEvent() { var obj = document.createElement("XXX"); obj.οnclick = onclickHandler;}//在定义事件处理函数的外部函数中,删除对dom的引用function bindEvent() { var obj = document.createElement("XXX"); obj.οnclick = function() { //Even if it's a empty function }; obj = null;}3)没有清理的 DOM 元素引用

  

var elements = { button: document.getElementById("button"), image: document.getElementById("image"), text: document.getElementById("text")};function doStuff() { image.src = "http://some.url/image"; button.click(): console.log(text.innerHTML)}function removeButton() { document.body.removeChild(document.getElementById('button'))}4)被遗忘的定时器或者回调

  

var someResouce = getData();setInterval(function() { var node = document.getElementById("Node"); if (node) { node.innerHTML = JSON.stringify(someResouce); }}, 1000);这样的代码很常见, 如果 id 为 Node 的元素从 DOM 中移除, 该定时器仍会存在, 同时, 因为回调函数中包含对 someResource 的引用, 定时器外面的 someResource 也不会被释放。

  

5)子元素存在引起的内存泄露

  

  

黄色是指直接被 js 变量所引用,在内存里,红色是指间接被 js 变量所引用,如上图,refB 被 refA 间接引用,导致即使 refB 变量被清空,也是不会被回收的子元素 refB 由于 parentNode 的间接引用,只要它不被删除,它所有的父元素(图中红色部分)都不会被删除。

  

6)IE7/8 引用计数使用循环引用产生的问题

  

function fn() { var a = {}; var b = {}; a.pro = b; b.pro = a;}fn();fn()执行完毕后,两个对象都已经离开环境,在标记清除方式下是没有问题的,但是在引用计数策略下,因为 a 和 b 的引用次数不为 0,所以不会被垃圾回收器回收内存,如果 fn 函数被大量调用,就会造成内存泄漏。在 IE7 与 IE8 上,内存直线上升。 IE 中有一部分对象并不是原生 js 对象。例如,其内存泄漏 DOM 和 BOM 中的对象就是使用 C++以 COM 对象的形式实现的,而 COM 对象的垃圾回收机制采用的就是引用计数策略。因此,即使 IE 的 js 引擎采用标记清除策略来实现,但 js 访问的 COM 对象依然是基于引用计数策略的。换句话说,只要在 IE 中涉及 COM 对象,就会存在循环引用的问题。

  

var element = document.getElementById("some_element");var myObject = new Object();myObject.e = element;element.o = myObject;上面的例子在一个 DOM 元素(element)与一个原生 js 对象(myObject)之间创建了循环引用。其中,变量 myObject 有一个名为 e 的属性指向 element 对象;而变量 element 也有一个属性名为 o 回指 myObject。由于存在这个循环引用,即使例子中的 DOM 从页面中移除,它也永远不会被回收。

  

看上面的例子,有人会觉得太弱了,谁会做这样无聊的事情,但是其实我们经常会这样做

  

window.οnlοad = function outerFunction() { var obj = document.getElementById("element"): obj.οnclick = function innerFunction() {};};这段代码看起来没什么问题,但是 obj 引用了 document.getElementById(“element”),而 document.getElementById(“element”)的 onclick 方法会引用外部环境中的变量,自然也包括 obj,是不是很隐蔽啊。

  

最简单的解决方式就是自己手工解除循环引用,比如刚才的函数可以这样

  

myObject.element = null;element.o = null;window.οnlοad = function outerFunction() { var obj = document.getElementById("element"): obj.οnclick = function innerFunction() {}; obj = null;};将变量设置为 null 意味着切断变量与它此前引用的值之间的连接。当垃圾回收器下次运行时,就会删除这些值并回收它们占用的内存。 要注意的是,IE9+并不存在循环引用导致 Dom 内存泄漏问题,可能是微软做了优化,或者 Dom 的回收方式已经改变

  

解析:

  

1、JS 的回收机制

  

JavaScript 垃圾回收的机制很简单:找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是实时的,因为其开销比较大,所以垃圾回收系统(GC)会按照固定的时间间隔, 周期性的执行。

  

到底哪个变量是没有用的?所以垃圾收集器必须跟踪到底哪个变量没用,对于不再有用的变量打上标记,以备将来收回其内存。用于标记的无用变量的策略可能因实现而有所区别,通常情况下有两种实现方式:标记清除和引用计数。引用计数不太常用,标记清除较为常用。

  

2、标记清除(mark and sweep)

  

js 中最常用的垃圾回收方式就是标记清除。当变量进入环境时,例如,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”。

  

function test() { var a = 10; //被标记,进入环境 var b = 20; //被标记,进入环境}test(); //执行完毕之后a、b又被标记离开环境,被回收3、引用计数(reference counting)

  

引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值(function object array)赋给该变量时,则这个值的引用次数就是 1。如果同一个值又被赋给另一个变量,则该值的引用次数加 1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减 1。当这个值的引用次数变成 0 时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为 0 的值所占用的内存。

  

function test() { var a = {}; //a的引用次数为0 var b = a; //a的引用次数加1,为1 var c = a; //a的引用次数加1,为2 var b = {}; //a的引用次数减1,为1}4、如何分析内存的使用情况

  

Google Chrome 浏览器提供了非常强大的 JS 调试工具,Memory 视图 profiles 视图让你可以对 JavaScript 代码运行时的内存进行快照,并且可以比较这些内存快照。它还让你可以记录一段时间内的内存分配情况。在每一个结果视图中都可以展示不同类型的列表,但是对我们最有用的是 summary 列表和 comparison 列表。 summary 视图提供了不同类型的分配对象以及它们的合计大小:shallow size (一个特定类型的所有对象的总和)和 retained size (shallow size 加上保留此对象的其它对象的大小)。distance 显示了对象到达 GC 根(校者注:最初引用的那块内存,具体内容可自行搜索该术语)的最短距离。 comparison 视图提供了同样的信息但是允许对比不同的快照。这对于找到泄漏很有帮助。

  

5、怎样避免内存泄露

  

1)减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收;

  

2)注意程序逻辑,避免“死循环”之类的 ;

  

3)避免创建过多的对象 原则:不用了的东西要及时归还。

  

参考

  

参与互动

  


  

36.重排与重绘的区别,什么情况下会触发?

  

参考答案:

  

1.简述重排的概念

  

浏览器下载完页面中的所有组件(HTML、JavaScript、CSS、图片)之后会解析生成两个内部数据结构(DOM 树和渲染树),DOM 树表示页面结构,渲染树表示 DOM 节点如何显示。重排是 DOM 元素的几何属性变化,DOM 树的结构变化,渲染树需要重新计算。

  

2.简述重绘的概念

  

重绘是一个元素外观的改变所触发的浏览器行为,例如改变 visibility、outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。由于浏览器的流布局,对渲染树的计算通常只需要遍历一次就可以完成。但 table 及其内部元素除外,它可能需要多次计算才能确定好其在渲染树中节点的属性值,比同等元素要多花两倍时间,这就是我们尽量避免使用 table 布局页面的原因之一。

  

3.简述重绘和重排的关系

  

重绘不会引起重排,但重排一定会引起重绘,一个元素的重排通常会带来一系列的反应,甚至触发整个文档的重排和重绘,性能代价是高昂的。

  

4.什么情况下会触发重排?

  

页面渲染初始化时;(这个无法避免)浏览器窗口改变尺寸;元素尺寸改变时;元素位置改变时;元素内容改变时;添加或删除可见的 DOM 元素时。5.重排优化有如下五种方法

  

将多次改变样式属性的操作合并成一次操作,减少 DOM 访问。如果要批量添加 DOM,可以先让元素脱离文档流,操作完后再带入文档流,这样只会触发一次重排。(fragment 元素的应用)将需要多次重排的元素,position 属性设为 absolute 或 fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。由于 display 属性为 none 的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行复杂的操作时,可以先隐藏它,操作完成后再显示。这样只在隐藏和显示时触发两次重排。在内存中多次操作节点,完成后再添加到文档中去。例如要异步获取表格数据,渲染到页面。可以先取得数据后在内存中构建整个表格的 html 片段,再一次性添加到文档中去,而不是循环添加每一行。参与互动

  


  

37.发布订阅设计模式

  

参考答案:

  

发布―订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。在JavaScript开发中,我们一般用事件模型来替代传统的发布―订阅模式。

  

解析:

  

发布订阅模式的构成最常见的发布订阅模式就是咱们DOM事件,仔细回想一下我们要给一个按钮,绑定一个事件,当我点击按钮的时候我要让他的颜色变了,并且页面弹出一个弹出框

  

我们分析一下这个流程:首先,我们得知道给哪个按钮的时候绑定事件,然后我们得知道触发事件以后需要干什么?

  

那么在这其中谁是发布者?

  

是DOM中的按钮,因为是在它身上绑定了事件,当我们点击按钮的时候它便向订阅者发布了这个消息

  

那么谁是订阅者?

  

是click事件,当点击按钮时,dom发布了一条消息,而事件订阅了它,所以当它被点击的时候,订阅者会接收到消息

  

简单例子上大学的时候甲要打游戏,下午的课不准备去了,然后甲跟乙说,如果下午老师问我去哪了,你就发信息告诉我。然后果然不出所料,下午老师来了,并且问了甲去哪了?然后乙发信息给甲,甲收到信息后干什么乙不知道,乙只是负责如果老师问了就发短信给甲。

  

参与互动

  


  

38.jsonp 优缺点?

  

参考答案:

  

jsonp 优缺点1.优点1.1 它不像 XMLHttpRequest 对象实现的 Ajax 请求那样受到同源策略的限制,JSONP 可以跨越同源策略;1.2 它的兼容性更好,在更加古老的浏览器中都可以运行,不需要 XMLHttpRequest 或 ActiveX 的支持1.3 在请求完毕后可以通过调用 callback 的方式回传结果。将回调方法的权限给了调用方。这个就相当于将 controller 层和 view 层终于分 开了。我提供的 jsonp 服务只提供纯服务的数据,至于提供服务以 后的页面渲染和后续 view 操作都由调用者来自己定义就好了。如果有两个页面需要渲染同一份数据,你们只需要有不同的渲染逻辑就可以了,逻辑都可以使用同 一个 jsonp 服务。2.缺点2.1 它只支持 GET 请求而不支持 POST 等其它类型的 HTTP 请求2.2 它只支持跨域 HTTP 请求这种情况,不能解决不同域的两个页面之间如何进行 JavaScript 调用的问题。2.3 jsonp 在调用失败的时候不会返回各种 HTTP 状态码。2.4 缺点是安全性。万一假如提供 jsonp 的服务存在页面注入漏洞,即它返回的 javascript 的内容被人控制的。那么结果是什么?所有调用这个 jsonp 的网站都会存在漏洞。于是无法把危险控制在一个域名下…所以在使用 jsonp 的时候必须要保证使用的 jsonp 服务必须是安全可信的参与互动

  


  

39.兼容各种浏览器版本的事件绑定

  

参考答案:

  

/*兼容低版本IE,ele为需要绑定事件的元素,eventName为事件名(保持addEventListener语法,去掉on),fun为事件响应函数*/function addEvent(ele, eventName, fun) { if (ele.addEventListener) { ele.addEventListener(eventName, fun, false); } else { ele.attachEvent("on" + eventNme, fun); }}参与互动

  


  

40.typescript 遇到过什么坑

  

参考答案:

  

main.ts 报错( Cannot find module './App.vue'.)

  

原因: typescript 不能识别.vue 文件

  

解决办法: 引入 vue 的 typescript declare 库

  

参与互动

  


  

41.this 和 apply 的应用

  

参考答案:比如求数组的最大值 Math.max.apply(this, 数组)

  

var numbers = <5, 458, 120, -215>;var maxInNumbers = Math.max.apply(this, numbers); //第一个参数也可以填Math或nullconsole.log(maxInNumbers); // 458var maxInNumbers = Math.max.call(this, 5, 458, 120, -215);console.log(maxInNumbers); // 458参与互动

相关文章