前端面试题集锦(Javascript篇)

请描述一下 JavaScript 事件冒泡机制?
前端面试题集锦(Javascript篇)_第1张图片
JS事件捕获与冒泡原型图

当页面中某个元素的事件被触发以后,比如点击了页面中的某个按钮,
就触发了当前按钮的点击事件,但是 JavaScript 并不是简单就直接触发该元素的相应事件,
而是会首先从 DOM 树的最顶层(window)依次的去触发目标(被直接点击的)元素所有父级的同类事件,
直到触发到目标元素,然后又会再一次的从目标元素开始触发其所有父级的所有同类事件直到window,
也就是同类型事件的目标元素与 window 之间触发一个来回,
window 到目标的触发阶段,我们称为捕获阶段,
目标触发事件的时候我们称为目标阶段,
而最后目标到 window 的触发阶段,我们称为冒泡阶段。
这种机制我们称为事件流(event flow),冒泡机制其实就是事件流机制中的冒泡阶段规则。

出处:https://www.w3.org/TR/2016/WD-uievents-20160804/ 中的
3.1. Event dispatch and DOM event flow


JavaScript 的事件流模型都有什么?

分析:
事件流模型这个知识点在妙味中级阶段 event 事件章节就有详细讲解,如果已经忘记的朋友,再去看看这个阶段的视频吧。 题外话:一般纯理论的知识点学起来枯燥(妙味实体班的学员也是如此),但理论的好处在于当遇到问题时,能迅速判断出错的原理所在,从而可以准确迅速的查找问题并精准修复,可以让冗余代码简化到最低、可以不再出了错以后像撞大运般的采用 “试来试去大法” 来修复~

事件流描述的是从页面中接收事件的顺序。 DOM 结构是树形结构,当页面中的某一个元素触发了某个一个事件,事件会从最顶层的 window 对象开始,向下传播到目标元素,途径的祖先节点都会触发对应的事件,如果当前节点的该事件绑定了事件处理函数的话,则会执行该函数当事件达到目标元素并执行绑定函数(如果有绑定的话)后,事件又会向上传播到 window 元素,途径的祖先节点都会触发对应的事件(如果绑定事件处理函数的话)

事件流包含三个阶段:

  • 事件捕捉阶段:事件开始由顶层对象触发,然后逐级向下传播,直到目标的元素;
  • 处于目标阶段:处在绑定事件的元素上;
  • 事件冒泡阶段:事件由具体的元素先接收,然后逐级向上传播,直到不具体的元素;

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

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

  1. 函数内再嵌套函数
  2. 内部函数可以引用外层的参数和变量
  3. 参数和变量不会被垃圾回收机制回收

BOM 对象有哪些,列举 window 对象?
  • window 对象,是 JS 的最顶层对象,其他的 BOM 对象都是 window 对象的属性;
  • location 对象,浏览器当前URL信息;
  • navigator 对象,浏览器本身信息;
  • screen 对象,客户端屏幕信息;
  • history 对象,浏览器访问历史信息;

new操作符具体干了什么呢?
  1. 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型。
  1. 属性和方法被加入到 this 引用的对象中。
  2. 新创建的对象由 this 所引用,并且最后隐式的返回 this 。

"==" 和 "===" 有什么不同?
  1. 相同的是:== 和 === 都是比较等值比较运算符,返回的布尔类型的比较结果。
  1. 不同的是:
    • == 是等值比较运算符,使用的是 抽象等值 比较算法。
      === 是严格等值比较运算符,使用的 严格等值 比较算法。
    • == 运算符在比较值的时候,会根据两者类型是否相同而做不同的处理,
      在两者不同类型的时候,会转换类型后进行比较:
      基本类型会转成数字,引用类型会转成对象原始值,然后再进行比较。
      而 === 首先也会判断类型是否一致,不同的是如果类型不一致则直接返回 false。

资料参考:

  • 等值比较运算符 ( == )
  • 抽象比较算法
  • 严格等值比较运算符 ( === )
  • 严格比较算法

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

使用instanceof


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

hasOwnProperty

+ hasOwnProperty函数方法是返回一个布尔值,
+ 指出一个对象是否具有指定名称的属性。
+ 此方法无法检查该对象的原型链中是否具有该属性;
+ 该属性必须是对象本身的一个成员。
+如果 object 具有指定名称的属性,那么JavaScript中hasOwnProperty函数方法返回 true,反之则返回 false。

------
##### window.foo || (window.foo = "bar"); 返回值是什么?
>参考答案:
"bar"

