JavaScript 前端面试题集锦

1

栈和队列的区别?

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

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

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

2

栈和堆的区别?

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

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

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

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

3

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

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

4

介绍js有哪些内置对象?

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

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

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

5

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

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

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

    区别:

        1.存储

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

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

        2.复制

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

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

        3.检测类型

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

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

6

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

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

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

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

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

    引用数据类型存储在堆(heap)中的对象,占据空间大、大小不固定,如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

 

 

7

null,undefined 的区别?

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

    undefined 表示不存在这个值。

    typeof undefined //"undefined"

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

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

    typeof null //"object"

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

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

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

    再来一个例子:

1null
2Q:有张三这个人么?
3A:有!
4Q:张三有房子么?
5A:没有!
6
7undefined
8Q:有张三这个人么?
9A:没有!

 

参考阅读:undefined与null的区别

8

说几条写JavaScript的基本规范?

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

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

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

4.不要使用全局函数。

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

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

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

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

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

9

eval是做什么的?

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

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

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

10

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

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

    使用它区别是:

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

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

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

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

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

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

11

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

[1, NaN, NaN]

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

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

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

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

 

    parseInt的第二个参数radix为0时,ECMAScript5将string作为十进制数字的字符串解析;

    parseInt的第二个参数radix为1时,解析结果为NaN;

    parseInt的第二个参数radix在2—36之间时,如果string参数的第一个字符(除空白以外),不属于radix指定进制下的字符,解析结果为NaN。

    parseInt("3", 2)执行时,由于"3"不属于二进制字符,解析结果为NaN。

12

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

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

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

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

3.利用递归进行下次比较

 

 1<script type="text/javascript">
 2
 3    function quickSort(arr){
 4        if(arr.length<=1){
 5            return arr;//如果数组只有一个数,就直接返回;
 6        }
 7
 8        var num = Math.floor(arr.length/2);//找到中间数的索引值,如果是浮点数,则向下取整
 9
10        var numValue = arr.splice(num,1);//找到中间数的值
11        var left = [];
12        var right = [];
13
14        for(var i=0;i<arr.length;i++){
15            if(arr[i]<numValue){
16                left.push(arr[i]);//基准点的左边的数传到左边数组
17            }
18            else{
19               right.push(arr[i]);//基准点的右边的数传到右边数组
20            }
21        }
22
23        return quickSort(left).concat([numValue],quickSort(right));//递归不断重复比较
24    }
25
26    alert(quickSort([32,45,37,16,2,87]));//弹出“2,16,32,37,45,87”
27
28</script>
29

 

13

Javascript作用链域?

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

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

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

14

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

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

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

    闭包的特性:

        1.函数内再嵌套函数

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

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

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

 

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

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

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

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

 1unction say667() {
 2    // Local variable that ends up within closure
 3    var num = 666;
 4    var sayAlert = function() {
 5        alert(num);
 6    }
 7    num++;
 8    return sayAlert;
 9}
10
11 var sayAlert = say667();
12 sayAlert()//执行结果应该弹出的667

15

javascript创建对象的几种方式?

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

1.对象字面量的方式

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

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

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

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

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

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

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

5.用原型方式来创建

1function Dog(){
2
3 }
4 Dog.prototype.name="旺财";
5 Dog.prototype.eat=function(){
6 alert(this.name+"是个吃货");
7 }
8 var wangcai =new Dog();
9 wangcai.eat();

6.用混合方式来创建

1function Car(name,price){
2  this.name=name;
3  this.price=price; 
4}
5 Car.prototype.sell=function(){
6   alert("我是"+this.name+",我现在卖"+this.price+"万元");
7  }
8var camry =new Car("凯美瑞",27);
9camry.sell(); 

16

谈谈This对象的理解。

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

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

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

17

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

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

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

    特点:

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

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

 1```
 2function Func(){}
 3Func.prototype.name = "Sean";
 4Func.prototype.getInfo = function() {
 5  return this.name;
 6}
 7var person = new Func();//现在可以参考var person = Object.create(oldObject);
 8console.log(person.getInfo());//它拥有了Func的属性和方法
 9//"Sean"
10console.log(Func.prototype);
11// Func { name="Sean", getInfo=function()}
12  ```

