热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【面试笔记】js面试25题笔记

2019独角兽企业重金招聘Python工程师标准自测链接在js25题、js21题或者js85题测验你的知识掌握。js25题笔记1.使用typeofbarobject可

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

 

自测链接>> 在js25题、js21题或者js85题测验你的知识掌握。

js25题笔记

1. 使用typeof bar === "object" 可能遇到的陷阱和解决方法

在 Javascript 里使用 typeof 来判断数据类型,只能区分基本类型,即 “number”,”string”,”undefined”,”boolean”,”object” 五种。

陷阱:如果bar是null,js会视之为object类型。

解决:判断bar是object但非null: 

console.log((bar !== null) && (typeof bar === "object"));

扩展:判断bar是数组:  typeof只能区分基本类型,它将function,array,object都视为object类型,所以要区分这三类对象就不能用typeof方法了,可以用toString.call()的返回值来判断:

console.log((bar !== null) && (typeof bar === "object") && (! $.isArray(bar)));

或者用jq的isArray() isFunction()来判断:

onsole.log((bar !== null) && (typeof bar === "object") && (toString.call(bar) !== "[object Array]"));

ECMA 5.1 中关于Object.prototype.toString.call() 的描述:

When the toString method is called, the following steps are taken:

If the this value is undefined, return “[object Undefined]“.

If the this value is null, return “[object Null]“.

Let O be the result of calling ToObject passing the this value as the argument.

Let class be the value of the [[Class]] internal property of O.

Return the String value that is the result of concatenating the three Strings “[object ", class, and "]“.

对所有值类型应用 Object.prototype.toString.call() 方法结果如下:

console.log(Object.prototype.toString.call(123)) //[object Number]
console.log(Object.prototype.toString.call('123')) //[object String]
console.log(Object.prototype.toString.call(undefined)) //[object Undefined]
console.log(Object.prototype.toString.call(true)) //[object Boolean]
console.log(Object.prototype.toString.call({})) //[object Object]
console.log(Object.prototype.toString.call([])) //[object Array]
console.log(Object.prototype.toString.call(function(){})) //[object Function]

2.不要写容易引起误会的代码

(function(){var a = b = 3;
})();console.log("a defined? " + (typeof a !== 'undefined'));
console.log("b defined? " + (typeof b !== 'undefined'));

陷阱: 误以为函数内相当于

var b = 3;
var a = b;

事实上是

b = 3;
var a = b;

因此如果不是在strict mode下,b被当成全局变量。所以应该是输出b有定义,a无定义。

3.在内联函数中,ECMA5之前this指向window,而在ECMA5 内联函数的this变成undefined。

4.闭包的应用

闭包的例子:

function f1(){var privateA = 1; function f2(){//相当于getter方法return privateA;};f3 = function(n){//相当于setter方法,注意,这里的f3是一个全局变量privateA = n;};return f2;
}
var f4 = f1();
console.log(f4());//1
f3(2);
console.log(f4());//2

闭包的特点和作用:

1.保护函数内的变量安全,限定访问接口,实现JS私有属性和私有方法。f1的变量只有f2能访问,f2相当于f1私有变量的getter方法。

2.在内存中维持一个变量。f4持有f2,f2引用着f1,因此f4存在的时候,f2和f1也会驻留在内存中(GC不会回收,因此使用闭包时也要留意内存泄露的问题)

5.jQ为了处理多库共存,使用noConflict()来转移$使用权,而立即调用表达式可以在加载时就初始化,形成一个单例模式的效果,故而使用立即调用表达式可以解决js变量污染问题。如果jq的$使用权转移之后还想用jq,结合立即调用表达式的作用,下面这个方法使我们仍然能使用jq:

(function($) { /* jQuery plugin code referencing $ */ } )(jQuery);

示例:









6.use strict 使用严格模式有什么好处

7.return的陷阱

当return单独处于一行时,Javascript会自动补全为return;









8.NaN的陷阱

NaN表示一个非数字类型的值。与任何值比较都返回false,包括它自己。用数学函数操作都会返回NaN。

var a = NaN;
console.log(a);//NaN
console.log(a===a);//false
console.log(a>0);//false
console.log(Math.max(a));//NaN

但是使用typeof比较时却会判断它为数值类型。

console.log(typeof NaN === "number"); // "true"

判断NaN的方法可以用isNaN(),虽然这个方法存在不足, 有一个更好的方法是使用Number.isNaN()

Number.isNaN(NaN); // true
Number.isNaN(Number.NaN); // true
Number.isNaN(0 / 0) // true// 使用全局的isNaN(),下面会返回true
Number.isNaN("NaN"); // false
Number.isNaN(undefined); // false
Number.isNaN({}); // false
Number.isNaN("blabla"); // false
isNaN("NaN"); // true
isNaN(undefined); // true
isNaN({}); // true
isNaN("blabla"); // true// 使用Number.isNaN()和全局isNaN()都返回false
Number.isNaN(true);
Number.isNaN(null);
Number.isNaN(37);
Number.isNaN("37");
Number.isNaN("37.37");
Number.isNaN("");
Number.isNaN(" ");

9.for循环中变量作用域的问题

for (var i &#61; 0; i <5; i&#43;&#43;) {var btn &#61; document.createElement(&#39;button&#39;);btn.appendChild(document.createTextNode(&#39;Button &#39; &#43; i));btn.addEventListener(&#39;click&#39;, (function(i) {return function() { console.log(i); };})(i));document.body.appendChild(btn);
}

学ECMAScript 6的时候遇过这个问题&#xff0c;点击任意按钮都是输出5&#xff0c;因为在onclick触发前&#xff0c;for循环已经结束了&#xff0c;点击按钮时输出的i是for循环结束后的i&#xff0c;所以都是5.为了输出0&#xff0c;1&#xff0c;2&#xff0c;3这样的值&#xff0c;我们可以从i的作作用域和onclick的执行时机下手。以下有三个方法&#xff0c;其中前两个方法是基于i的作用域处理&#xff0c;后一个则是限制onclick的执行时机&#xff08;用了立即调用方式&#xff09; 

for (let i &#61; 0; i <5; i&#43;&#43;) { //let让i的作用域在每次执行循环时都独立出来 var btn &#61; document.createElement(&#39;button&#39;);btn.appendChild(document.createTextNode(&#39;Button &#39; &#43; i));btn.addEventListener(&#39;click&#39;, (function(i) {return function() { console.log(i); };})(i));document.body.appendChild(btn);
}

[&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;, &#39;e&#39;].forEach(function (value, i) { //[&#39;a&#39;, &#39;b&#39;, &#39;c&#39;, &#39;d&#39;, &#39;e&#39;]同样是将每次循环的i分隔开来var btn &#61; document.createElement(&#39;button&#39;);btn.appendChild(document.createTextNode(&#39;Button &#39; &#43; i));btn.addEventListener(&#39;click&#39;, function() { console.log(i); });document.body.appendChild(btn);
});

for (var i &#61; 0; i <5; i&#43;&#43;) {var btn &#61; document.createElement(&#39;button&#39;);btn.appendChild(document.createTextNode(&#39;Button &#39; &#43; i));(function (i) {btn.addEventListener(&#39;click&#39;, function() { console.log(i); });})(i);//立即调用表达式使btn.addEventListener在循环中完成初始化并加载document.body.appendChild(btn);
}

10.reverse,push,concat的使用

var arr1 &#61; "john".split(&#39;&#39;);
var arr2 &#61; arr1.reverse();
var arr3 &#61; "jones".split(&#39;&#39;);
arr2.push(arr3);
console.log("array 1: length&#61;" &#43; arr1.length &#43; " last&#61;" &#43; arr1.slice(-1));
console.log("array 2: length&#61;" &#43; arr2.length &#43; " last&#61;" &#43; arr2.slice(-1));
//输出&#xff1a;
//"array 1: length&#61;5 last&#61;j,o,n,e,s"
//"array 2: length&#61;5 last&#61;j,o,n,e,s"

通过上面这段代码来巩固reverse,push和concat的使用。

首先&#xff0c;reverse会改变数组本身&#xff08;arr1&#xff09;并且返回一个数组引用&#xff08;不是返回数组arr1&#xff0c;是返回arr1的引用&#xff09;&#xff0c;因此arr2 &#61; arr1.reverse() 使得arr2指向arr1&#xff0c;从而对arr2的操作也会映射到arr1上。

此时arr1与arr2指向同一个对象&#xff0c;值为[ &#39;n&#39; , &#39;h&#39; , &#39;o&#39; , &#39;j&#39; ]。

其次&#xff0c;push在插入一个数组时&#xff0c;会把数组当成一个元素插进去&#xff0c;而且直接改变数组。因此arr2.push(arr3)的结果是[ &#39;n&#39; , &#39;h&#39; , &#39;o&#39; , &#39;j&#39; ,[&#39;j&#39; ,&#39;o&#39;, &#39;n&#39; ,&#39;e&#39; ,&#39;s&#39;]]。从中我们知道push和concat的区别就是concat是将数组中的元素一个一个拼接到前一个数组中&#xff0c;而且不直接改变对象&#xff0c;要将拼接后的对象重新返回给原对象&#xff08;使用时 arr &#61; arr.concat(xxx);  <&#61;&#61; > arr.push(xxx);&#xff09;。而push是把元素整个放入对象结尾&#xff0c;所以遇到数组时push是往数组中放入array对象&#xff0c;concat是拼接数组。

因此在上面这段代码中&#xff0c;输出arr1最后一个元素时便输出了arr3这个数组&#xff08;push时arr3被当作最后一个元素加入arr1指向的数组对象&#xff09;&#xff0c;而arr1和arr2指向的对象相同&#xff0c;所以输出两者内容都是一样的。

 11.利用事件队列解决堆栈溢出

下面这份代码在list特别大的时候会导致堆栈溢出

var list &#61; readHugeList();var nextListItem &#61; function() {var item &#61; list.pop();if (item) {// process the list item...nextListItem();}
};

 可以巧妙地用事件队列解决这个问题

var list &#61; readHugeList();var nextListItem &#61; function() {var item &#61; list.pop();if (item) {// process the list item...setTimeout( nextListItem, 0);}
};