>分析:
|| 又称为短路或,短路:如果左侧为真,则不再进行右侧运算,同时返回左侧表达式运算结果。
如果左侧为假则执行右侧表达式运算,并返回右侧计算结果。
上面window.foo是不存在的,所有结果为undefined,转成boolean就是false,
那么就会运算 window.foo = "bar",
把 "bar" 赋值给 window.foo 的同时,
返回值也是 "foo",所以打印返回结果是 "bar"

------------------------------------------------------------------------------------------------
##### JavaScript 的 typeof 返回哪些数据类型?

> + **基础类型**包括:Number、String、Boolean、Null、Undefined、Symbol(该类型位 ES2015 中新增类型)
+ **引用类型**包括:Object typeof 运算符把类型信息以字符串形式返回,需要注意的是 typeof 返回的类型和 JavaScript 定义的类型有细微的差异。 typeof 返回七种可能的值:“number”、“string”、“boolean”、“object”、"symbol"、“function”和“undefined”。

------------------------------------------------------------------------------------------------
##### 请写出以下运算结果:

alert(typeof null); // object
alert(typeof undefined); // undefined
alert(typeof NaN); // number
alert(NaN == undefined); // false
alert(NaN == NaN); // false

var str = "123abc";
alert(typeof str++); // number
alert(str); // NaN

------------------------------------------------------------------------------------------------
##### null 和 undefined 的区别?
>+  ** null**表示空值,转为数值时为0;
+ **undefined**表示"缺少值",就是此处应该有一个值,但是还没有定义。
+ 变量被声明了,但没有赋值时,就等于undefined。
+ 对象没有赋值的属性,该属性的值为undefined。
+ 函数没有返回值时,默认返回undefined。

------------------------------------------------------------------------------------------------
##### 例举至少 3 种强制类型转换和 2 种隐式类型转换?
> 1. 强制类型转换: 明确调用内置函数,强制把一种类型的值转换为另一种类型。强制类型转换主要有:Boolean、Number、String、parseInt、parseFloat

>2. 隐式类型转换: 在使用算术运算符时,运算符两边的数据类型可以是任意的,比如,一个字符串可以和数字相加。之所以不同的数据类型之间可以做运算,是因为 JavaScript 引擎在运算之前会悄悄的把他们进行了隐式类型转换。隐式类型转换主要有:+、–、==、!

------------------------------------------------------------------------------------------------
#####  $(".foo div#bar:eq(0)") 请优化这段 JQuery 选择器?

>参考答案:

> ```
$("#bar:eq(0)")

分析:
因为有 id 选择器,所以前面的 .foo div 是没有必要的。


请解释 JQuery 中 .end() 的用途?

参考答案:

返回当前jq对象的上级jq对象

分析:

  1. 当我们通过$()会得到一个对象
```

$jq1 = $('#div1');


>2. jq对象下有一系列的方法,有的方法会返回一个新的对象
// 通过$jq1的find返回了一个新的jquery对象

var $jq2 = $jq1.find('p');


>3. 这个时候在$jq2下面有一个属性 prevObject,该属性保存的就是 $jq1,通过比较 $jq2.prevObject == $jq1,会发现返回true。

>4. 通过 prevObject 属性会产生一个类似原型链的引用,
而 .end() 方法就是返回就是当前 JQ 对象的 prevObject 对象,
也就是当我们 $jq2.end() 的时候,返回的就是上层的 $jq1。

------------------------------------------------------------------------------------------------
##### 注册账号要求以字母开头,可以包含字母、数字、下划线,请写出验证该账号的正则表达式?
>参考答案:

/^[a-zA-Z]\w+$/


------------------------------------------------------------------------------------------------
##### 请列举三种减低页面加载时间的方法。(加载时间指感知的时间或者实际加载时间)
>参考答案:

>1. 减少实际加载时间
    1.  减少 http 请求(合并文件、合并图片)
    2.  压缩 JavaScript、CSS 代码
    3.  启用服务器压缩传输(如 gzip)
    
>2. 减少感知时间
    1. script 外部脚本加载放到 html 最后进行
    2. 按需加载资源(如:只加载当前能看到的区域的图片)

------------------------------------------------------------------------------------------------
##### "I'm lasagna hog".split("").reverse().jion(""); 语句的返回值是什么?

>参考答案:

goh angasal m'I


>分析:

>1. split(""),拆分字符串,得到数组:

