前端面试题集锦——JavaScript

Posted 合众汇才

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端面试题集锦——JavaScript相关的知识,希望对你有一定的参考价值。


javascript

栈和队列的区别?

栈的插入和删除操作都是在一端进行的,而队列的操作却是在两端进行的。

队列先进先出,栈先进后出。

栈只允许在表尾一端进行插入和删除,而队列只允许在表尾一端进行插入,在表头一端进行删除

栈和堆的区别?

栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。

堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收。

堆(数据结构):堆可以被看成是一棵树,如:堆排序;

栈(数据结构):一种先进后出的数据结构。

浏览器端的js包括哪几个部分?

核心( ECMAScript) , 文档对象模型(DOM), 浏览器对象模型(BOM)

介绍js有哪些内置对象?

Object 是 JavaScript 中所有对象的父对象

数据封装类对象:Object、Array、Boolean、Number 和 String

其他对象:Function、Arguments、Math、Date、RegExp、Error

基本类型与引用类型有什么区别?

基本数据类型有: Undefined、Null、Boolean、Number、String

引用类型则有: Object, Array, Date, RegExp, Function

区别:

  1. 存储

    • 基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中

    • 引用类型的值是对象, 保存在堆内存中. 包含引用类型的变量实际上包含的并不是对象本身, 而是一个指向改对象的指针

  2. 复制

    • 从一个变量向另一个变量复制基本类型的值, 会创建这个值的一个副本

    • 从一个变量向另一个变量复制引用类型的值, 复制的其实是指针, 因此两个变量最终都指向同一个对象

  3. 检测类型

    • 确定一个值是哪种基本类型可以用typeof操作符

    • 确定一个值是哪种引用类型可以使用instanceof操作符

JavaScript有几种类型的值?,你能画一下他们的内存图吗?

栈:原始数据类型(Undefined,Null,Boolean,Number、String)

堆:引用数据类型(对象、数组和函数)

两种类型的区别是:存储位置不同;

原始数据类型直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;

null,undefined 的区别?

null 表示一个对象被定义了,值为“空值”;

undefined 表示不存在这个值。

typeof undefined //"undefined"

undefined :是一个表示"无"的原始值或者说表示"缺少值",就是此处应该有一个值,但是还没有定义。当尝试读取时会返回 undefined;

例如变量被声明了,但没有赋值时,就等于undefined

typeof null //"object"

null : 是一个对象(空对象, 没有任何属性和方法);

例如作为函数的参数,表示该函数的参数不是对象;

注意:在验证null时,一定要使用 === ,因为 == 无法分别 null 和 undefined

再来一个例子:

null
Q:有张三这个人么?
A:有!
Q:张三有房子么?
A:没有!

undefined
Q:有张三这个人么?
A:没有!

参考阅读:undefined与null的区别

说几条写JavaScript的基本规范?

  1. 不要在同一行声明多个变量。

  2. 请使用 ===/!==来比较true/false或者数值

  3. 使用对象字面量替代new Array这种形式

  4. 不要使用全局函数。

  5. Switch语句必须带有default分支

  6. 函数不应该有时候有返回值,有时候没有返回值。

  7. for循环必须使用大括号

  8. if语句必须使用大括号

  9. for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染。

eval是做什么的?

它的功能是把对应的字符串解析成JS代码并运行;

应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。

由JSON字符串转换为JSON对象的时候可以用eval,var obj =eval('('+ str +')');

javascript 代码中的"use strict";是什么意思 ? 使用它区别是什么?

use strict是一种ECMAscript 5 添加的(严格)运行模式,这种模式使得 Javascript 在更严格的条件下运行。

使用它区别是:

  • 使JS编码更加规范化的模式,消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为。

  • 默认支持的糟糕特性都会被禁用,比如不能用with,也不能在意外的情况下给全局变量赋值;

  • 全局变量的显示声明,函数必须声明在顶层,不允许在非函数代码块内声明函数,arguments.callee也不允许使用;

  • 消除代码运行的一些不安全之处,保证代码运行的安全,限制函数中的arguments修改,严格模式下的eval函数的行为和非严格模式的也不相同;

  • 提高编译器效率,增加运行速度;

  • 为未来新版本的Javascript标准化做铺垫。

["1", "2", "3"].map(parseInt) 答案是多少?

[1, NaN, NaN]

因为 parseInt 需要两个参数 (val, radix),其中 radix 表示解析时用的基数。

map 传了 3 个 (element, index, array),对应的 radix 不合法导致解析失败。

parseInt方法将会通过以下方式被调用

parseInt("1", 0)
parseInt("2", 1)
parseInt("3", 2)

parseInt的第二个参数radix为0时,ECMAScript5将string作为十进制数字的字符串解析;
parseInt的第二个参数radix为1时,解析结果为NaN;
parseInt的第二个参数radix在2—36之间时,如果string参数的第一个字符(除空白以外),不属于radix指定进制下的字符,解析结果为NaN。
parseInt("3", 2)执行时,由于"3"不属于二进制字符,解析结果为NaN。

快速 排序的思想并实现一个快排?

“快速排序”的思想很简单,整个排序过程只需要三步:

(1)在数据集之中,找一个基准点

(2)建立两个数组,分别存储左边和右边的数组

(3)利用递归进行下次比较

