2017前端面试题之Js篇(1)

1 . 请解释事件代理 (event delegation)

当需要对很多元素添加事件的时,可以通过将事件添加到它们的父节点通过委托来触发处理函数。其中利用到了浏览器的事件冒泡机制。

var delegate = function(client, clientMethod) {
  return function() {
      return clientMethod.apply(client, arguments);
  }
}

var agentMethod = delegate (client, clientMethod);
agentMethod();

// 获取父节点,并为它添加一个click事件
document.getElementById("parent-list").addEventListener("click",function(e) {
  // 检查事件源e.targe是否为Li
  if(e.target && e.target.nodeName.toUpperCase == "LI") {
    // 真正的处理过程在这里
    console.log("List item ",e.target.id.replace("post-")," was clicked!");
  }
});


2 . 谈谈浏览器的事件冒泡机制

对于事件的捕获和处理,不同的浏览器厂商有不同的处理机制,我们以W3C对DOM2.0定义的标准事件为例
DOM2.0模型将事件处理流程分为三个阶段:一、事件捕获阶段,二、事件目标阶段,三、事件起泡阶段。

  • 事件捕获:当某个元素触发某个事件(如onclick),顶层对象document就会发出一个事件流,随着DOM树的节点向目标元素节点流去,直到到达事件真正发生的目标元素。在这个过程中,事件相应的监听函数是不会被触发的。
  • 事件目标:当到达目标元素之后,执行目标元素该事件相应的处理函数。如果没有绑定监听函数,那就不执行。
  • 事件起泡:从目标元素开始,往顶层元素传播。途中如果有节点绑定了相应的事件处理函数,这些函数都会被一次触发。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)来组织事件的冒泡传播。


3 . JavaScript 中 this 是如何工作的。

  • 作为函数调用,this 绑定全局对象,浏览器环境全局对象为 window 。
  • 内部函数的 this 也绑定全局对象,应该绑定到其外层函数对应的对象上,这是 JavaScript的缺陷,用that替换。
  • 作为构造函数使用,this 绑定到新创建的对象。
  • 作为对象方法使用,this 绑定到该对象。
  • 使用apply或call调用 this 将会被显式设置为函数调用的第一个参数。


4 . 谈谈CommonJs 、AMD 和CMD

CommonJS规范,一个单独的文件就是一个模块。每一个模块都是一个单独的作用域 CommonJS的使用代表:NodeJS

AMD 即Asynchronous Module Definition 异步模块定义 它是一个在浏览器端模块化开发的规范 AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出

CMD 即Common Module Definition 通用模块定义 其代表为SeaJS

requireJS主要解决两个问题

  • 多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
  • js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长

CMD和AMD的区别

  • AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
  • CMD推崇就近依赖,只有在用到某个模块的时候再去require


5 . 谈谈对IIFE的理解

IIFE即Immediately-Invoked Function Expression 立即执行函数表达式

不推荐

(function(){})();

推荐

(function(){}());

在javascript里,括号内部不能包含语句,当解析器对代码进行解释的时候,先碰到了(),然后碰到function关键字就会自动将()里面的代码识别为函数表达式而不是函数声明。

知识拓展:

function(){ /* code */ }();  解释下该代码能正确执行吗?