["I", "'", "m", " ", "l", "a", "s", "a", "g", "n", "a", " ", "h", "o", "g"]

>2. 对数组使用.reverse(),翻转数组,得到:

["g", "o", "h", " ", "a", "n", "g", "a", "s", "a", "l", " ", "m", "'", "I"]

>3. 最后使用join(""),把数组再次拼接成字符串,得到字符串:

goh angasal m'I


------------------------------------------------------------------------------------------------
#####  $(function(){console.log(1)}); 和 window.onload = function(){console.log(2)};执行结果?详细说明原因?
>参考答案:

>先输出2,再输出1


>分析:

>这里重点是:JQ 的 $(function(){}) 和 window.onload = function(){},并不等同

>1. **window.onload **是页面资源加载完成后触发的事件,
比如页面中有图片需要加载,那么onload是等图片加载完成以后才触发的。

>2. **$(function) **监听的是 DOMContentLoaded 事件,而该事件只需要把 HTML 结构加载完成就会触发
(一般我们js操作的就是页面元素,所以只需要等结构加载完成能操作页面元素就可以了)
所以该事件会比 onload 事件要先触发,所以 2 先执行。

------------------------------------------------------------------------------------------------
##### 请指出 JQuery中 ".bind()"、".live()" 和 "delegate()" 的区别?

>参考答案:

>1. bind:把函数直接绑定到指定元素的指定事件上。
>2. live:把函数绑定到document上,接收选择器和事件类型作为参数,当触发一个元素的事件的时候,会利用事件冒泡到document上这一特性,判断事件目标元素和绑定参数中的选择器是否匹配,如果匹配则执行绑定函数的执行。
3. delegate:和live有点类似,但是可以指定绑定元素,而不是document,其他和live一致,但是比live更加灵活。

------------------------------------------------------------------------------------------------
#####  请使用标准的 JSON 格式封装一组学生信息数据,内容包括:姓名、性别、住址(包括城市、街道、门牌号、地铁线)

[
{
"name": "北京妙味",
"gender": "男",
"address": {
"city": "北京",
"street": "西二旗辉煌国际"
"RoomNo": "6楼319室",
"subwayLine": "13"
}
},
{
"name": "上海妙味",
"gender": "男",
"address": {
"city": "上海",
"street": "闵行区新龙路七宝宝龙城"
"RoomNo": "T4楼9层902室",
"subwayLine": "9"
}
}
]


------------------------------------------------------------------------------------------------
#####  客户查询手机消费清单要求:
实现 A、B、C 三个异步接口,A 接口需传参 user_name、mobi(用户姓名和手机号码),请求成功返回该用户此手机号码的消费清单信息,user_name 可通过接口 B 获取,mobi 可通过接口 C 获取,请使用 JQuery 写出具体的实现方法?