18

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

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

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

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

 1function add(a,b)
 2{
 3    alert(a+b);
 4}
 5
 6function sub(a,b)
 7{
 8    alert(a-b);
 9}
10
11add.call(sub,3,1);
12//alert(4)

19

Javascript如何实现继承?

1.构造继承

2.原型继承

3.实例继承

4.拷贝继承

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

20

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

    使用instanceof

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

21

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

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

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

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

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

22

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

     hasOwnProperty 

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

使用方法:

object.hasOwnProperty(proName)

    其中参数object是必选项。一个对象的实例。

proName是必选项。一个属性名称的字符串值。

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

23

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

 1//混合的构造函数/原型方式
 2//创建对象
 3function Card(sID,ourName){
 4this.ID = sID;
 5this.OurName = ourName;
 6this.Balance = 0;
 7}
 8Card.prototype.SaveMoney = function(money){
 9this.Balance += money;
10};
11Card.prototype.ShowBalance = function(){
12alert(this.Balance);
13};
14//使用对象
15var cardAA = new Card(1000,'james');
16var cardBB = new Card(1001,'sun');
17cardAA.SaveMoney(30);
18cardBB.SaveMoney(80);
19cardAA.ShowBalance();
20cardBB.ShowBalance();

24

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

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

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

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

25

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

 1// event(事件)工具集,来源:github.com/markyun
 2markyun.Event = {
 3    // 页面加载完成后
 4    readyEvent : function(fn) {
 5        if (fn==null) {
 6            fn=document;
 7        }
 8        var oldonload = window.onload;
 9        if (typeof window.onload != 'function') {
10            window.onload = fn;
11        } else {
12            window.onload = function() {
13                oldonload();
14                fn();
15            };
16        }
17    },
18    // 视能力分别使用dom0||dom2||IE方式 来绑定事件
19    // 参数: 操作的元素,事件名称 ,事件处理程序
20    addEvent : function(element, type, handler) {
21        if (element.addEventListener) {
22            //事件类型、需要执行的函数、是否捕捉
23            element.addEventListener(type, handler, false);
24        } else if (element.attachEvent) {
25            element.attachEvent('on' + type, function() {
26                handler.call(element);
27            });
28        } else {
29            element['on' + type] = handler;
30        }
31    },
32    // 移除事件
33    removeEvent : function(element, type, handler) {
34        if (element.removeEventListener) {
35            element.removeEventListener(type, handler, false);
36        } else if (element.datachEvent) {
37            element.detachEvent('on' + type, handler);
38        } else {
39            element['on' + type] = null;
40        }
41    },
42    // 阻止事件 (主要是事件冒泡,因为IE不支持事件捕获)
43    stopPropagation : function(ev) {
44        if (ev.stopPropagation) {
45            ev.stopPropagation();
46        } else {
47            ev.cancelBubble = true;
48        }
49    },
50    // 取消事件的默认行为
51    preventDefault : function(event) {
52        if (event.preventDefault) {
53            event.preventDefault();
54        } else {
55            event.returnValue = false;
56        }
57    },
58    // 获取事件目标
59    getTarget : function(event) {
60        return event.target || event.srcElement;
61    },
62    // 获取event对象的引用,取到事件的所有信息,确保随时能使用event;
63    getEvent : function(e) {
64        var ev = e || window.event;
65        if (!ev) {
66            var c = this.getEvent.caller;
67            while (c) {
68                ev = c.arguments[0];
69                if (ev && Event == ev.constructor) {
70                    break;
71                }
72                c = c.caller;
73            }
74        }
75        return ev;
76    }
77};

26

什么是伪数组?

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

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

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

27

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

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

    例:

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

 

1<ul id="list">
2    <li id="li-1">Li 2</li>
3    <li id="li-2">Li 3</li>
4    <li id="li-3">Li 4</li>
5    <li id="li-4">Li 5</li>
6    <li id="li-5">Li 6</li>
7    <li id="li-6">Li 7</li>
8</ul>

 

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