<script type="text/javascript">

    function quickSort(arr){
        if(arr.length<=1){
            return arr;//如果数组只有一个数,就直接返回;
        }

        var num = Math.floor(arr.length/2);//找到中间数的索引值,如果是浮点数,则向下取整

        var numValue = arr.splice(num,1);//找到中间数的值
        var left = [];
        var right = [];

        for(var i=0;i<arr.length;i++){
            if(arr[i]<numValue){
                left.push(arr[i]);//基准点的左边的数传到左边数组
            }
            else{
               right.push(arr[i]);//基准点的右边的数传到右边数组
            }
        }

        return quickSort(left).concat([numValue],quickSort(right));//递归不断重复比较
    }

    alert(quickSort([32,45,37,16,2,87]));//弹出“2,16,32,37,45,87”

</script>

Javascript作用链域?

全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节。

当需要从局部函数查找某一属性或方法时,如果当前作用域没有找到,就会上溯到上层作用域查找,直至全局函数,这种组织形式就是作用域链。

作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的。

什么是闭包(closure),为什么要用它?

闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。

使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念

闭包的特性:

  1. 函数内再嵌套函数

  2. 内部函数可以引用外层的参数和变量

  3. 参数和变量不会被垃圾回收机制回收

//li节点的onclick事件都能正确的弹出当前被点击的li索引
 <ul id="testUL">
    <li> index = 0</li>
    <li> index = 1</li>
    <li> index = 2</li>
    <li> index = 3</li>
</ul>
<script type="text/javascript">
    var nodes = document.getElementsByTagName("li");
    for(i = 0;i<nodes.length;i+= 1){
        nodes[i].onclick = function(){
            console.log(i+1);//不用闭包的话,值每次都是4
        }(i);
    }
</script>

执行say667()后,say667()闭包内部变量会存在,而闭包内部函数的内部变量不会存在

使得Javascript的垃圾回收机制GC不会收回say667()所占用的资源

因为say667()的内部函数的执行需要依赖say667()中的变量

这是对闭包作用的非常直白的描述

unction say667() {
    // Local variable that ends up within closure
    var num = 666;
    var sayAlert = function() {
        alert(num);
    }
    num++;
    return sayAlert;
}

 var sayAlert = say667();
 sayAlert()//执行结果应该弹出的667

什么是伪数组

伪数组是能通过Array.prototype.slice 转换为真正的数组的带有length属性的对象

比如arguments对象,还有像调用getElementsByTagName,document.childNodes之类的,它们都返回NodeList对象都属于伪数组

我们可以通过Array.prototype.slice.call(fakeArray)将伪数组转变为真正的Array对象: 返回新数组而不会修改原数组

javascript创建对象的几种方式?

javascript创建对象简单的说,无非就是使用内置对象或各种自定义对象,当然还可以用JSON;但写法有很多种,也能混合使用。

1、对象字面量的方式

person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};

2、用function来模拟无参的构造函数

function Person(){}
var person=new Person();//定义一个function,如果使用new"实例化",该function可以看作是一个Class
person.name="Mark";
person.age="25";
person.work=function(){
alert(person.name+" hello...");
}
person.work();

3、用function来模拟参构造函数来实现(用this关键字定义构造的上下文属性)

function Pet(name,age,hobby){
   this.name=name;//this作用域:当前对象
   this.age=age;
   this.hobby=hobby;
   this.eat=function(){
      alert("我叫"+this.name+",我喜欢"+this.hobby+",是个程序员");
   }
}
var maidou =new Pet("麦兜",25,"coding");//实例化、创建对象
maidou.eat();//调用eat方法

4、用工厂方式来创建(内置对象)

var wcDog =new Object();
wcDog.name="旺财";
wcDog.age=3;
wcDog.work=function(){
alert("我是"+wcDog.name+",汪汪汪......");
}
wcDog.work();

5、用原型方式来创建

function Dog(){

 }
 Dog.prototype.name="旺财";
 Dog.prototype.eat=function(){
 alert(this.name+"是个吃货");
 }
 var wangcai =new Dog();
 wangcai.eat();

6、用混合方式来创建

function Car(name,price){
  this.name=name;
  this.price=price; 
}
 Car.prototype.sell=function(){
   alert("我是"+this.name+",我现在卖"+this.price+"万元");
  }
var camry =new Car("凯美瑞",27);
camry.sell(); 

谈谈This对象的理解。

  • this总是指向函数的直接调用者(而非间接调用者);

  • 如果有new关键字,this指向new出来的那个对象;

  • 在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window;

JavaScript原型,原型链? 有什么特点?

每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype,于是就这样一直找下去,也就是我们平时所说的原型链的概念。

关系:instance.constructor.prototype = instance.__proto__

特点:

JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。

当我们需要一个属性的时,Javascript引擎会先看当前对象中是否有这个属性, 如果没有的话,就会查找他的Prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象。

```
function Func(){}
Func.prototype.name = "Sean";
Func.prototype.getInfo = function() {
  return this.name;
}
var person = new Func();//现在可以参考var person = Object.create(oldObject);
console.log(person.getInfo());//它拥有了Func的属性和方法
//"Sean"
console.log(Func.prototype);
// Func { name="Sean", getInfo=function()}
```

javascript中call()和apply()方法的区别?

ECMAScript规范给所有函数都定义了这两个方法call()和apply()。

call()和apply()都能继承另一个对象的方法和属性,区别在于参数列表不一样

Function.call(obj, arg1, arg2,...)Function.apply(obj, args) 的第一个参数都是要调用的函数的对象,call()的剩余参数是传递给要调用的函数的值,而apply()只有两个参数,第一个是对象,第二个是数组,这个数组就是该函数的参数。

function add(a,b)
{
    alert(a+b);
}

function sub(a,b)
{
    alert(a-b);
}