通过上面的方法&#xff0c;用事件队列处理递归&#xff0c;而不是调用堆栈。当运行nextListItem时&#xff0c;如果item不为空&#xff08;未到列表最后一个&#xff09;&#xff0c;这个计时方法&#xff08;nextListItem&#xff09;会被加入事件队列&#xff0c;同时该方法也就退出了调用堆栈&#xff0c;这样nextListItem方法会被一直加入到事件队列&#xff0c;知道item为空时开始逐个执行事件队列里的方法。与此同时&#xff0c;调用堆栈一直为空。

12. || 与 &&

0 || 1 &#61; 1  //0为false&#xff0c;继续计算下一个操作数1&#xff0c;最终得到1
1 || 2 &#61; 1  //1为true&#xff0c;忽略下一个操作数2&#xff0c;最终得到1
0 && 1 &#61; 0 //0为false&#xff0c;忽略下一个操作数1&#xff0c;最终得到0
1 && 2 &#61; 2 //1为true&#xff0c;继续计算下一个操作数1&#xff0c;最终得到2

13. &#61;&#61; 与 &#61;&#61;&#61;

&#61;&#61;判断值相等&#xff0c;&#61;&#61;&#61;判断值与类型均相同。

14.js在设置对象属性时&#xff0c;会自动吧参数字符串化。

var a&#61;{},b&#61;{key:&#39;b&#39;},c&#61;{key:&#39;c&#39;};a[b]&#61;123;
a[c]&#61;456;console.log(a[b]); //456

原因&#xff1a;b和c都是object&#xff0c;放入a时字符串化得到[object object] 。因此a[b],a[c]其实都是a["[object object]"]&#xff0c;输出的值自然就是最后赋值的那一个了。

15.bind的用法&#xff08;IE678不支持&#xff09;

var hero &#61; {_name: &#39;John Doe&#39;,getSecretIdentity: function (){return this._name;}
};var stoleSecretIdentity &#61; hero.getSecretIdentity;//undefinedconsole.log(stoleSecretIdentity());//John Doevar stoleSecretIdentity2 &#61; hero.getSecretIdentity.bind(hero);//John Doe

 


转:https://my.oschina.net/u/2368420/blog/732177



推荐阅读
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • Final关键字的含义及用法详解
    本文详细介绍了Java中final关键字的含义和用法。final关键字可以修饰非抽象类、非抽象类成员方法和变量。final类不能被继承,final类中的方法默认是final的。final方法不能被子类的方法覆盖,但可以被继承。final成员变量表示常量,只能被赋值一次,赋值后值不再改变。文章还讨论了final类和final方法的应用场景,以及使用final方法的两个原因:锁定方法防止修改和提高执行效率。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • Java实战之电影在线观看系统的实现
    本文介绍了Java实战之电影在线观看系统的实现过程。首先对项目进行了简述,然后展示了系统的效果图。接着介绍了系统的核心代码,包括后台用户管理控制器、电影管理控制器和前台电影控制器。最后对项目的环境配置和使用的技术进行了说明,包括JSP、Spring、SpringMVC、MyBatis、html、css、JavaScript、JQuery、Ajax、layui和maven等。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
author-avatar
对方尽快
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有