28

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

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

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

29

JSON的了解?

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

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

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

1//JSON字符串转换为JSON对象:
2var obj =eval('('+ str +')');
3var obj = str.parseJSON();
4var obj = JSON.parse(str);
5
6//JSON对象转换为JSON字符串:
7var last=obj.toJSONString();
8var last=JSON.stringify(obj);

30

XML和JSON的区别?

1. 数据体积方面。

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

2. 数据交互方面。

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

3. 数据描述方面。

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

4. 传输速度方面。

JSON的速度要远远快于XML。

 

1

同步和异步的区别?

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

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

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

 

 

2

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

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

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

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

4. 按需异步载入js

 

 

3

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暴露了与服务器交互的细节

 

 

4

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都会执行这条语句就是不需要保存缓存记录。

 

 

5

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

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

 

6

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

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

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

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

7

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

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

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

8

documen.write和 innerHTML的区别

    document.write只能重绘整个页面;

    innerHTML可以重绘页面的一部分。

9

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

    1.创建新节点

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

    2.添加、移除、替换、插入

 

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

3.查找

1getElementsByTagName()    //通过标签名称
2getElementsByName()    //通过元素的Name属性的值(IE容错能力较强,会得到一个数组,其中包括id等于name值的)
3getElementById()    //通过元素Id,唯一性appendChild()
4removeChild()
5replaceChild()
6insertBefore() //在已有的子节点前插入一个新的子节点

10

document load 和document ready的区别

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

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

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

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

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

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

11

[].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位

12

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

 1function getStyle(obj,attr,value)
 2{
 3if(!value)
 4{
 5if(obj.currentStyle)
 6{
 7return obj.currentStyle(attr)
 8}
 9else
10{
11obj.getComputedStyle(attr,false)
12}
13}
14else
15{
16obj.style[attr]=value
17}
18}

13

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

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

14

哪些地方会出现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阻塞下载的情况。

15

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

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

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

    3.使用defer(只支持IE)

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

16

Javascript无阻塞加载具体方式

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

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

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

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

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

代码如下:

1```
2<script>
3var script=document.createElement("script");
4script.type="text/javascript";
5script.src="file.js";
6document.getElementsByTagName("head")[0].appendChild(script);
7</script>
8此技术的重点在于:无论在何处启动下载,文件的下载和运行都不会阻塞其他页面处理过程。即使在head里(除了用于下载文件的http链接)。

17

谈谈你对模块化的理解?

什么是模块化?

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

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

模块化的过程

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

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

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

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

模块的历程

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

    1.namespace

    2.sass,less

    3.AMD&CMD

    4.html模版

    5.grunt,gulp,webpack

    6.FIS,YUI,KISSY

模块化开发怎么做?

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

 1var module1 = (function(){
 2    var _count = 0;
 3    var m1 = function(){
 4      //...
 5    };
 6    var m2 = function(){
 7      //...
 8    };
 9    return {
10      m1 : m1,
11      m2 : m2
12    };
13  })();

AMD和CMD

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

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

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

区别:

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

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

 1// CMD
 2define(function(require, exports, module) {
 3    var a = require('./a')
 4    a.doSomething()
 5    // 此处略去 100 行
 6    var b = require('./b') // 依赖可以就近书写
 7    b.doSomething()
 8    // ...
 9})
10
11// AMD 默认推荐
12define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
13    a.doSomething()
14    // 此处略去 100 行
15    b.doSomething()
16    // ...
17})

模块加载器

    规范提出来了,但是在浏览器怎么实现?业内大神造出了轮子,用的多的就是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)

18

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

    • 命名空间

    • 封闭空间

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

    • seajs

    • 变量转换成对象的属性

    • 对象化

19

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

1.概念

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

2.原理

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

3.特点

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

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

4.项目优化

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

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

20

javascript的同源策略

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

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

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

为什么要有同源限制?

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

21

请解释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是一个是跨域的,还有就是二者接收参数形式不一样!

22

如何解决跨域问题

    由于浏览器同源策略,凡是发送请求url的协议、域名、端口三者之间任意一与当前页面地址不同即为跨域。存在跨域的情况:

    • 网络协议不同,如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的请求是否失败并不容易,大多数框架的实现都是结合超时时间来判定。

 

 1<script>
 2    function createJs(sUrl){
 3        var oScript = document.createElement('script');
 4        oScript.type = 'text/javascript';
 5        oScript.src = sUrl;
 6        document.getElementsByTagName('head')[0].appendChild(oScript);
 7    }
 8
 9    createJs('jsonp.js');
10
11    box({
12       'name': 'test'
13    });
14
15    function box(json){
16        alert(json.name);
17    }
18</script>
19

2. CORS【Cross-Origin Resource Sharing】

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

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

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

服务器端对于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首先需要信任该证书(尤其是自定义证书)或者忽略证书检查,否则你的请求无法成功。

23

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

    对于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 src="http://www.xxx.com/test.js; charset="utf-8"></script>

24

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

工厂模式:

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

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

 

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

构造函数模式

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

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

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

    3.没有 renturn 语句。

25

IE和DOM事件流的区别

1.执行顺序不一样

2.参数不一样

3.事件加不加on

4.this指向问题

26

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

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

27

JS的垃圾回收机机制

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

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

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

内存管理

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

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

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

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

2.合理的GC方案:

① 遍历所有可访问的对象; 

② 回收已不可访问的对象。

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

4.GC优化策略:

① 分代回收(Generation GC);

② 增量GC

Javascript垃圾回收方法

1.标记清除(mark and sweep)

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

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

2.引用计数(reference counting)

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

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

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

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

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

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

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

3.当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在IE中不会作出恰当处理,此时要先手工移除事件,不然会存在内存泄露。

    实例如下:

 1<div id="myDiv">
 2    <input type="button" value="Click me" id="myBtn">
 3</div>
 4<script type="text/javascript">
 5    var btn = document.getElementById("myBtn");
 6    btn.onclick = function(){
 7        document.getElementById("myDiv").innerHTML = "Processing...";
 8    }
 9</script>
10

 解决方法如下:

 1<div id="myDiv">
 2    <input type="button" value="Click me" id="myBtn">
 3</div>
 4<script type="text/javascript">
 5    var btn = document.getElementById("myBtn");
 6    btn.onclick = function(){
 7    btn.onclick = null;
 8        document.getElementById("myDiv").innerHTML = "Processing...";
 9    }
10</script>
11

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

    实例如下:

1function bindEvent(){
2    var obj=document.createElement("XXX");
3    obj.onclick=function(){
4        //Even if it's a empty function
5    }
6}

解决方法如下:

1function bindEvent(){
2    var obj=document.createElement("XXX");
3    obj.onclick=function(){
4         //Even if it's a empty function
5    }
6    obj=null;
7}

28

图片预加载的实现

1.使用jQuery图片预加载插件Lazy Load

    ① 加载jQuery, 与jquery.lazyload.js

    ② 设置图片的占位符为data-original, 给图片一个特别的标签,比如class=".lazy"    ③ 然后延迟加载: $('img.lazy').lazyload();这个函数可以选择一些参数:

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

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

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

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

3.用CSS实现图片的预加载

写一个CSS样式设置一批背景图片,然后将其隐藏

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

4.用Ajax实现预加载

其实就是通过ajax请求请求图片地址. 还可以用这种方式加载css,js文件等

29

如何编写高性能的Javascript?

• 用hash-table来优化查找

• 少用全局变量

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

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

• 缓存DOM节点查找的结果

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

• 多个变量声明合并

30

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

Ajax的优势

1.可搜索型

2. 开放性

3. 费用

4. 易用性

5. 易于开发

Flash的优势

1. 多媒体处理

2. 兼容性

3. 矢量图形 比SVG,Canvas优势大很多

4.客户端资源调度,比如麦克风,摄像头

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

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值