add.call(sub,3,1);
//alert(4)

Javascript如何实现继承?

  1. 构造继承

  2. 原型继承

  3. 实例继承

  4. 拷贝继承

参考:构造函数的继承,非构造函数的继承;

如何判断一个对象是否属于某个类?

使用instanceof

if(a instanceof Person){
   alert('yes');
}

new操作符具体干了什么呢?

  1. 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。

  2. 属性和方法被加入到 this 引用的对象中。

  3. 新创建的对象由 this 所引用,并且最后隐式的返回 this 。

var obj  = {};
obj.__proto__ = Base.prototype;
Base.call(obj);

Javascript中,有一个函数,执行时对象查找时,永远不会去查找原型,这个函数是?

hasOwnProperty

javaScript中hasOwnProperty函数方法是返回一个布尔值,指出一个对象是否具有指定名称的属性。此方法无法检查该对象的原型链中是否具有该属性;该属性必须是对象本身的一个成员。

使用方法:
object.hasOwnProperty(proName)

其中参数object是必选项。一个对象的实例。
proName是必选项。一个属性名称的字符串值。

如果 object 具有指定名称的属性,那么JavaScript中hasOwnProperty函数方法返回 true,反之则返回 false。

JS 怎么实现一个类?怎么实例化这个类?

//混合的构造函数/原型方式
//创建对象
function Card(sID,ourName){
this.ID = sID;
this.OurName = ourName;
this.Balance = 0;
}
Card.prototype.SaveMoney = function(money){
this.Balance += money;
};
Card.prototype.ShowBalance = function(){
alert(this.Balance);
};
//使用对象
var cardAA = new Card(1000,'james');
var cardBB = new Card(1001,'sun');
cardAA.SaveMoney(30);
cardBB.SaveMoney(80);
cardAA.ShowBalance();
cardBB.ShowBalance();

事件是?IE与火狐的事件机制有什么区别? 如何阻止冒泡?

  1. 我们在网页中的某个操作(有的操作对应多个事件)。例如:当我们点击一个按钮就会产生一个事件。是可以被 JavaScript 侦测到的行为。

  2. 事件处理机制:IE是事件冒泡、Firefox同时支持两种事件模型,也就是:捕获型事件和冒泡型事件;

  3. ev.stopPropagation();(旧ie的方法 ev.cancelBubble = true;

写一个通用的事件侦听器函数。

// event(事件)工具集,来源:github.com/markyun
markyun.Event = {
    // 页面加载完成后
    readyEvent : function(fn) {
        if (fn==null) {
            fn=document;
        }
        var oldonload = window.onload;
        if (typeof window.onload != 'function') {
            window.onload = fn;
        } else {
            window.onload = function() {
                oldonload();
                fn();
            };
        }
    },
    // 视能力分别使用dom0||dom2||IE方式 来绑定事件
    // 参数: 操作的元素,事件名称 ,事件处理程序
    addEvent : function(element, type, handler) {
        if (element.addEventListener) {
            //事件类型、需要执行的函数、是否捕捉
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent('on' + type, function() {
                handler.call(element);
            });
        } else {
            element['on' + type] = handler;
        }
    },
    // 移除事件
    removeEvent : function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.datachEvent) {
            element.detachEvent('on' + type, handler);
        } else {
            element['on' + type] = null;
        }
    },
    // 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)
    stopPropagation : function(ev) {
        if (ev.stopPropagation) {
            ev.stopPropagation();
        } else {
            ev.cancelBubble = true;
        }
    },
    // 取消事件的默认行为
    preventDefault : function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    // 获取事件目标
    getTarget : function(event) {
        return event.target || event.srcElement;
    },
    // 获取event对象的引用,取到事件的所有信息,确保随时能使用event;
    getEvent : function(e) {
        var ev = e || window.event;
        if (!ev) {
            var c = this.getEvent.caller;
            while (c) {
                ev = c.arguments[0];
                if (ev && Event == ev.constructor) {
                    break;
                }
                c = c.caller;
            }
        }
        return ev;
    }
};

事件委托(事件代理)是什么

事件委托利用了事件冒泡, 只指定一个事件处理程序, 就可以管理某一类型的所有事件.

例:

html部分: 要点击li弹出其id

<ul id="list">
    <li id="li-1">Li 2</li>
    <li id="li-2">Li 3</li>
    <li id="li-3">Li 4</li>
    <li id="li-4">Li 5</li>
    <li id="li-5">Li 6</li>
    <li id="li-6">Li 7</li>
</ul>
//js部分
document.getElementById("list").addHandler("click", function(e){
    var e = e || window.event;
    var target = e.target || e.srcElement;
    if(target.nodeName.toUpperCase == "LI"){
        console.log("List item", e,target.id, "was clicked!");
    }
});

我们给一个dom同时绑定两个点击事件,一个用捕获,一个用冒泡。会执行几次事件,会先执行冒泡还是捕获?

绑定在目标元素上的事件是按照绑定的顺序执行的!

即: 绑定在被点击元素的事件是按照代码顺序发生,其他元素通过冒泡或者捕获“感知”的事件,按照W3C的标准,先发生捕获事件,后发生冒泡事件。所有事件的顺序是:其他元素捕获阶段事件 -> 本元素代码顺序事件 -> 其他元素冒泡阶段事件 。

JSON 的了解?

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。

它是基于JavaScript的一个子集。数据格式简单, 易于读写, 占用带宽小

如:{"age":"12", "name":"back"}