不行,在javascript代码解释时,当遇到function关键字时,会默认把它当做是一个函数声明,而不是函数表达式,如果没有把它显视地表达成函数表达式,就报错了,因为函数声明需要一个函数名,而上面的代码中函数没有函数名。(以上代码,也正是在执行到第一个左括号(时报错,因为(前理论上是应该有个函数名的。)

function foo(){ /* code */ }();  解释下该代码能正确执行吗?

在一个表达式后面加上括号,表示该表达式立即执行;而如果是在一个语句后面加上括号,该括号完全和之前的语句无法匹配,而只是一个分组操作符,用来控制运算中的优先级(小括号里的先运算)相当于先声明了一个叫foo的函数,之后进行()内的表达式运算,但是()(分组操作符)内的表达式不能为空,所以报错。(以上代码,也就是执行到右括号时,发现表达式为空,所以报错)。



6 . .call 和 .apply 的区别是什么?

foo.call(this, arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)

call, apply方法区别是,从第二个参数起, call方法参数将依次传递给借用的方法作参数, 而apply直接将这些参数放到一个数组中再传递, 最后借用方法的参数列表是一样的.



7 . 请解释 Function.prototype.bind?

bind() 方法的主要作用就是将函数绑定至某个对象,bind() 方法会创建一个函数,函数体内this对象的值会被绑定到传入bind() 函数的值。

原理

Function.prototype.bind = function(context) {
 var self = this; // 保存原函数
 return function() { // 返回一个新函数
  return self.apply(context, arguments); // 执行新函数时,将传入的上下文context作为新函数的this
 }
}

用法:

var paint = {
 color: "red",
 count: 0,
 updateCount: function() {
  this.count++;
  console.log(this.count);
 }
};

// 事件处理函数绑定的错误方法:
document.querySelector(‘button‘)
 .addEventListener(‘click‘, paint.updateCount); // paint.updateCount函数的this指向变成了该DOM对象

// 事件处理函数绑定的正确方法:
document.querySelector(‘button‘)
 .addEventListener(‘click‘, paint.updateCount.bind(paint)); // paint.updateCount函数的this指向变成了paint


8 . 请解释原型继承 (prototypal inheritance) 的原理。

当查找一个对象的属性时,JavaScript 会向上遍历原型链,直到找到给定名称的属性为止。——出自JavaScript秘密花园

JavaScript中的每个对象,都有一个内置的 proto 属性。这个属性是编程不可见的(虽然ES6标准中开放了这个属性,然而浏览器对这个属性的可见性的支持不同),它实际上是对另一个对象或者 null 的引用。

当一个对象需要引用一个属性时,JavaScript引擎首先会从这个对象自身的属性表中寻找这个属性标识,如果找到则进行相应读写操作,若没有在自身的属性表中找到,则在 proto 属性引用的对象的属性表中查找,如此往复,直到找到这个属性或者 proto 属性指向 null 为止。

以下代码展示了JS引擎如何查找属性:

//__proto__ 是一个不应在你代码中出现的非正规的用法,这里仅仅用它来解释JavaScript原型继承的工作原理。
function getProperty(obj, prop) {
if (obj.hasOwnProperty(prop))
    return obj[prop]
else if (obj.__proto__ !== null)
    return getProperty(obj.__proto__, prop)
else
    return undefined
}

JS的ECMA规范只允许我们采用 new 运算符来进行原型继承

原型继承

function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype = {
    print: function () { console.log(this.x, this.y); }
};

var p = new Point(10, 20);
p.print(); // 10 20

顺便阐述下new 运算符是如何工作的?

  • 创建类的实例。这步是把一个空的对象的 proto 属性设置为 F.prototype 。
  • 初始化实例。函数 F 被传入参数并调用,关键字 this 被设定为该实例。
  • 返回实例
function New (f) {
    var n = { ‘__proto__‘: f.prototype }; /*第一步*/
    return function () {
        f.apply(n, arguments);            /*第二步*/
        return n;                         /*第三步*/
    };
}

JavaScript中真正的原型继承

Object.create = function (parent) {
    function F() {}
    F.prototype = parent;
    return new F();
};

使用真正的原型继承(如 Object.create 以及 proto)还是存在以下缺点:

  • 标准性差:proto 不是一个标准用法,甚至是一个不赞成使用的用法。同时原生态的 Object.create 和道爷写的原版也不尽相同。
  • 优化性差: 不论是原生的还是自定义的 Object.create ,其性能都远没有 new 的优化程度高,前者要比后者慢高达10倍。

ES6 内部实现类和类的继承

class Parent {
    constructor(name) { //构造函数
          this.name = name;
    }
    say() {
          console.log("Hello, " + this.name + "!");
    }
}

class Children extends Parent {
    constructor(name) { //构造函数
        super(name);    //调用父类构造函数
        // ...
    }
    say() {
          console.log("Hello, " + this.name + "! hoo~~");
    }
}

参考:



9 . 请尽可能详尽的解释 AJAX 的工作原理

Ajax 的原理简单来说通过 XmlHttpRequest 对象来向服务器发异步请求,从服务器获得数据,然后用 JavaScript来操作 DOM 而更新页面。 这其中最关键的一步就是从服务器获得请求数据。

不使用ajax工作原理

不使用ajax浏览网页的原理

使用ajax工作原理

使用ajax网页的原理



10 . javascript中"attribute" 和 "property" 的区别是什么?

property 和 attribute非常容易混淆,两个单词的中文翻译也都非常相近(property:属性,attribute:特性),但实际上,二者是不同的东西,属于不同的范畴。每一个DOM对象都会有它默认的基本属性,而在创建的时候,它只会创建这些基本属性,我们在TAG标签中自定义的属性是不会直接放到DOM中的。

  • property是DOM中的属性,是JavaScript里的对象;
  • attribute是HTML标签上的特性,它的值只能够是字符串;
  • DOM有其默认的基本属性,而这些属性就是所谓的“property”,无论如何,它们都会在初始化的时候再DOM对象上创建。
  • 如果在TAG对这些属性进行赋值,那么这些值就会作为初始值赋给DOM的同名property。

作者:岁寒3友
链接:http://www.jianshu.com/p/8e505fe77762
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

时间: 2024-10-09 14:48:48

2017前端面试题之Js篇(1)的相关文章

前端面试题(JS篇)

原题地址:http://handyxuefeng.blog.163.com/blog/static/454521722013111714040259/ 好吧,最近打算换工作,所以关注比较多的是面试题,这套还不错,留下~~ 1.JS相关问题: 解释下事件代理(基础题) 解释下 JavaScript 中 this 是如何工作的(始终指向调用当前函数的对象) 解释下原型继承的原理. AMD vs. CommonJS? 什么是哈希表? 解释下为什么接下来这段代码不是 IIFE(立即调用的函数表达式):f

2017前端面试题之Html篇(1)

1 . doctype(文档类型) 的作用是什么? 对文档进行有效性验证: 它告诉用户代理和校验器这个文档是按照什么DTD 写的.这个动作是被动的, 每次页面加载时,浏览器并不会下载DTD 并检查合法性,只有当手动校验页面时才启用. 决定浏览器的呈现模式: 对于实际操作,通知浏览器读取文档时用哪种解析算法. 如果没有写,则浏览器则根据自身的规则对代码进行解析,可能会严重影响HTML 排版布局. 浏览器有三种方式解析HTML文档. 非怪异(标准)模式 怪异模式 部分怪异(近乎标准)模式 2 . H

2017前端面试题之Css篇(1)

1 . CSS 属性是否区分大小写? 答:不区分. HTML,CSS都对大小写不敏感,但为了更好的可读性和团队协作一般都小写,而在XHTML 中元素名称和属性是必须小写的. 2 . 行内(inline)元素 设置margin-top和margin-bottom 是否起作用?padding-top和padding-bottom是否会增加它的高度? 答:行内元素又分为替换元素(replaced element)和非替换元素(non-replaced element). 替换元素: 是指用作为其他内容

前端面试题之JS篇

1.var a=b=3的执行顺序 var a,b; (function(){     alert(a);     alert(b);     var a=b=3;     alert(a);     alert(b); })(); alert(a); alert(b); 输出结果:undefined,undefined,3,3,undefined,3 参考:http://stackoverflow.com/questions/27329444/why-a-is-undefined-while-b

各大互联网公司前端面试题(js)

对于巩固复习js更是大有裨益.    初级Javascript: 1.JavaScript是一门什么样的语言,它有哪些特点? 没有标准答案. 2.JavaScript的数据类型都有什么? 基本数据类型:String,Boolean,Number,Undefined, Null 引用数据类型:Object(Array,Date,RegExp,Function) 那么问题来了,如何判断某变量是否为数组数据类型? 方法一.判断其是否具有“数组性质”,如slice()方法.可自己给该变量定义slice方

前端面试题整理---JS基础

为了督促自己学习,整理了一下前端的面试题 JavaScript: JavaScript 中如何监测一个变量是String类型? typeof(obj)==="string"; typeof obj ==="string"; obj.constructor ===string JS中清除字符串空格的方法        方法一:使用正则匹配 // 去除所有的空格 var str1 = strings.replace(/\s*/g,""); // 去掉

web前端面试题整理后篇(程序篇)

需要web前端课程工具和电子书,可以加: 33群105601600;  22群120342833 1. var obj = {a : 1}; (function (obj) { obj = {a : 2}; })(obj);       //问obj的值会改变吗? var obj = {a : 1}; (function (obj) {     obj = {a : 2}; })(obj); //问obj的值会改变吗? 外部的obj不变. 因为匿名函数中obj传入参数等于是创建了一个局部变量ob

前端面试题,js预处理部分小结,函数声明提升和变量声明提升

博客搬迁,给你带来的不便,敬请谅解! http://www.suanliutudousi.com/2017/11/25/%e5%89%8d%e7%ab%af%e9%9d%a2%e8%af%95%e9%a2%98%ef%bc%8cjs%e9%a2%84%e5%a4%84%e7%90%86%e9%83%a8%e5%88%86%e5%b0%8f%e7%bb%93%e5%87%bd%e6%95%b0%e5%a3%b0%e6%98%8e%e6%8f%90%e5%8d%87%e5%92%8c%e5%8f%9

前端面试题:JS中的let和var的区别

最近很多前端的朋友去面试被问到let和var的区别,其实阮一峰老师的ES6中已经很详细介绍了let的用法和var的区别.我简单总结一下,以便各位以后面试中使用. ES6 新增了let命令,用来声明局部变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效,而且有暂时性死区的约束. 先看个var的常见变量提升的面试题目: 题目1: var a = 99; // 全局变量a f(); // f是函数,虽然定义在调用的后面,但是函数声明会提升到作用域的顶部. console.l