JavaScript专项刷题

  • JS语言是:
  • JS一种动态类型,弱类型,基于原型,直译式的脚本语言(解释性语言)
  • JS是一门单线程语言
  • 浏览器端的JavaScript包含ECMAScript,DOM对象以及BOM对象
  • JS语言不仅可以在浏览器环境运行,也可以在node提供的服务器端的平台运行。
  • JS不是面向对象的语言(有争议,但是牛客上遇到有个题的答案是这么说的
  • 变量作用域:
    当作用域中没有所需的变量时,会通过作用域链向上查找
  • 数据类型:
  • 基本/原始数据类型(值类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol(ES6-独一无二的值)
  • 引用数据类型(复杂类型):对象(Object)
  • BOM对象:
  • Navagator:提供有关浏览器的信息
  • Window:Window对象处于对象层次的最顶层,它提供了处理Navagator窗口的方法和属性
  • Location:提供了与当前打开的URL一起工作的方法和属性,是一个静态的对象
  • History:提供了与历史清单有关的信息
  • Document:包含与文档元素一起工作的对象,它将这些元素封装起来供编程人员使用
  • 静态语言和动态语言:
    静态语言(强类型语言):
    静态语言是在编译时变量的数据类型即可确定的语言,多数静态类型语言要求在使用变量之前必须声明数据类型。 如C++、Java、Delphi、C#等
    动态语言(弱类型语言):
    动态语言是在运行时确定数据类型的语言。变量使用之前不需要类型声明,通常变量的类型是被赋值的那个值的类型。如PHP/ASP/Ruby/Python/Perl/ABAP/SQL/JavaScript/Unix Shell等等。
  • new Boolean()
new Boolean(); // false
new Boolean(0); //false
new Boolean(null); //false
new Boolean(""); //false
new Boolean(NaN); //false
new Boolean(Symbol()); //true
  • JS常见事件:
    onkeypress:某个键盘的键被按下或按住
    onmousedown:某个鼠标按键被按下
    contextmenu:按下右键(添加contextmenu监听并返回false可以阻止弹出右键菜单)
    onblur:元素失去焦点 //通常用于代码验证(当用户离开表单输入域时)
    onfocus:元素获得焦点
  • 事件方法:
event.stopImmediatePropagation() //彻底的阻止事件, 在其之后的绑定在元素上的其他监听事件都不会触发

//阻止默认事件的默认操作
event.preventDefault(); //符合W3C标准
window.event.returnValue = false; //IE

//阻止冒泡
event.stopPropagation(); //符合W3C标准
window.event.cancelBubble = true; //IE
  • 逻辑判断——相等:
    ===严格相等运算符: 首先计算其操作数的值,然后比较这两个值,比较过程中没有任何类型转换(当类型和值都一致时才相等 )
    ==相等运算符: 如果两个操作数不是同一类型,那么会尝试进行一些类型转换,然后进行比较

(1)尽管null和undefined是不同的,但它们都表示“值的空缺”,两者往往可以互换,因此==运算符结果为true,但是===运算符结果为false

(2)NaN表示非数字值,特殊之处:它和任何值都不相等,包括自身。判断NaN的方法:x!=x返回true,说明x是NaN

  • 特殊需要记忆的:
NaN != NaN //true
null != 0 //true
undefined != 0 //true
false != null //true
false != undefined //true
undefined == null //true
[] == 0 //true
[] == true //false []会隐式转化为0
![] == false //true []被当成对象处理,所有对象都是true
[] == false  //true []被隐式转化为0
  • 相等运算符(补充):
  • 如果一个值是null,另一个值是undefined,则它们相等
  • 如果一个值是数字,另一个值是字符串,先将字符串转换为数字,然后使用转换后的值进行比较。
  • 如果其中一个值是true,则将其转换为1再进行比较。如果其中的一个值是false,则将其转换为0再进行比较。
  • 如果一个值是对象,另一个值是数字或字符串,则将对象转换为原始值,再进行比较。
  • 数据类型转换true/false:

数据类型

转换为true的值

转换为false的值

Boolean

true

false

String

非空字符串

空字符串

Number

非0(包括负数、infinity)

0和null

Object

任何对象

null(null不属于对象)

undefined

undefined

typeof null === 'object' //true
null instanceof Object //false
  • instanceof:
    instanceof在跨frame时会失效。
    判断类型时使用下述方法最为准确:
Object.prototype.toString.call(obj) === '[object ...]';
//比如
Object.prototype.toString.call(arr) === '[object Array]';
  • 数组排序:
    升序:a-b
    降序:b-a
  • 如果不给cookie设置过期时间,则coolie会在浏览器会话结束时过期。
  • this:
    1)当在函数调用的时候指向widow(特殊的是:IE中的attachEvent中的this总是指向全局对象window
    2)当方法调用的时候指向调用对象(谁调用指向谁)
    3)当用apply和call上下文调用的时候指向传入的第一个参数
    4)构造函数调用指向实例对象(new时指向新建的对象)
    5)严格模式下禁止this关键字指向全局对象