//JSON字符串转换为JSON对象:
var obj =eval('('+ str +')');
var obj = str.parseJSON();
var obj = JSON.parse(str);

//JSON对象转换为JSON字符串:
var last=obj.toJSONString();
var last=JSON.stringify(obj);

XML和JSON的区别?

(1) 数据体积方面。

JSON相对于XML来讲,数据的体积小,传递的速度更快些。

(2) 数据交互方面。

JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互。

(3) 数据描述方面。

JSON对数据的描述性比XML较差。

(4) 传输速度方面。

JSON的速度要远远快于XML。

同步和异步的区别?

同步的概念应该是来自于OS中关于同步的概念:不同进程为协同完成某项工作而在先后次序上调整(通过阻塞,唤醒等方式).同步强调的是顺序性.谁先谁后.异步则不存在这种顺序性.

同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作。

异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容。

异步加载JS的方式有哪些?

(1) defer,只支持IE,并行加载js文件,会按照页面上script标签的顺序执行

(2) async,并行加载js文件,下载完成立即执行,不会按照页面上script标签的顺序执行

(3) 创建script,插入到DOM中,加载完毕后callBack

(4) 按需异步载入js

Ajax 是什么? 如何创建一个Ajax?

ajax的全称:Asynchronous Javascript And XML。

异步传输+js+xml。

所谓异步,在这里简单地解释就是:向服务器发送请求的时候,我们不必等待结果,而是可以同时做其他的事情,等到有了结果它自己会根据设定进行后续操作,与此同时,页面是不会发生整页刷新的,提高了用户体验。

创建ajax过程:

  1. 创建XMLHttpRequest对象,也就是创建一个异步调用对象

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

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

  4. 发送HTTP请求

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

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

Ajax可以实现动态不刷新(局部刷新)

readyState属性 状态 有5个可取值: 0=未初始化 ,1=启动 2=发送,3=接收,4=完成

优点:

  • 可以使得页面不重载全部内容的情况下加载局部内容,降低数据传输量

  • 避免用户不断刷新或者跳转页面,提高用户体验

缺点:

  • 对搜索引擎不友好

  • ajax不支持浏览器back按钮

  • 可能造成请求数的增加

  • 跨域问题限制

  • 安全问题,AJAX暴露了与服务器交互的细节

Ajax 解决浏览器缓存问题?

  1. 在ajax发送请求前加上 anyAjaxObj.setRequestHeader("If-Modified-Since","0")

  2. 在ajax发送请求前加上 anyAjaxObj.setRequestHeader("Cache-Control","no-cache")

  3. 在URL后面加上一个随机数: "fresh=" + Math.random();

  4. 在URL后面加上时间搓:"nowtime=" + new Date().getTime();

  5. 如果是使用jQuery,直接这样就可以了 $.ajaxSetup({cache:false})。这样页面的所有ajax都会执行这条语句就是不需要保存缓存记录。

ajax请求时,如何解释json数据

使用eval、parse。鉴于安全性考虑 使用parse更靠谱

javascript的本地对象,内置对象和宿主对象

  • 本地对象为array obj regexp等可以new实例化

  • 内置对象为gload Math 等不可以实例化的

  • 宿主为浏览器自带的document,window 等

什么是window对象? 什么是document对象?

Window – 代表浏览器中一个打开的窗口

document对象 – 代表整个HTML 文档,可用来访问页面中的所有元素。

documen.write和 innerHTML的区别

document.write只能重绘整个页面

innerHTML可以重绘页面的一部分

DOM操作——怎样添加、移除、移动、复制、创建和查找节点?

(1)创建新节点

createDocumentFragment()    //创建一个DOM片段
createElement()   //创建一个具体的元素
createTextNode()   //创建一个文本节点

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

appendChild()
removeChild()
replaceChild()
insertBefore() //在已有的子节点前插入一个新的子节点

(3)查找

getElementsByTagName()    //通过标签名称
getElementsByName()    //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
getElementById()    //通过元素Id,唯一性

document load 和document ready的区别

页面加载完成有两种事件:

  1. ready,表示文档结构已经加载完成(不包含图片等非文字媒体文件)

  2. onload,指示页面包含图片等文件在内的所有元素都加载完成。

Document.onload 是在结构和样式加载完才执行js

Document.ready原生中没有这个方法,jquery中有 $().ready(function)

一般情况下,一个页面响应加载的顺序是,域名解析-加载html-加载js和css-加载图片等其他信息。

[].forEach.call($$("*"),function(a){a.style.outline="1px solid #"+(~~(Math.random()*(1<<24))).toString(16)}) 能解释一下这段代码的意思吗?

[].forEach.call()–调用引用数组的forEach方法

$$("")–等价于document.querySelectortAll("*")

~~a–等价于parseInt(a)

1<<24–对二进数1小数点右移24位

写一个获取非行间样式的函数

function getStyle(obj,attr,value)
{
if(!value)
{
if(obj.currentStyle)
{
return obj.currentStyle(attr)
}
else
{
obj.getComputedStyle(attr,false)
}
}
else
{
obj.style[attr]=value
}
}

写一个方法获取url中?号后面的参数,并将参数对象化?