```javascript

function getUserName() {
    return $.ajax('/get_user_name.php');
}
function getMobi() {
    return $.ajax('/get_mobi.php');
}

$.when(getUserName(), getMobi()).then(function(data1, data2) {
    $.ajax({
        url: 'getConsumerList.php',
        data: {
            user_name: data1[0],
            mobi: data2[0],
        }
    }).success(function(consumerList) {
        //consumerList
    });
}, function() {
    console.log('获取用户名或手机号未成功');
});

请简述 AJAX 及基本步骤?
  • 初始化ajax对象
  • 连接地址,准备数据
  • 发送请求
  • 接收数据(正在接收,尚未完成)
  • 接收数据完成
//初始化ajax对象
var xhr = new XMLHttpRequest();
//连接地址,准备数据
xhr.open(“方式”,”地址”,是否为异步);
//接收数据完成触发的事件
xhr.onload =function(){}
//发送数据
xhr.send();

js延迟加载的方式有哪些?

normaldefer和async、动态创建DOM方式(用得最多)、按需异步载入js


同步和异步的区别?

概念1:同步异步可以说是对被请求方来说的,被请求者使用什么方式来告知处理结果。

  • 首先同步异步于阻塞非阻塞并没有关系。同步异步主要是事情做完以后,如何进行处理、或者说关注的是一 种消息通信机制。
  • 同步的情况下,是由处理消息者自己去等待消息是否被触发;
  • 异步的情况下是由触发机制来通知处理消息者;

概念2:同步可以是阻塞的也可以是非阻塞的,异步也是如此。

  • 阻塞非阻塞,主要是对于请求者而言的。
  • 阻塞:发出请求等待结果返回,然后再处理后续的事情;
  • 非阻塞:发出请求不等待结果返回,可以接着做后续的事情;

GET和POST的区别,何时使用POST?
  • GET:一般用于查询数据,使用URL传递参数,由于浏览器对地址栏长度有限制,所以对使用get方式所发送信息的数量有限制,同时浏览器会记录(历史记录,缓存)中会保留请求地址的信息,包括地址后面的数据。get 只能发送普通格式(URL 编码格式)的数据。
  • POST:一般用于向服务器发送数据,对所发送的数据的大小理论上是没有限制,浏览器会缓存记录地址,但是不会记录 post 提交的数据。post 可以发送纯文本、URL编码格式、二进制格式的字符串,形式多样。
  • 在以下情况中,请使用 POST 请求:
  1. 以提交为目的的请求(类似语义化,get 表示请求,post 表示提交);
  2. 发送私密类数据(用户名、密码)(因为浏览器缓存记录特性);
  3. 向服务器发送大量数据(数据大小限制区别);
  4. 上传文件图片时(数据类型区别);

AJAX 的局限性?
  • AJAX 不支持浏览器 back 按钮。
  • 安全问题 AJAX 暴露了与服务器交互的细节。
  • 对搜索引擎的支持比较弱。不会执行你的 JS 脚本,只会操作你的网页源代码;
  • 跨域请求有一定限制。解决方式:jsonp;

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

当使用 new 操作符调用构造函数,函数实际会经历如下步骤:

  • 创建一个新对象;
  • 把函数中上下文(作用域)对象this指向该对象;
  • 执行代码,通过this给新对象添加属性或方法;
  • 返回对象;

JavaScript 原型,原型链 ? 有什么特点?
  • JavaScript 原型: 每创建一个函数,函数上都有一个属性为 prototype,它的值是一个对象。 这个对象的作用在于当使用函数创建实例的时候,那么这些实例都会共享原型上的属性和方法。
  • 原型链: 在 JavaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接(proto)。这个原型对象又有自己的原型,直到某个对象的原型为 null 为止(也就是不再有原型指向)。这种一级一级的链结构就称为原型链(prototype chain)。 当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止;到查找到达原型链的顶部(Object.prototype),仍然没有找到指定的属性,就会返回 undefined。

实现对数组进行乱序
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var sign = 1; 
a.sort(function(a, b) {
    return Math.random() - 0.5
});

实现一个函数 clone(),可以对 JavaScript 中的5种主要的数据类型(包括 Number、String、Object、Array、Boolean)进行值复制。

这道题考察了以下知识点:

  • 使用 typeof 判断值得类型;
  • 使用 toString 区分数组和对象;
  • 递归函数的使用;
function clone(obj) {
    //判断是对象,就进行循环复制
    if (typeof obj === 'object' && typeof obj !== 'null') {
        // 区分是数组还是对象,创建空的数组或对象
        var o = Object.prototype.toString.call(obj).slice(8, -1) === "Array" ? [] : {};
        for (var k in obj) {
            // 如果属性对应的值为对象,则递归复制
            if(typeof obj[k] === 'object' && typeof obj[k] !== 'null'){
                o[k] = clone(obj[k])
            }else{
                o[k] = obj[k];
            }
        }
    }else{ //不为对象,直接把值返回
        return obj;
    }
    return o;
}

判断代码输出结果
var test = 2;
console.log("test is a Number--" + (test.constructor == Number));  //true
function test1() {};
var t1 = new test1();
var test2 = "37degree";

console.info("typeof test--" + typeof test); //number
console.info("typeof test1--" + typeof test1);  //function
console.info("typeof t1--" + typeof t1);  //object
console.info("t1 instanceof test1--" + (t1 instanceof Object));   //true
console.info("test instanceof Array--" + (test instanceof Array));  //false

首先涉及到 JS 预解析的概念,这里的 变量申明 和 函数申明 都会被预解析处理,知道这个以后,那么下面一个一个来分析:

  • 第一个:
    因为 test = 2 先执行了,所以这里 test 的值已经是一个数字了,那么 test.constructr 就是 Number,所以下面这个打印 true;
    console.log("test is a Number--" + (test.constructr == Number))
  • 第二个:
    原因同上,需要注意 typeof 得到的结果 number 的 n 是小写的!
  • 第三个:
    test1 是一个函数,typeof 值为 function;
  • 第四个:
    通过 new 得到的结果一定是一个 Object,所以 t1 的 typeof 结果为 object;
  • 第五个:
    这个题有点误导人的,首先出题人写的是 instanceof test1,但真正计算的却是 instanceof Object,请注意它们的差异!不过不影响结果的,结果都是 true;
  • 第六个:
    test 是一个数字,所以他的构造函数应是 Number,而不是 Array,所以结果为 false;

解释 call 与 apply 的区别,并写出下面代码输出的结果:
function add(a, b) {
    alert(a + b);
}
function sub(a, b) {
    alert(a - b);
}
add.call(sub, 3, 1)  //结果为 4
  • call 和 apply 都是函数下的一个静态方法,可以通过函数 .call() 或 函数 .apply() 的方式来间接调用该函数,通过 call 或 apply 执行时候的第一个参数改变该函数执行过程中的上下文对象(this),如果第一个参数不存在或者设置成 null/undefined,那么该函数执行过程中的上下文对象指向全局上下文对象,在 JavaScript 中指向了 window 对象。
  • 不同之处在于后续参数上,call 第一个参数以后的参数值将被一一对应的赋值给源函数的形参,而 apply 则是传入一个数组,间接传给函数的 arguments 对象。

研究下面 JS 代码是否有问题,有问题请描述问题并解决,没有问题请回答最终结果。

代码一:

var a = 10;
sayHi();
function sayHi() {
    a = a + 10;
    console.log(a);
    return a;
}
console.info(a);
console.info(sayHi() + 10);

代码一分析:

//申明全局 a,值为 10
var a = 10;
sayHi();  //调用
function sayHi() {
    a = a + 10;  //这里的 a 是全局的 a,而不是局部的,所以执行的结果是把全局 a 设置成了 20
    console.log(a);  //20
    return a;  //返回 20
}
console.info(a);  //全局 a 已经是 20 了
console.info(sayHi() + 10);  //首先又一次执行了 sayHi(),结果把 a 改成了 30,然后打印了一次 30,执行完以后返回了 30,然后在加 10,打印结果 40

代码二:

var a = 10;
sayHi();
function sayHi() {
    var a = a + 10;
    console.info(a);
    return a;
}
console.info(a);
console.info(sayHi() + 10);

代码二分析:

//申明全局 a,值为 10
var a = 10;
//调用
sayHi();
function sayHi() {
    //注意这里有一个 var,那么这里的 a 就是局部变量了,另外还是需要预解析一下,其实可以这么去看代码:
    /*
    var a;  //申明未赋值,默认值是 undefined
    a = a + 10;  // a = undefined + 10 结果是 NaN
    */
    var a = a + 10;
    console.info(a);  // NaN
    return a;  //返回 NaN
}
console.info(a);  //这个还是全局的 a,所以结果 10
console.info(sayHi() + 10); //依据上面的分析,这里的 sayHi 会打印一次 NaN,然后加 10,结果还是 NaN

代码三:

function init() {
    var ps = document.getElementsByTagName("p");  //body内有四个p标签
    for (var i=0; i

代码三分析:

// 1. console.info(i); 的执行是需要用户点击后执行的,当用户点击的时候,for 循环的执行已经结束,那么 i 的值已经被设置成了 4,也就说当用户去点击的时候 i 的值已经是 4 了;
// 2. 当 console.info(i); 执行的时候,会根据作用域链去查找 i,这样会找到 for 中定义的全局 i,这个时候不管点击那个 p 标签其实打印的都是全局 i 变量,所以结果都是统一的 4;

// 解决方案一:
function init() {
    var ps = document.getElementsByTagName("p");
    for (var i=0; i

设计一个列表,包含:地域、人数、百分比、时间。请实现按照 人数 与 时间 的排序算法。
var data = [
    {
        area: '深圳',
        percentage: 15,
        number: 80,
        staytime: 2
    },
    {
        area: '北京',
        percentage: 30,
        number: 150,
        staytime: 4
    },
    {
        area: '广州',
        percentage: 25,
        number: 60,
        staytime: 3
    },
    {
        area: '上海',
        percentage: 30,
        number: 100,
        staytime: 4
    }
];

/*
* 根据指定的字段和规则排序数据
* data Array 要排序的数据
* field string 排序依据的字段
* rule string 排序规则 DESC / ASC
* throw 
*       data is invalid : 要排序的数据不存在或类型不正确
*       field is invalid : 排序参考字段不存在
* return Array 排序后的数据
*/
function mySort(data, field, rule) {
    if (!(data instanceof Array)) {
        throw new TypeError('data is invalid');
    }
    if ( !(field in data[0]) ) {
        throw new RangeError('field is invalid');
    }
    if ( !rule || ['DESC','ASC'].indexOf( (rule = rule.toString().toUpperCase()) ) == -1 ) {
        rule = 'DESC';
    }
    
    data.sort(function(a, b) {
        var v = a[field] - b[field];
        return rule == 'ASC' ? v : -v;
    });
}

mySort(data, 'number', 'desc');
console.dir( data );

请列举一些浏览器兼容性问题?以及提高性能方面的方案

JS兼容问题

  1. JSON 解析问题:
    ecmascript5 通过 JSON 对象进行处理,ecmascript5 之前通过 eval 进行解析;
  1. 自定义属性问题:
    IE 下,可以使用获取常规属性的方法来获取自定义属性,也可以使用 getAttribute() 获取自定义属性;
    Firefox下,只能使用 getAttribute( )获取自定义属性。
    解决方法:
    统一通过 getAttribute() 获取自定义属性,不过更推荐直接通过 “点” 运算符访问元素属性。
  1. 事件对象兼容性问题:
    非标准 IE 和 chrome 下可以通过全局 event 对象来获取,标准(包括标准 IE,chrome 等)浏览器通过事件函数的第一个参数传入。
  1. 事件源对象
    IE 下使用 event.srcElement,标准下使用 event.target 来获取。
  1. 阻止事件冒泡
    通常可以通过 event.cancelBubble = false 来阻止,但是标准推荐使用 event.stopPropagation() 方法来阻止;
  1. 事件默认行为的阻止
    DOM1 事件绑定中(属性 on... 的方式)可以通过 return false 来阻止,但是在 DOM2 的事件绑定中(addEventListener)中,只能通过 event.preventDefault() 方法来阻止。

其实还有很多……懒得写了~~ ㄟ(▔,▔)ㄏ

**JS 优化问题 **

  1. 最小化 DOM 访问次数,尽可能在 JS 端执行;
  2. 如果需要多次访问某个 DOM 节点,请使用局部变量存储对它的引用;
  3. 小心处理 HTML 集合,因为它实时连系着底层的文档,把集合的长度缓存到一个变量中,并在迭代中使用它,如果需要经常操作集合,建议把它拷贝到一个数组中;
  4. 如果可能的话,使用速度更快的 API,比如 querySelectorAll 和 firstElementChild;
  5. 要留意重绘和重排,批量修改样式时,“离线”操作 DOM 树。使用缓存,并减少访问布局的次数;
  6. 使用事件委托来减少事件处理器的数量;
  7. 避免多次访问对象成员或函数中的全局变量,尽量将它们赋值给局部变量以缓存;
  8. 能用 CSS 解决的问题,尽量不用 JS 去解决;

写一个通用的事件侦听器函数?
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;
    }
};


eval是做什么的?
  • 它的功能是把对应的字符串解析成JS代码并运行;
  • 应该避免使用eval,不安全,非常耗性能(2次,一次解析成js语句,一次执行)。
  • 由JSON字符串转换为JSON对象的时候可以用eval,例如
var obj =eval('('+ str +')');

谈谈This对象的理解。
  • this总是指向函数的直接调用者(而非间接调用者);
  • 如果有new关键字,this指向new出来的那个对象;
  • 在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window;

javascript创建对象的几种方式?

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

  1. 对象字面量的方式
person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
  1. 用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();
  1. **用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方法
  1. ** 用工厂方式来创建(内置对象) **
var wcDog =new Object(); 
wcDog.name="旺财"; 
wcDog.age=3; 
wcDog.work=function(){
      alert("我是"+wcDog.name+",汪汪汪......");
 } 
wcDog.work();
  1. **用原型方式来创建 **
function Dog(){ } 
Dog.prototype.name="旺财";
Dog.prototype.eat=function(){
     alert(this.name+"是个吃货");
 } 
var wangcai =new Dog(); 
wangcai.eat();
  1. **用混合方式来创建 **
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();

Javascript如何实现继承?
  1. 构造继承
  1. 原型继承
  2. 实例继承
  3. 拷贝继承
//原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式。
function Parent(){ 
  this.name = 'wang'; 
} 
function Child(){ 
  this.age = 28; 
} 
Child.prototype = new Parent();//继承了Parent,通过原型 
var demo = new Child(); 
alert(demo.age); 
alert(demo.name);//得到被继承的属性 }

持续更新........................

摘录自 妙味课堂

你可能感兴趣的:(前端面试题集锦(Javascript篇))