匿名函数调用时具有全局作用域

  • Math.round(x):
    如果参数的小数部分大于 0.5,则舍入到下一个绝对值更大的整数;
    如果参数的小数部分小于 0.5,则舍入到下一个绝对值更小的整数;
    如果参数的小数部分恰好等于0.5,则舍入到下一个在正无穷(+∞)方向上的整数。
    eg:
Math.round(11.5) //12
Math.round(-11.5) //-11
Math.round(-11.6) //-12

if(! "a" in window) {
    //判断window对象中是否有变量a
    ...
}
console.log("a" in window);  //true  var声明的全局变量会提前声明,所以为true
var a = 1;
  • 函数定义方式:
function add(a,b){return a+b;}  //函数声明
var add=function(a,b){return a+b;} //函数表达式
var add = new Function('a','b','return a+b') //Function构造函数(不推荐使用,影响函数解析性能)
  • slice()方法返回一个新的数组,不会破坏原数组
  • es6中没有枚举的概念
  • ng-style和ng-class:
    angluar中的绑定style和绑定class
    类似的还有:

给元素绑定监听: ng-click等
显示隐藏 : ng-show ng-hide
自带路由:ng-route
寄存方式:ng-template
指令绑定了 HTML 表单元素到 scope 变量中:ng-model
指定控制器ng-controller

  • Promise状态:
  • 异步操作“未完成”(pending)
  • 异步操作“已完成”(resolved,又称fulfilled)
  • 异步操作“失败”(rejected)

这种变化只能发生一次,一旦当前状态变为“已完成”或“失败”,就意味着不会再有新的状态变化了。因此,Promise对象的最终结果只有两种:

异步操作成功, Promise对象传回一个值,状态变为resolved。

异步操作失败, Promise对象抛出一个错误,状态变为rejected。

  • 跨域:
  • 域名、端口、协议任意一个不同,即为跨域
  • js可以使用jsonp进行跨域
  • 通过修改document.domain来跨子域
  • 使用window.name来进行跨域
  • 异步任务:
    异步任务分为宏任务微任务微任务优先级高于宏任务
    promise属于微任务,setTimeout属于宏任务
  • DOM中的children和childrenNodes:
    children :指DOM Object类型的子对象,不包括tag之间隐形存在的TextNode
    childrenNodes :指DOM Object类型的子对象,包括tag之间隐形存在的TextNode对象
  • JS的全局属性、函数:
    全局属性、函数

setTimeout不是JS的全局函数,它是window的方法

  • 页面的性能指标:
    白屏时间(first Paint Time) ——用户从打开页面开始到页面开始有东西呈现为止,也就是开始解析DOM耗时
    首屏时间 ——用户浏览器首屏内所有内容都呈现出来所花费的时间
    用户可操作时间(dom Interactive) ——用户可以进行正常的点击、输入等操作,默认可以统计domready时间,因为通常会在这时候绑定事件操作
  • map()遇到空位时:
    会跳过空位,但是输出结果会保留空位的值。

orEach(), filter(), reduce(), every() 和some()都会跳过空位。

map()会跳过空位,但会保留这个值。