function getSearch (url) {
    var reg_url = /^[^\?]+\?([\w\W]+)$/,
             reg_params =/([^&=]+)=([\w\W]*?)(&|$|#)/g,
             arr_url = reg_url.exec(url),
             ret = {};
    if(arr_url && arr_url[1]) {
        var str_params = arr_url[1], result;
        while((result = reg_ params.exec(str_ params)) != null) {
            ret[result[1]]= result[2];
          }
     }
    return ret;
}

哪些地方会出现css阻塞,哪些地方会出现js阻塞?

js的阻塞特性:所有浏览器在下载JS的时候,会阻止一切其他活动,比如其他资源的下载,内容的呈现等等。直到JS下载、解析、执行完毕后才开始继续并行下载其他资源并呈现内容。为了提高用户体验,新一代浏览器都支持并行下载JS,但是JS下载仍然会阻塞其它资源的下载(例如.图片,css文件等)。

由于浏览器为了防止出现JS修改DOM树,需要重新构建DOM树的情况,所以就会阻塞其他的下载和呈现。

嵌入JS会阻塞所有内容的呈现,而外部JS只会阻塞其后内容的显示,2种方式都会阻塞其后资源的下载。也就是说外部样式不会阻塞外部脚本的加载,但会阻塞外部脚本的执行。

CSS怎么会阻塞加载了?CSS本来是可以并行下载的,在什么情况下会出现阻塞加载了(在测试观察中,IE6下CSS都是阻塞加载)

当CSS后面跟着嵌入的JS的时候,该CSS就会出现阻塞后面资源下载的情况。而当把嵌入JS放到CSS前面,就不会出现阻塞的情况了。

根本原因:因为浏览器会维持html中css和js的顺序,样式表必须在嵌入的JS执行前先加载、解析完。而嵌入的JS会阻塞后面的资源加载,所以就会出现上面CSS阻塞下载的情况。

嵌入JS应该放在什么位置?

  1. 放在底部,虽然放在底部照样会阻塞所有呈现,但不会阻塞资源下载。

  2. 如果嵌入JS放在head中,请把嵌入JS放在CSS头部。

  3. 使用defer(只支持IE)

  4. 不要在嵌入的JS中调用运行时间较长的函数,如果一定要用,可以用setTimeout来调用

Javascript无阻塞加载具体方式

  • 将脚本放在底部。<link>还是放在head中,用以保证在js加载前,能加载出正常显示的页面。<script>标签放在</body>前。

  • 成组脚本:由于每个<script>标签下载时阻塞页面解析过程,所以限制页面的<script>总数也可以改善性能。适用于内联脚本和外部脚本。

  • 非阻塞脚本:等页面完成加载后,再加载js代码。也就是,在window.onload事件发出后开始下载代码。

(1)defer属性:支持IE4和fierfox3.5更高版本浏览器

(2)动态脚本元素:文档对象模型(DOM)允许你使用js动态创建HTML的几乎全部文档内容。代码如下:

```
<script>
var script=document.createElement("script");
script.type="text/javascript";
script.src="file.js";
document.getElementsByTagName("head")[0].appendChild(script);
</script>
```

此技术的重点在于:无论在何处启动下载,文件的下载和运行都不会阻塞其他页面处理过程。即使在head里(除了用于下载文件的http链接)。

把 Script 标签 放在页面的最底部的body封闭之前 和封闭之后有什么区别?浏览器会如何解析它们?

谈谈你对模块化的理解?

什么是模块化?

模块化就是为了减少系统耦合度,提高高内聚,减少资源循环依赖,增强系统框架设计。让开发者便于维护,同时也让逻辑相同的部分可复用。

模块化开发:针对js、css,以功能或业务为单元组织代码。js方面解决独立作用域、依赖管理、api暴露、按需加载与执行、安全合并等问题,css方面解决依赖管理、组件内部样式管理等问题。

模块化的过程

  1. 拆分。将整个系统按功能,格式,加载顺序,继承关系分割为一个一个单独的部分。

    注意::拆分的粒度问题、可复用问题、效率问题,如果这些问题处理的不好,就有可能出现不想要的后果。

  2. 将功能或特征相似的部分组合在一起,组成一个资源块。

  3. 将每个资源块按照需求,功能场景以及目录约束放到固定的地方以供调用。

模块的历程

模块化的发展也是从草根一步一步走过来的。从最开始到现在成熟方案:

  1. namespace

  2. sass,less

  3. AMD&CMD

  4. html模版

  5. grunt,gulp,webpack

  6. FIS,YUI,KISSY

模块化开发怎么做?

立即执行函数,不暴露私有成员

var module1 = (function(){
    var _count = 0;
    var m1 = function(){
      //...
    };
    var m2 = function(){
      //...
    };
    return {
      m1 : m1,
      m2 : m2
    };
  })();

AMD和CMD

Asynchronous Module Definition,异步模块定义,所有的模块将被异步加载,模块加载不影响后面语句运行。所有依赖某些模块的语句均放置在回调函数中。

AMD(Asynchronous Modules Definition)是 RequireJS 在推广过程中对模块定义的规范化产出。

CMD(Common Module Definition)是 SeaJS 在推广过程中对模块定义的规范化产出。

区别:

  1. 对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。不过 RequireJS 从 2.0 开始,也改成可以延迟执行(根据写法不同,处理方式不同)。CMD 推崇 as lazy as possible.

  2. CMD 推崇依赖就近,AMD 推崇依赖前置。看代码:

// CMD
define(function(require, exports, module) {
    var a = require('./a')
    a.doSomething()
    // 此处略去 100 行
    var b = require('./b') // 依赖可以就近书写
    b.doSomething()
    // ...
})

// AMD 默认推荐
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
    a.doSomething()
    // 此处略去 100 行
    b.doSomething()
    // ...
})

模块加载器

规范提出来了,但是在浏览器怎么实现?业内大神造出了轮子,用的多的就是require.js和sea.js。

RequireJS 和 SeaJS 是模块加载器

