前端面试中该问些什么?

3月份是找工作的高峰期,最近也面试了很多前端,然后本人也不是什么技术大牛,很多时候都不知道该从那些方面去考察一个人的技术水平,希望这篇文章能够抛砖引玉,听听各位大神的意见,那么就来说说我面试前端主要问些什么吧。

首先,css和html的考察只要是简历上有几个项目我都不会去多问,我个人偏好问的是js,那么就只能先对这语言的认识开始了。
 

一、JavaScript的对象。

JavaScript 中所有变量都是对象:字符串、数值、数组、函数...,除了两个例外 null 和 undefined。JavaScript 的对象只是带有属性方法的特殊数据类型,
可以作为哈希表使用,主要用来保存命名的键与值的对应关系。JavaScript 提供多个内建对象,比如 String、Date、Array 等等。

此外,JavaScript 允许自定义对象,有两种不同的方法:

  1. 定义并创建对象的实例
  2. 使用函数来定义对象,然后创建新的对象实例

1、创建直接的实例

person=new Object();
person.firstname="Bill";
person.lastname="Gates";
person.age=56;
person.eyecolor="blue";

这个例子创建了对象的一个新实例,并向其添加了四个属性;此外,我们也可以通过对象字面量直接创建对象实例:person={firstname:"John",lastname:"Doe",age:50,eyecolor:"blue"};

2、使用对象构造器

使用函数来构造对象:

function person(firstname,lastname,age,eyecolor)
{
    this.firstname=firstname;
    this.lastname=lastname;
    this.age=age;
    this.eyecolor=eyecolor;
} 
参照来源:http://www.w3school.com.cn/js/js_objects.asp

 

二、JavaScript的面向对象。

  Javascript是一种基于对象(object-based)的语言,你遇到的所有东西几乎都是对象。但是,它又不是一种真正的面向对象编程(OOP)语言,因为它的语法中没有class(类)。JavaScript 不包含传统的类继承模型,而是使用 prototype 原型模型。虽然这经常被当作是 JavaScript 的缺点被提及,其实基于原型的继承模型比传统的类继承还要强大。那么javascript是如何去实现继承的呢?
 
比如,现在有一个"动物"对象的构造函数。
 
function Animal(){
  this.species = "动物";
}

还有一个"猫"对象的构造函数。

function Cat(name,color){
  this.name = name;
  this.color = color;
}

怎样才能使"猫"继承"动物"呢?

使用prototype属性。

如果"猫"的prototype对象,指向一个Animal的实例,那么所有"猫"的实例,就能继承Animal了。
  Cat.prototype = new Animal();
  Cat.prototype.constructor = Cat;
  var cat1 = new Cat("大毛","黄色");
  alert(cat1.species); // 动物

代码的第一行,我们将Cat的prototype对象指向一个Animal的实例。

Cat.prototype = new Animal();

它相当于完全删除了prototype 对象原先的值,然后赋予一个新值。但是,第二行又是什么意思呢?

Cat.prototype.constructor = Cat;

 原来,任何一个prototype对象都有一个constructor属性,指向它的构造函数。如果没有"Cat.prototype = new Animal();"这一行,Cat.prototype.constructor是指向Cat的;加了这一行以后Cat.prototype.constructor指向Animal。

alert(Cat.prototype.constructor == Animal); //true
更重要的是,每一个实例也有一个constructor属性,默认调用prototype对象的constructor属性。  
alert(cat1.constructor == Cat.prototype.constructor); // true
因此,在运行"Cat.prototype = new Animal();"这一行之后,cat1.constructor也指向Animal!  
alert(cat1.constructor == Animal); // true
这显然会导致继承链的紊乱(cat1明明是用构造函数Cat生成的),因此我们必须手动纠正,将Cat.prototype对象的constructor值改为Cat。这就是第二行的意思。
这是很重要的一点,编程时务必要遵守。下文都遵循这一点,即如果替换了prototype对象, 
o.prototype = {};

 

那么,下一步必然是为新的prototype对象加上constructor属性,并将这个属性指回原来的构造函数。
o.prototype.constructor = o;

这里还有另外一种方法,就是直接继承prototype,这种方法是对第一种方法的改进。由于Animal对象中,不变的属性都可以直接写入Animal.prototype。所以,我们也可以让Cat()跳过 Animal(),直接继承Animal.prototype。

现在,我们先将Animal对象改写:
function Animal(){ }
Animal.prototype.species = "动物";