join()和toString()会将空位视为undefined,而undefined和null会被处理成空字符串。

  • JS变量回收规则:
  • 全局变量不会 被回收。
  • 局部变量 被回收,也就是函数一旦运行完以后,函数内部的东西都会被销毁。
  • 只要被另外一个作用域所引用就不会 被回收
  • 变量类型判断:
    **typeof 能判断类型有:**number、string、boolean、symbol、undefined、object(object、array、null 的变量都返回 object);
    Object.prototype.toString(): Object 对象的实例方法,默认情况下(即不重写该方法),返回参数的类型字符串。
  • 能冒泡的事件
  • DNS:
  • DNS的作用是将域名翻译成IP地址。
  • DNS协议大多运行在UDP之上,但是当请求字节过长超过512字节时用TCP协议,将其分割成多个片段传输。
  • DNS协议默认端口号是53。
  • 操作系统的DNS缓存:windows DNS缓存的默认值是 MaxCacheTTL,它的默认值是86400s,也就是一天。macOS 严格遵循DNS协议中的TTL。
  • 浏览器的DNS缓存:1分钟到半小时不等
  • 严格模式:
    使用'use strict'来开启严格模式(可以开启整个文件,也可以开启部分代码块)
    严格模式下禁止this关键字指向全局对象。
  • iframe:
    局限:
  • 创建比一般的 DOM 元素慢了 1-2 个数量级
  • 阻塞页面加载
  • 唯一的连接池
    绝大部分浏览器,主页面和其中的 iframe 是共享连接池的(同域名可打开的连接是有限的)。这意味着 iframe 在加载资源时可能用光了所有的可用连接,从而阻塞了主页面资源的加载。
  • 不利于 SEO
  • History对象:
go() //加载history列表中的某个具体页面。
back() // 加载 history 列表中的前一个URL
forward() // 加载 history 列表中的下一个URL
length //返回浏览器历史列表中的URL数量
  • 闭包:
    作用:
  • 可以读取函数内部的变量
  • 可以把变量始终保存在内存中

写法:

  1. 一个函数(即外部函数)里面包含另一个函数(即内部函数),并且return返回这个内部函数, 然后内部函数在定义内部函数之外的作用域被调用,这时的内部函数就是一个闭包了。
  2. 内部函数引用了外部函数的变量,这个变量不会被销毁,因为闭包需要这个变量, 所以通过闭包可以访问闭包保存的变量。

局限:

  • 因为闭包的变量保存在内存中,内存泄漏,对内存的消耗很大。

闭包常用的地方:

  • es5 for循环的事件监听
  • 函数里使用了定时器
  • 封装许多高级的功能集
  • JS数组对象方法:
    Array对象
  • reflow(回流\重新布局)和repaint(重绘):
  • 位置改变->reflow->repaint
  • 显示样式改变(颜色等)->repaint

repaint速度明显快于repaint,在开发中要尽量避免reflow,并减少repaint

  • 可能导致reflow的操作:
  • 改变窗口大小
  • 改变文字大小
  • 内容改变(在输入框中输入内容)
  • 激活伪类(如:hover)
  • 操作(改变)class属性
  • 脚本操作DOM
  • 计算offsetWidthoffsetHeight
  • 设置style属性
  • 浮点数精度:
  • toFixed 把数字转换为字符串,结果的小数点后有指定位数的数字
  • toPrecision 把数字格式化为指定的长度
  • Math.round 把一个数字舍入为最接近的整数
  • 运算符隐式转换:
    +: 有两个含义:第一个含义是做字符串拼接,第二个含义是加减法中的加法。==如果操作数里有一个是字符串,其他的值将被转换成字符串;==其他情况,操作数转换成数字执行加法运算。
    -: 只有一个含义,做数值的减运算。
    当加减号进行数值运算是,若存在NaN,则结果为NaN
console.log(1+ "2"+"2"); //1 -> "122"
console.log(1+ +"2"+"2"); //2 -> "32"
console.log("A"- "B"+"2"); //3 -> "NaN2"
console.log("A"- "B"+2); //4 -> NaN
console.log("10"+3-"1") //5 -> 102
  1. 先执行字符串拼接运算,得到字符串"12",在进行2个字符串的拼接运算,得到字符串"122"
  2. 执行1+ +"2"时,+"2"为一元运算符运算,相当于Number()函数==(注意不是取正运算)==,会将后面的变量先转换为Number再进行运算,所以得到数值2,在与数值1相加得到Number3;再与后面的字符串进行拼接运算,得到字符串结果"32"
  3. -运算符只会执行数值减运算,但运算符两边转换为Number为NaN,所以得到NaN,再与后面的字符串进行拼接运算,得到结果NaN2
  4. 前段与第3题一致,得到NaN,与后面的数值2进行加运算,NaN+2=NaN,所以结果为NaN
  5. 先执行字符串拼接运算,得到字符串"103",再执行数值减运算,得到数值结果102
  • 字符串拼接效率问题:
    直接使用字符串+运算,会新建一个临时字符串,将新字符串赋值为拼接后的结果,然后返回这个临新字符串并同时销毁原始字符串。效率较低(类似Java)
    当数据量比较大时的拼接方法: 将字符串push进一个空数组tempArr,然后tempArr.join()来获得字符串。