利用模块加载器,我们只有一个入口文件,然后根据依赖关系去加载对应的js文件,依赖关系在入口文件写好,(只有一个入口文件,但是解析依赖关系的时候会去加载对应的依赖模块,加载的js文件就不止一个了)

两者的区别:

  1. 两者都是异步加载js,只不过一个写法遵循amd,一个写法遵循cmd,其实都是让浏览器支持模块化写法的库。

  2. requirejs是无论模块需不需要都去加载完全部的依赖文件,seajs是某个模块需要用到才去加载,所以说AMD体验好,因为依赖模块一开始全都加载好了,cmd性能好,因为需要才去加载对应的模块

这样我们就可以在浏览器端实现模块化开发了,解决了全局变量的问题,也解决了依赖关系的问题,但是却也带来了新的问题,页面依赖的文件多(浏览器解析的时候就会去加载对应的依赖模块,一个模块就是一个文件),发起的http请求也多,随之而来的就是加载性能的影响(HTTP1,并行的http请求有限制个数).这个时候模块打包器就应运而生了.

模块打包器

在模块化加载器处理的基础上,为了减少解析时加载依赖模块而增加的http请求,我们可以把入口文件打包,在打包的过程中,让它去加载对应的依赖模块,最终生成的那份文件就是包含依赖模块的文件,那样就可以减少http请求,这样的打包操作我们交给构建工具或者说打包工具去实现,比如webpack/Browserify/rollup等等,这样,我们可以只专注怎么写出模块化的,可维护的,高聚合,低耦合的代码

随着es6的出现,js原生也出现了模块开发定义,也有对应的规范,用export导出,用import导入,让我们可以不用使用requirejs和seajs就能进行模块化开发,不过目前浏览器兼容性有限,不过我们可以用webpack来实现兼容,webpack不只可以帮我们把相关依赖的文件打成一个包,也能帮我们打成一个能够兼容的包(借助一些loader).

规避javascript多人开发函数重名问题

  • 命名空间

  • 封闭空间

  • js模块化mvc(数据层、表现层、控制层)

  • seajs

  • 变量转换成对象的属性

  • 对象化

requireJS的核心原理是什么?(如何动态加载的?如何避免多次加载的?如何 缓存的?)

  1. 概念

    requireJS是基于AMD模块加载规范,使用回调函数来解决模块加载的问题。

  2. 原理

    requireJS是使用创建script元素,通过指定script元素的src属性来实现加载模块的。

  3. 特点

    1. 实现js文件的异步加载,避免网页失去响应

    2. 管理模块之间的依赖,便于代码的编写和维护

  4. 项目优化

    r.js 是基于requirejs模块化的基础上进一步的压缩和打包成一个js,请求数大大减少,便于优化

核心是js的加载模块,通过正则匹配模块以及模块的依赖关系,保证文件加载的先后顺序,根据文件的路径对加载过的文件做了缓存。

JS模块加载器的轮子怎么造,也就是如何实现一个模块加载器?

参考资料:JS模块化编程之加载器原理

javascript的同源策略

一段脚本只能读取来自于同一来源的窗口和文档的属性,这里的同一来源指的是主机名、协议和端口号的组合。

同源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和操作另外一个域的绝大部分属性和方法。

同源策略还应该对一些特殊情况做处理,比如限制file协议下脚本的访问权限。本地的HTML文件在浏览器中是通过file协议打开的,如果脚本能通过file协议访问到硬盘上其它任意文件,就会出现安全隐患,目前IE8还有这样的隐患。

为什么要有同源限制?

我们举例说明:比如一个黑客程序,他利用Iframe把真正的银行登录页面嵌到他的页面上,当你使用真实的用户名,密码登录时,他的页面就可以通过Javascript读取到你的表单中input中的内容,这样用户名,密码就轻松到手了。

请解释JSONP的工作原理,以及它为什么不是真正的AJAX。

JSONP (JSON with Padding)是一个简单高效的跨域方式,HTML中的script标签可以加载并执行其他域的javascript,于是我们可以通过script标记来动态加载其他域的资源。例如我要从域A的页面pageA加载域B的数据,那么在域B的页面pageB中我以JavaScript的形式声明pageA需要的数据,然后在 pageA中用script标签把pageB加载进来,那么pageB中的脚本就会得以执行。JSONP在此基础上加入了回调函数,pageB加载完之后会执行pageA中定义的函数,所需要的数据会以参数的形式传递给该函数。JSONP易于实现,但是也会存在一些安全隐患,如果第三方的脚本随意地执行,那么它就可以篡改页面内容,截获敏感数据。但是在受信任的双方传递数据,JSONP是非常合适的选择。

AJAX是不跨域的,而JSONP是一个是跨域的,还有就是二者接收参数形式不一样!

如何解决跨域问题

  • 网络协议不同,如http协议访问https协议。

  • 端口不同,如80端口访问8080端口。

  • 域名不同,如qianduanblog.com访问baidu.com。

  • 子域名不同,如abc.qianduanblog.com访问def.qianduanblog.com。

  • 域名和域名对应ip,如www.a.com访问20.205.28.90.

  • 跨域请求资源的方法:jsonp、 iframe、window.name、window.postMessage、flash、服务器上设置代理页面

1. JSONP

JSONP:json+padding(内填充),顾名思义,就是把JSON填充到一个盒子里。

原理是:动态插入script标签,通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。

由于同源策略的限制,XmlHttpRequest只允许请求当前源(域名、协议、端口)的资源,为了实现跨域请求,可以通过script标签实现跨域请求,然后在服务端输出JSON数据并执行回调函数,从而解决了跨域的数据请求。

