面试图谱未攻略内容
最近发现一个大佬总结的前端面试百科全书网站:面试图谱,感觉挺不错的,现在正在看,但现在水平不高肯定有些地方理解不了,在这里记录一下以便日后回顾。
未攻略内容
JS部分
模块化、防抖、节流、Promise实现、Generator实现
需反复巩固的内容
原型、模拟实现call,apply,bind
值 类型
0 Number
NaN Number
‘’(空字符串) String
false Boolean
null Object
undefined Undefined
typeof不能判断出数组和null,而且对于通过new操作符生成的对象,只会返回’object’
1 | alert(typeof null); //'object' |
但Object.prototype.toString对任何变量会永远返回这样一个字符串”[object class]”,而这个class就是JavaScript内嵌对象的构造函数的名字。至于用户自定义的变量,则class等于object。
1 | alert(Object.prototype.toString.call(null)); //'[object Null]' |
通过Object.prototype.toString可以获得的数据类型包括:Date, Object, String, Number, Boolean, Regexp, Function, undefined, null等。
1 | //var value=null; |
NaN值一般在试图把非数字形式的字符串转换为数字时产生。
上面的typeof和Object.prototype.toString.call(obj);都不能判断NaN值,而且NaN也不等同于它自己。
1 | alert(typeof NaN); //'number' |
1 | alert(isNaN('0')); //false |
undefined和null与任何有意义的值比较返回的都是false,但是null与undefined之间互相比较返回的是true。
一般typeof正则表达式都会返回’object’,但在Safari3.x版本中,返回的是’function’
1 | alert(undefined==null); //true |
严格相等运算符(===)有两个需要注意的例子:除了NaN===NaN返回false以外,+0===-0却返回true。所以ES6提出了Object.is()方法来比较两个值是否严格相等。
第一个参数是默认是 string 类型值,如果不是,会通过抽象的 ToString 强制转化成 string 类型的值。这其中就会有强制类型转换过程中的各种坑
第二个参数是 number 类型的进制,如果不是,会通过抽象的 ToNumber 强制转化成 number 类型的值,范围是 2-36,通过强制类型转换后如果是其他值会返回 NaN。在 ES5 之前如果没有传入这个参数,会根据第一个参数的开头来判断进制,0 开头的字符串会判断成八进制,也就是很多人提到的老黄历坑。ES5 之后已经解决,不传这个参数默认十进制。但是这个参数容易被忽略,尤其是在和 map 之类的也容易忽略后续可选参数的函数搭配使用的时候,比如
1 | ["1", "2", "3"].map(parseInt) // 结果是 [1, NaN, NaN] |
map方法在调用callback函数时,会给它传递三个参数:当前正在遍历的元素, 元素索引, 原数组本身.
第三个参数parseInt会忽视, 但第二个参数不会,也就是说,parseInt把传过来的索引值当成进制数来使用.从而返回了NaN。
即实际是下面这样:
1 | parseInt("1", 0); // 这是特例, 按照 0 进制转成数, 直接得本身 |
所以如果只是用 parseInt 来 “取整”,一个良好的习惯是永远记得设置第二个参数为 10
最后提一点,在ES6中将全局对象的parseInt()和parseFloat()移植到了Number对象上面,行为完全不变。但Number.isFinite()和Number.isNaN()则是在内层借用了全局的相应方法,所以只能说ES6在Number对象上提供了isFinite()和isNaN()方法。
1 | alert(isFinite===Number.isFinite); //false |
JavaScript 中的 number 类型的值都是使用 IEEE 754 标准的 64 位双精度浮点型存储,即 1 位符号位 + 11 位指数部分 + 52 位尾数部分 。用来表示整数时,安全的范围是 53 位,超出这个返回可能会造成精度丢失
1 | var num=-9999999.1234; |
关于其它的取整方法可以见博客中:“JS中的取整”
1 | console.log(~1); //-2 |
我们可以发现:-1 是唯一一个经过 ~ 运算返回假值0的值(包括其他那些特殊的值比如 NaN、{}、[] 等都不会返回假值)
所以字符串和数组的 indexOf 函数查找失败会返回 -1,这时候就可以用:
1 | if(~str.indexOf('str')) // 来表示查找失败 |
比判断 >= 0 或者 != -1 更优雅,跟用 !! 来判断非假值有异曲同工之妙
eg:取任意数字的任意二进制位上的值(不是1就是0)
eg:128的第一到第7位是0,第八位是1(128=10000000)1
2
3
4
5
6
7
8
9
10/*
主要方法是和1按位与,
如10000
&
00001,这样就能取到10000的最后一位数字
*/
function valueAtBit(num,bit){
return (num>>(bit-1)) & 1;
}
console.log(valueAtBit(128,8)); //1
JS取0~9的一个随机数可以用:1
(Math.random()+"").slice(-1); //eg从0.984652315464中复制最后一个数字4
看下面的这些东西之前,先好好看看高程的第六章面向对象部分!里面提到了很多基本概念,比如:
只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。
对原型所做的修改,能够立即在所有实例中得到反映。
因为new运算符会返回一个指向构造器函数原型的对象,所以通常情况下this就指向返回的这个对象。
其中new运算符创建对象的过程,实际上就是:
在Chrome和Firefox等向外暴露了对象proto属性的浏览器下,我们可以通过下面这段代码理解new运算的过程:
1 | function Person(name){ |
然后我们就能理解构造器模式是如何创建对象的了:
1 | function Point(x=10,y=6){ |
相关理解图示:原型继承示意图
最近做网页时,想做一个点击标题滑动出内容的模块,然后看了下参考的源码,结果发现有好几种做法。
解决方法是使用setTimeout延时display: none;的操作,因为我最终没有采用这种方法,留待以后检测。
首先肯定需要对Git的基本操作有一定的认识,这里肯定要放上浅显易懂的:廖雪峰老师的Git教程
看完后我们就应该对Git有个大体的认识了,然后一般用Git的人中我们分两类:一类就是自己在用着玩,那看完上面的教程差不多就可以自己去摸索了;第二类就是想要多人协作,进行一个项目开发或协同作业,所以我在这里就记一下这几天搞多人协作这块儿踩过的坑。
首先干一件事肯定是有个目标,我最近正在和同班同学搞一个网站的小项目,我们前端部分用的VSCode码代码,然后发现里面内置了Git,于是我们就兴冲冲的准备使用,经过一段时间摸索,自己add、commit、push到自己的GitHub时一点问题都没有,于是我们就准备多人协作了,在疯狂网上查找后,我们试出了三种方法。
具体操作可见:GitHub上如何进行PR(Pull Request)操作
这样可行,但各位仁兄不觉得太过麻烦了吗……而且还需要审核,对于那种开源项目来说肯定是有必要的,但如果就是想四五个人协同作业的话,可以选用下面两种方法。
如下图:
这个方法有一个缺点,那就是需要其他成员把自己的SSH与自己的Github远程库解绑,才能被项目拥有者绑定到这个项目上,所以这就不方便其他成员操作自己的GitHub了。
如下图:
综上看如果你是个小项目想多人协作的话,这是最简便的方法,不过这里需要注意一点:项目拥有者发送邀请后,被邀请协作的成员需要去自己的GitHub注册邮箱里面找一封确认信!!!可能被标记为垃圾邮件了!一定要确认,否则无法完成!
最后多人协作肯定会有冲突发生,以后再更新一下解决冲突的方法。
JavaScript中的this总是指向一个对象,而具体指向哪个对象是在**运行时**基于函数的执行环境动态绑定的。
有位人说A.apply(x,array);等价于(A.bind(x))(array),现在看着挺对的,留待以后验证。
当函数作为对象的方法被调用时,this指向该对象。
this总是指向全局对象,在浏览器中,这个全局对象就是window对象。
但在使用**严格模式**"use strict";时,this在函数调用模式不会指向全局对象window,而是undefined。
因为new运算符会返回一个指向构造器函数原型的对象,所以通常情况下this就指向返回的这个对象。
关于new运算符的内部具体操作请见我博客中的“JS中new运算符详解”!
但还有特殊的情况,比如构造器显式的返回了一个object类型的对象时,new调用构造器则会最终返回这个对象,而不是我们期待的this。
详情见我博客中的“JS中的apply()使用详解”一文,它的第一个参数可以改变函数体内this对象的指向。
如果我们传入的第一个参数是null或undefined,函数体内的this会指向全局对象,在浏览器中则是window。
1 | var func=function(a,b,c){ |
但如果是在严格模式下,则会严格执行第一个参数指定了函数体内this对象的指向,即传进来null,this就指向null;传进来undefined,this就指向undefined
1 | var func=function(a,b,c){ |
每个函数在被调用时都会自动取得两个特殊变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此闭包中永远不可能直接访问外部函数中的这两个变量,this一定是在这个闭包被调用时动态绑定的。如果想使用外层函数的this,最常用的方法就是找一个变量把它保存下来(eg:that)。
Function.prototype.bind,用来指定函数内部的this指向,其简化版实现可以这样模拟:
1 | Function.prototype.bind=function(context){ |
通常我们还会实现的稍微复杂一点,可以往func函数中预先填入一些参数:
1 | Function.prototype.bind=function(){ |
补充bind和call的返回值
返回由指定的this值和初始化参数改造的原函数拷贝
返回值是你调用的方法的返回值,若该方法没有返回值,则返回undefined。
最后我还有一个需要填的问题坑,留待以后实力提高后解决:JavaScript中Apply调用模式的this指向问题
它不能像数组一样,进行排序操作或者往集合里添加一个新的元素。
像Array.prototype.slice可以把arguments转成真正的数组;想截去arguments列表中头一个元素时,又可以借用Array.prototype.shift方法。
要了解这种机制的实现原理,需要查看一下V8引擎的源码,比如Array.prototype.push:
1 | function ArrayPush(){ |
可见Array.prototype.push实际上是一个属性复制的过程,把参数按照下标依次添加到被push的对象上面,顺便修改了这个对象的属性。所以只要是个对象,不管是数组对象还是类数组对象,都可以操作。
盒模型中上下左右边框交界处呈现平滑的斜线. 利用这个特点, 通过设置不同的上下左右边框宽度或者颜色可以得到小三角, 小梯形等。具体链接
使用border可以画很多与三角形有关的东东,比如我们经常见到的向上向下的“对号图标”就是使用两层border叠加生成的。
首先我们需要一个div和两个i,两个i就是用来叠加生成对号图标用的。
HTML:
1 | <div class="bottom"><!-- 这里换成top就是向上的对号--> |
CSS:
1 | .bottom{ |
然后下面关键的就来了,我们给第一个只设置上边框的话在这种情况下是个三角形:
然后我们可以给第二个再设置一个白色的三角形然后用绝对定位的偏移使它下移盖住灰色三角形的一部分:
1 | .bottom .arrow1{ |
然后我们一开始的那个向下的对号图标就出现啦,向上同理啦,下面就是向上向下放在一起的完整版CSS。
1 | .bottom,.top{ |