tempArr.toString()会将item的分隔符’,'也输出,所以不可以用toString()

  • Ajax:
  • Ajax不是新的编程语言,而是一门提供网页局部刷新的技术。
  • Ajax最大的优点是在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页内容。
  • Ajax技术核心就是XMLHttpRequest对象。
  • Ajax技术的工作原理
    1)创建Ajax对象:
    var xhr = new XMLHttpRequest();
    2)xhr 发送请求:
    xhr.open(‘get’,‘test.html’,‘true’);
    xhr.send();
    3)xhr获取响应:
xhr.onreadystatechange = function(){

if(xhr.readystate == 4){//请求的状态码

/*

0:请求还没有建立(open执行前)

1:请求建立了还没发送(执行了open)

2:请求正式发送(执行了send)

3:请求已受理,有部分数据可以用,但还没有处理完成

4:请求完全处理完成

*/

alert(xhr.responseText);//返回的数据

}

}
  • Ajax和Flash的对比:
    Ajax的优势:
    1.可搜索性 2.开放性 3.费用 4.易用性 5.易于开发
    Ajax的劣势:
  1. 它可能破坏浏览器的后退功能
  2. 使用动态页面更新使得用户难于将某个特定的状态保存到收藏夹中

Flash的优势:

1.多媒体处理 2.兼容性 3.矢量图形

4.客户端资源调度(容易调用客户端之外的内容,比如摄像头、麦克风等)

Flash的劣势:

1.二进制格式 2.格式私有 3.文件经常会很大,第一次使用的时候需要等待时间 4.性能问题

  • web的生命周期:
    web的生命周期
  • 对象的for…in方法:
    对象的for…in属性是遍历对象的key
  • 块级元素的总宽度:
    块级元素的总的宽度=左右padding+左右border+内容区的width。
    我们实际设置的width指的就是内容区的width,所以当改变padding、border、width中的任一项的时候,块元素的总宽度都会发生变化。
  • 触摸事件:
    ouchstart: //手指放到屏幕上时触发
    touchmove: //手指在屏幕上滑动式触发
    touchend: //手指离开屏幕时触发
    touchcancel: //系统取消touch事件的时候触发,这个好像比较少用
    每个触摸事件被触发后,会生成一个event对象,event对象里额外包括以下三个触摸列表
    touches: //当前屏幕上所有手指的列表(多点触控)
    targetTouches: //当前dom元素上手指的列表,尽量使用这个代替touches
    changedTouches: //涉及当前事件的手指的列表,尽量使用这个代替touches
  • Number的小数点(.):
    将一个数值型转换为字符串:
2.toString() //错误Uncaught SyntaxError: Invalid or unexpected token

因为JS引擎会优先将.解析为数字的小数点,所以上述就被解析成了:

(2)toString

为了避免上述问题,应该写成:

2..toString()
2 .toString()
(2).toString()
  • 原型对象:
    hasOwnProperty: 是用来判断一个对象是否有你给出名称的属性或对象。不过需要注意的是,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。
    isPrototypeOf : 是用来判断要检查其原型链的对象是否存在于指定对象实例中,是则返回true,否则返回false。
  • Number()函数:
    结果为0的:
Number() //0
Number(0) //0
Number('') //0
Number('0') //0
Number(false) //0
Number(null) //0
Number([]) //0
Number([0]) //0

结果是NaN的:

Number(undefined) //NaN
  • parseInt:
    parseInt()接受2个参数,第一个是要转换为整数的字符串,第二个是进制。
    ***关于javascript的说法错误的有 关于js说法不正确的是_字符串:***paraseInt使用时,若第一个参数不是字符串,则会将其隐式转换为字符串类型的。
    结果为NaN的:
parseInt("") //NaN
parseInt(null) //NaN
parseInt(undefined) //NaN
  • jQuery选择器:
    常用有三种:
    ①元素选择器:$(TagName) ②ID 选择器:$(#Id) ③类选择器:$(.className)

removeClass():删除class。

addClass():添加class。

remove():把元素从元素中删除(包括所有的文本和子节点)。

add():把元素添加到已有元素中(包括所有的文本和子节点)。

  • 块内函数定义:
  • 不要在块内声明一个函数(严格模式会报语法错误)。如果确实需要在块中定义函数,可以使用函数表达式来声明函数。
  • 块内声明的变量只要没加var 都算作全局变量。
  • ES5看起来像支持块级作用域,实际上只有函数作用域和全局作用域。
  • ES6才规定块级作用域。
if (x) {  function foo() {}} //因为有函数声明提前,所以相当于声明了一个全局匿名函数(在if内叫foo)
if (x) {  foo = function() {}} //没有var,所以是全局函数foo
if (x) {  var foo = function() {}} //块级函数foo
  • 模块引入机制:
    Q:在文件/home/somebody/workspace/somemodule.js中第一行引用了一个模块:require(‘othermodule‘),请问required 的查找模块的顺序是?
    A:
  1. CORE MODULES named othermodule(核心模块)
  2. /home/somebody/workspace/node_modules/othermodule. js (当前路径的js)
  3. /home/somebody/workspace/node_modules/othermodule/index.js(当前路径的同名文件夹下的index.js)
  4. /home/somebody/node_modules/othermodule/index.js (node_modules下的模块)
  • JS标准事件模型的触发顺序:
    事件捕获->事件处理->事件冒泡
  • ★★★★★
var foo = {n:1};
(function(foo){            //形参foo同实参foo一样指向同一片内存空间,这个空间里的n的值为1
    var foo;               //优先级低于形参,无效。
    console.log(foo.n);    //输出1
    foo.n = 3;             //形参与实参foo指向的内存空间里的n的值被改为3
    foo = {n:2};           //形参foo指向了新的内存空间,里面n的值为2.
    console.log(foo.n);    //输出新的内存空间的n的值
})(foo);
console.log(foo.n);        //实参foo的指向还是原来的内存空间,里面的n的值为3.

输出:1,2,3

  • in操作符:
    判断一个属性(key)是否属于一个对象,对于数组来说,key是下标。
1 in [1] //false 因为数组长度为1,所以下标只有0,1不在其中
  • 1 && 2>1 :
    &&优先级低于>,所以先算2>1 为 true,原题变为:1 && true,操作符短路,所以结果为1。
  • Document对象的属性和方法:
    Document对象的属性和方法
  • 字符串与字符串对象:
  • JS 中值的类型分为原始值类型和对象类型。原始值类型包括 number, string, boolean, null 和 undefined;对象类型即 object。首先原始值类型它就不是对象
  • 另外,要注意 ‘hello’ 和 new String(‘hello’) 的区别,前者是字符串字面值,属于原始类型,而后者是对象。用 typeof 运算符返回的值也是完全不一样的:
typeof 'hello';  // 'string'
typeof new String('hello');  // 'object'
  • 之所以很多人分不清字符串字面值和 String 对象,归根结底就是 JS 的语法对你们太过纵容了。当执行 ‘hello’.length 时,发现可以意料之中的返回 5,你们就觉得 ‘hello’ 就是 String 对象,不然它怎么会有 String 对象的属性。其实,这是由于 JS 在执行到这条语句的时候,内部将 ‘hello’ 包装成了一个 String 对象,执行完后,再把这个对象丢弃了,这种语法叫做 “装箱”,在其他面向对象语言里也有(如 C#)。
  • JS继承:
  • 原型链继承;
  • 借助构造函数继承;
  • 组合继承;
  • 原型式继承;
  • 寄生式继承;
  • 寄生组合式继承。
  • JS跨域:
  • 第一种方式:jsonp请求;jsonp的原理是利用

/ES6 class区别](https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/20):**

  1. es6的class的声明会提前,但不会初始化赋值,类似letconst,会存在暂时性死区(TDZ);
  2. es6的class声明的内部会启用严格模式;
  3. es6的class的所有方法(包括静态方法和实例方法)都是不可枚举的;
  4. es6的class的多有方法(包括静态方法和实例方法)都没有原型对象prototype,所以也没有[[construct]],不能使用new来调用;
  5. es6必须使用new来调用class
  6. es6的class内部无法重写类名。
function Bar() {
  Bar = 'Baz'; // it's ok,重写后Bar就为string,不再是function(前提是调用一次)
  this.bar = 42;
}
const bar = new Bar();
// Bar: 'Baz'
// bar: Bar {bar: 42}  

class Foo {
  constructor() {
    this.foo = 42;
    Foo = 'Fol'; // TypeError: Assignment to constant variable
  }
}
const foo = new Foo();
Foo = 'Fol'; // it's ok