浏览器对script的资源引用没有同源限制,同时资源加载到页面后会立即执行(没有阻塞的情况下)。

优点是兼容性好,简单易用,支持浏览器与服务器双向通信。

缺点是只支持GET请求。另外要确定jsonp的请求是否失败并不容易,大多数框架的实现都是结合超时时间来判定。

<script>
    function createJs(sUrl){
        var oScript = document.createElement('script');
        oScript.type = 'text/javascript';
        oScript.src = sUrl;
        document.getElementsByTagName('head')[0].appendChild(oScript);
    }
 
    createJs('jsonp.js');
 
    box({
       'name': 'test'
    });
 
    function box(json){
        alert(json.name);
    }
</script>

2. CORS【Cross-Origin Resource Sharing】

定义和用法:是现代浏览器支持跨域资源请求的一种最常用的方式。

使用方法:一般需要后端人员在处理请求数据的时候,添加允许跨域的相关操作。如下:

res.writeHead(200, {
    "Content-Type": "text/html; charset=UTF-8",
    "Access-Control-Allow-Origin":'http://localhost',
    'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
    'Access-Control-Allow-Headers': 'X-Requested-With, Content-Type'
});

服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。如果浏览器检测到相应的设置,就可以允许Ajax进行跨域的访问。

3. 通过修改document.domain来跨子域

将子域和主域的document.domain设为同一个主域。前提条件:这两个域名必须属于同一个基础域名!而且所用的协议,端口都要一致,否则无法利用document.domain进行跨域

主域相同的使用document.domain

4. 使用window.name来进行跨域

window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的

5. 使用HTML5中新引进的window.postMessage方法来跨域传送数据

6. porxy代理

定义和用法:proxy代理用于将请求发送给后台服务器,通过服务器来发送请求,然后将请求的结果传递给前端。

实现方法:通过nginx代理;

注意点:如果你代理的是https协议的请求,那么你的proxy首先需要信任该证书(尤其是自定义证书)或者忽略证书检查,否则你的请求无法成功。

页面编码和被请求的资源编码如果不一致如何处理?

对于ajax请求传递的参数,如果是get请求方式,参数如果传递中文,在有些浏览器会乱码,不同的浏览器对参数编码的处理方式不同,所以对于get请求的参数需要使用encodeURIComponent函数对参数进行编码处理,后台开发语言都有相应的解码api。对于post请求不需要进行编码。

若请求的资源编码,如外引js文件编码与页面编码不同。可根据外引资源编码方式定义为 charset=“utf-8"或"gbk”。

比如:http://www.yyy.com/a.html 中嵌入了一个http://www.xxx.com/test.js。a.html 的编码是gbk或gb2312的。 而引入的js编码为utf-8的 ,那就需要在引入的时候
<script utf-8"></script>

用过哪些设计模式?知道什么是singleton, factory, strategy, decrator么?

工厂模式:

主要好处就是可以消除对象间的耦合,通过使用工程方法而不是new关键字。将所有实例化的代码集中在一个位置防止代码重复。

工厂模式解决了重复实例化的问题 ,但还有一个问题,那就是识别问题,因为根本无法 搞清楚他们到底是哪个对象的实例。

function createObject(name,age,profession){//集中实例化的函数var obj = new Object();
    obj.name = name;
    obj.age = age;
    obj.profession = profession;
    obj.move = function () {
        return this.name + ' at ' + this.age + ' engaged in ' + this.profession;
    };
    return obj;
}
var test1 = createObject('trigkit4',22,'programmer');//第一个实例var test2 = createObject('mike',25,'engineer');//第二个实例

构造函数模式

使用构造函数的方法 ,即解决了重复实例化的问题 ,又解决了对象识别的问题,该模式与工厂模式的不同之处在于:

  1. 构造函数方法没有显示的创建对象 (new Object());

  2. 直接将属性和方法赋值给 this 对象;

  3. 没有 renturn 语句。

IE和DOM事件流的区别

  1. 执行顺序不一样

  2. 参数不一样

  3. 事件加不加on

  4. this指向问题

IE和标准下有哪些兼容性的写法

var ev = ev || window.event
document.documentElement.clientWidth || document.body.clientWidth
var target = ev.srcElement||ev.target

JS的垃圾回收机机制

什么是垃圾回收机制(GC)?

早期的计算机语言,比如C和C++,需要开发者手动的来跟踪内存,这种机制的优点是内存分配和释放的效率很高。但是它也有着它的缺点,程序员很容易不小心忘记释放内存,从而造成内存的泄露。

新的编程语言,比如JAVA, C#, javascript, 都提供了所谓“垃圾回收的机制”,运行时自身会运行相应的垃圾回收机制。程序员只需要申请内存,而不需要关注内存的释放。垃圾回收器(GC)会在适当的时候将已经终止生命周期的变量的内存给释放掉。GC的优点就在于它大大简化了应用层开发的复杂度,降低了内存泄露的风险。

内存管理

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

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

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

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

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

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

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

Javascript垃圾回收方法

  • 标记清除(mark and sweep)

    这是JavaScript最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”。

    垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了

  • 引用计数(reference counting)

    在低版本IE中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个 变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1,如果该变量的值变成了另外一个,则这个值得引用次数减1,当这个值的引用次数变为0的时 候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的空间。

在IE中虽然JavaScript对象通过标记清除的方式进行垃圾回收,但BOM与DOM对象却是通过引用计数回收垃圾的, 也就是说只要涉及BOM及DOM就会出现循环引用问题。