然后,将Cat的prototype对象,然后指向Animal的prototype对象,这样就完成了继承。 

Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛","黄色");
alert(cat1.species); // 动物
与前一种方法相比,这样做的优点是效率比较高(不用执行和建立Animal的实例了),比较省内存。缺点是 Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对Cat.prototype的修改,都会反映到Animal.prototype。
所以,上面这一段代码其实是有问题的。请看第二行 
Cat.prototype.constructor = Cat;
这一句实际上把Animal.prototype对象的constructor属性也改掉了! 
alert(Animal.prototype.constructor); // Cat
参照来源:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance.html  想要了解更多继承实现的小伙伴可以看下这个博客
 

三、上下文(this的理解)。

JavaScript 有一套完全不同于其它语言的对 this 的处理机制。在五种不同的情况下 ,this 指向的各不相同。

1、全局范围内this;

当在全部范围内使用 this,它将会指向全局对象。浏览器中运行的 JavaScript 脚本,这个全局对象是 window。

2、函数调用

foo();
这里 this 也会指向全局对象。
ES5 注意: 在严格模式下(strict mode),不存在全局变量。 这种情况下 this 将会是 undefined。

3、方法调用

test.foo();
这个例子中,this 指向 test 对象。

4、调用构造函数

new foo();
如果函数倾向于和 new 关键词一块使用,则我们称这个函数是 构造函数。在函数内部,this 指向新创建的对象。

5、显式的设置 this

function foo(a, b, c) {}
var bar = {};
foo.apply(bar, [1, 2, 3]); // 数组将会被扩展,如下所示
foo.call(bar, 1, 2, 3); // 传递到foo的参数是:a = 1, b = 2, c = 3
当使用 Function.prototype 上的 call 或者 apply 方法时,函数内的 this 将会被 显式设置为函数调用的第一个参数。
因此函数调用的规则在上例中已经不适用了,在foo 函数内 this 被设置成了 bar。
 
注意: 在对象的字面声明语法中,this 不能用来指向对象本身。 因此 var obj = {me: this} 中的 me 不会指向 obj,因为 this 只可能出现在上述的五种情况中。 译者注:这个例子中,如果是在浏览器中运行,obj.me 等于 window 对象。
 

四、闭包

“官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
相信很少有人能直接看懂这句话,因为他描述的太学术。其实这句话通俗的来说就是:JavaScript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”。看下面这段代码:
function a() {
    var i = 0;
    function b() {
        alert(++i);
    }
    return b;
}
var c = a();
c();
这段代码有两个特点:
函数b嵌套在函数a内部;
函数a返回函数b。
引用关系如图:
 
 
这样在执行完var c=a()后,变量c实际上是指向了函数b,b中用到了变量i,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。这段代码其实就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:
当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个我们通常所谓的“闭包”。
让我们说的更透彻一些。所谓“闭包”,就是在构造函数体内定义另外的函数作为目标对象的方法函数,而这个对象的方法函数反过来引用外层外层函数体中 的临时变量。这使得只要目标 对象在生存期内始终能保持其方法,就能间接保持原构造函数体当时用到的临时变量值。尽管最开始的构造函数调用已经结束,临时变量的名称也都消失了,但在目 标对象的方法内却始终能引用到该变量的值,而且该值只能通这种方法来访问。即使再次调用相同的构造函数,但只会生成新对象和方法,新的临时变量只是对应新 的值,和上次那次调用的是各自独立的。
简而言之,闭包的作用就是在a执行完并返回后,闭包使得Javascript的垃圾回收机制GC不会收回a所占用的资源,因为a的内部函数b的执行需要依赖a中的变量。、

闭包的应用场景

保护函数内的变量安全。以最开始的例子为例,函数a中i只有函数b才能访问,而无法通过其他途径访问到,因此保护了i的安全性。
在内存中维持一个变量。依然如前例,由于闭包,函数a中i的一直存在于内存中,因此每次执行c(),都会给i自加1。
通过保护变量的安全实现JS私有属性和私有方法(不能被外部访问)推荐阅读:http://javascript.crockford.com/private.html
私有属性和方法在Constructor外是无法被访问的 
function Constructor(...) {
    var that = this;
    var membername = value;
    function membername(...) {...}
}
以上3点是闭包最基本的应用场景,很多经典案例都源于此。
参照来源:http://blog.csdn.net/adeyi/article/details/8808046  要理解更多的小伙伴可以访问该链接
 

五、Javascript模块化开发的实现

var module1 = (function(){
  var _count = 0;
  var m1 = function(){
      //...
  };
  var m2 = function(){
      //...
  };
  return {
    m1 : m1,
    m2 : m2
  };
})();
 
暂时先写到这里了,这也是我在前端技术水平方向上几个比较关注的点,如果是你的话会从哪些方面去考察呢,或者是你在面试的过程中又遇到那些印象比较深刻的题目呢,有兴趣的话大家一起讨论讨论。。。
 

 

 
posted @ 2015-03-10 23:43  jackyWHJ  阅读(6634)  评论(2编辑  收藏  举报