哪些操作会造成内存泄漏?

内存泄漏指任何对象在您不再拥有或需要它之后仍然存在。

垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。

1、setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。

2、闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)

3、当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在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>

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

实例如下:

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. 使用jQuery图片预加载插件Lazy Load

    • 图片预先加载距离:threshold,通过设置这个值,在图片未出现在可视区域的顶部距离这个值时加载。

    • 事件绑定加载的方式:event

    • 图片限定在某个容器内:container

    1. 加载jQuery, 与jquery.lazyload.js

    2. 设置图片的占位符为data-original, 给图片一个特别的标签,比如class=".lazy"

    3. 然后延迟加载: $('img.lazy').lazyload();这个函数可以选择一些参数:

  2. 使用js实现图片加载: 就是new一个图片对象, 绑定onload函数, 赋值url

  3. 用CSS实现图片的预加载
    写一个CSS样式设置一批背景图片,然后将其隐藏

    改进: 使用js来推迟预加载时间, 防止与页面其他内容一起加载

如何编写高性能的Javascript?

  • 用hash-table来优化查找

  • 少用全局变量

  • 用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能

  • 用setTimeout来避免页面失去响应

  • 缓存DOM节点查找的结果

  • 避免使用with(with会创建自己的作用域,会增加作用域链长度)

  • 多个变量声明合并

需求:实现一个页面操作不会整页刷新的网站,并且能在浏览器前进、后退时正确响应。给出你的技术实现方案?

如何判断当前脚本运行在浏览器还是node环境中?(阿里)

this === window ? 'browser' : 'node';
通过判断Global对象是否为window,如果不为window,当前脚本没有运行在浏览器中

检测浏览器版本版本有哪些方式?

功能检测、userAgent特征检测

比如:

navigator.userAgent
//"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36
  (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36"

移动端最小触控区域是多大?

移动端的点击事件的有延迟,时间是多久,为什么会有? 怎么解决这个延时?

click 有 300ms 延迟,为了实现safari的双击事件的设计,浏览器要知道你是不是要双击操作。

用js实现千位分隔符?(来源:前端农民工,提示:正则+replace)

function commafy(num) {
     num = num + '';
     var reg = /(-?d+)(d{3})/;

    if(reg.test(num)){
     num = num.replace(reg, '$1,$2');
    }
    return num;
}

What is a Polyfill?

polyfill 是“在旧版浏览器上复制标准 API 的 JavaScript 补充”,可以动态地加载 JavaScript 代码或库,在不支持这些标准 API 的浏览器中模拟它们。

例如,geolocation(地理位置)polyfill 可以在 navigator 对象上添加全局的 geolocation 对象,还能添加 getCurrentPosition 函数以及“坐标”回调对象,所有这些都是 W3C 地理位置 API 定义的对象和函数。因为 polyfill 模拟标准 API,所以能够以一种面向所有浏览器未来的方式针对这些 API 进行开发,一旦对这些 API 的支持变成绝对大多数,则可以方便地去掉 polyfill,无需做任何额外工作。

做的项目中,有没有用过或自己实现一些 polyfill 方案(兼容性处理方案)?

比如: html5shiv、Geolocation、Placeholder

Flash、Ajax各自的优缺点,在使用中如何取舍?

Ajax的优势

(1) 可搜索型
  (2) 开放性
  (3) 费用
  (4) 易用性
  (5) 易于开发

Flash的优势

(1) 多媒体处理
  (2) 兼容性
  (3) 矢量图形 比SVG,Canvas优势大很多
  (4) 客户端资源调度,比如麦克风,摄像头

Flash适合处理多媒体、矢量图形、访问机器;对CSS、处理文本上不足,不容易被搜索。

Ajax对CSS、文本支持很好,支持搜索;多媒体、矢量图形、机器访问不足。

共同点:与服务器的无刷新传递消息、用户离线和在线状态、操作DOM

ECMAScript6

Object.is() 与原来的比较操作符"="、""的区别?

两等号判等,会在比较时进行类型转换;

三等号判等(判断严格),比较时不进行隐式类型转换,(类型不同则会返回false);

Object.is 在三等号判等的基础上特别处理了 NaN 、-0 和 +0 ,保证 -0 和 +0 不再相同,但 Object.is(NaN, NaN) 会返回 true.

Object.is 应被认为有其特殊的用途,而不能用它认为它比其它的相等对比更宽松或严格。

谈一谈你对ECMAScript6的了解?

新增模板字符串(为JavaScript提供了简单的字符串插值功能)、箭头函数(操作符左边为输入的参数,而右边则是进行的操作以及返回的值Inputs=>outputs。)、for-of(用来遍历数据—例如数组中的值。)arguments对象可被不定参数和默认参数完美代替。ES6将promise对象纳入规范,提供了原生的Promise对象。增加了let和const命令,用来声明变量。增加了块级作用域。let命令实际上就增加了块级作用域。ES6规定,var命令和function命令声明的全局变量,属于全局对象的属性;let命令、const命令、class命令声明的全局变量,不属于全局对象的属性。还有就是引入module模块的概念。



以上是关于前端面试题集锦——JavaScript的主要内容,如果未能解决你的问题,请参考以下文章

常用Javascript代码片段集锦

JavaScript笔试题(js高级代码片段)

nodejs面试题笔记

前端面试题集锦及答案解析--HTML HTTPweb综合问题

好程序员HTML5大前端分享web前端面试题集锦三

web前端开发程序员面试题集锦