分类目录归档:JavaScript

关于前端面试

摘自:https://mdluo.github.io/blog/about-front-end-interview/

继上一篇 关于程序员求职简历 之后如果顺利的话就应该是面试了,在此也整理一下最近在网上收集的前端面试相关资料,包括预备知识、书籍、面试考点、面经等。前端方面资料其实太多太多,就光从知乎、前端乱炖、w3cplus 等网站就能找到很多,所以针对细节不发散,仅挑一些内容丰富的合集,更多的资料可以从其中找到。

1. 前端团队

参考我整理的列表(部分维护了网站、技术型前端团队): 国内知名前端团队

2. 知识技能

前端技能汇总 Frontend Knowledge Structure (源码)(朴灵,阿里巴巴)

大前端的瑞士军刀,只记录有用的源码)(聂微东,百度)

前端收集(罗磊,腾讯阅文)

知乎上前端开发领域有哪些值得推荐的问答?——知乎

2015-2016前端知识体系图谱(w3ctech)

前端收藏夹源码)(w3ctrian)

QQ联盟群交流(492107297)群规(有大量的教程、资料、面试题)(豪情)

3. 学习路线、书籍

前端开发者手册(Pomy,美团)

有哪些关于前端开发技术(HTML、CSS 和 JavaScript 等)的值得推荐的书籍?(李路,Knewone)

前端路上的旅行(大漠,淘宝)

Developer进阶书单(phodal,ThoughtWorks)

年后跳槽如何准备?(豪情)

学习前端的这一年(Helkyle @ w3ctrian)

零基础的前端开发初学者应如何系统地学习?——知乎

4. 面试考点、面经

写给前端面试者(大漠,淘宝)

谈谈面试与面试题谈谈面试与面试题 II (winter,淘宝)

互联网公司技术岗实习/求职经验(实习内推+简历+面试+offer篇)(张秋怡,阿里巴巴)

史上最全 前端开发面试问题及答案整理(trigkit4,口袋购物)

最全前端开发面试问题及答案整理(AutumnsWind)

前端开发面试题(马云云,ZTE)

收集的前端面试题和答案(邱德清,阿里妈妈)

web前端面试相关的知识点(王文杰,乐视云)

2016十家公司前端面试小记(沧海)

一道常被人轻视的前端JS面试题(沧海)

Web前端开发测试题(大漠,淘宝)

常见前端面试题及答案(默语,腾讯)

前端工作面试问题(一)(Ruipeng Zhang,哈工大)

面试经验分享之数据结构、算法题(Song Chengru,清华)

名企笔试(伯乐在线)

如何面试一名前端开发工程师?(芋头,大搜车)

国内大型互联网公司(如BAT)对于web前端开发方向校招都考些什么?——知乎

如何面试前端工程师?——知乎

初级前端面试需要带什么作品?——知乎

5. 网站、专栏、周刊

前端开发 —— 知乎

前端 —— 稀土掘金

前端乱炖

w3cplus

w3ctech

前端开发博客

前端观察

前端De早读课

前端大全 —— 伯乐在线

前端 —— 开发早读课

imweb前端社区

奇舞周刊

精华 —— CNode社区

web前端开发 —— segmentfault

发现:前端 —— 开发者头条

6. 前端新技术

谈谈前端『新』技术(尤雨溪,Meteor)

为什么整个互联网行业都缺前端工程师?(100offer)

近几年前端技术盘点以及 2016 年技术发展方向(小胡子哥,淘宝)

如何跟上前端开发的最新前沿(GitHub)

HTML的BUTTON标签

调试一个JavaScript的程序,相当郁闷(花了不少时间),虽然问题不经意间解决(哥的运气还好~),但还不知道所以然。

简单叙述下该场景:

JS代码(Ajax):

<script>

function search(item) {
items = item.forms.elements;
Ajax.call(…..);
}

</script>

HTML代码:

<form actioin=”javascript:;” method=”post”>
<button onclick=”search(this)”>搜索</button>
</form>

以上是简化的模拟场景。一直跟踪到XMLHttpRequest的onreadystatechange方法,检查到status为0,Firefox给出的提示是:Firefox不知道如何打开此地址,因为协议(Javascript)未知任何程序关联。

用了好多test确保程序无误,但在以上情况下就通不过。当快要绝望的时候,我把button这个HTML标签,加个type=”button”。噢嘢!运行成功。坑爹的!

PS:<button> 控件 与 <input type=”button”> 相比,提供了更为强大的功能和更丰富的内容,所以一开始用了button,没想到这里被“调戏”了下~

Java工程师可能不知道的那些FE潜规则

写了一个多月JavaScript,感觉如今可不比几年前只有IE6的年代,而且过去只是用JS写个Ajax或者是简单的表单验证,可如今写一个稍微复杂点的小应用,要兼容所有浏览器,才发现真是太难了,难怪FE是一个独立的工种,有别于我们这些Java工程师了。

1 首先是最简单的select标签,就有诸多不兼容:

A、 cloneNode方法,对于非IE浏览器没有问题,对于IE浏览器,我遇到的问题包括:
1)option selected的会clone不过去,然后会将第一个option作为selected值
2)事件clone也会有问题

B、Readonly:对于IE6,可以通过以下方法将select设为readonly:
obj.onbeforeactive=function(){return false}
obj.onfocus=function(){obj.blur();
obj.onmouseover=function(){obj.setCapture();}
obj.onmouseout=function(){obj.releaseCapture();}
对于其他浏览器,我采用的是元素替代法,动态创建一个input标签,把值赋给它,然后将select隐藏。

C、select的z-index对于IE6无效,网上有很多关于这个讨论,JQuery采用一个iframe搞定

D、动态添加option的方法不同,这个网上一搜一大堆

E、对于onclick和onchange的响应不同,在FF下可以在onclick select时动态读取option值然后构建option,然后选中一个值后执行onchange事件,但是IE下不能这样做。

2 css对offsetWidth之类的理解不同 – http://newleague.iteye.com/blog/765535

3 对于vertical-align baseline的理解不同 – http://w3help.org/zh-cn/causes/RD1016

4 设置背景色
element.style.backgroundColor
在firefox下想改变颜色,必须先设为null,再设为其他颜色才行,即先取消原来的颜色。
在IE下,想取消颜色,必须设为”才行,而换其他颜色,无需先去掉之前的颜色。

5 不同浏览器去padding的理解不同

6 不同浏览器对强制换行和强制不换行的理解不同 – http://www.cftea.com/c/2009/01/QPDZU40MNW8FYYG3.asp
最恶心的是对于IE6,如果是<td><span>我是蚊子</span></td>,那么在td上写了word-break:keep-all依然无效,必须在span上也写。

7 获得head节点的方式不同
在Firefox下可以用window.head,而所有浏览器都兼容的方式是document.getElementsByTagName(‘head’)[0]

8 往head上添加css code的方法不同,也就是动态添加<style>标签。
IE下可以用var style=document.createStyleSheet();style.cssText=cssCode;而有文章说,在Windows上的IE,用createStyleSheet返回的是styleElement的styleSheet,而在Mac上返回的是styleElement自己。在其他浏览器下需要document.createElement(‘style’); 然后还有区分是否具有styleSheet属性。

9 对于onchange事件,firefox浏览器可以注册在table,div等组件上,然后通过冒泡,拦截input,select等发出的事件,而IE不行,必须绑定到相应的组件上

10 将input设为readonly=true,其依然会响应keypress,keyup,keydown,onblur事件

11 IE和非IE对于停止冒泡和取消默认行为的方法不同

12 大家都知道IE和非IE在动态添加事件时使用的方法不同,IE是attachEvent,其他是addListener,然后参数也不同。更重要的是如果一个控件绑定了多个function,他们绑定和执行的顺序是不同的,IE是跟绑定顺序相反,其他是跟绑定顺序相同

13 获得当前事件不同,一个是window.event一个是直接接受event

14 FF下执行offset系列非常慢,但是IE下比较快,而IE的改变CSS的执行非常慢。
Firefox6比Firefox3.6速度快的多,相差好几百倍(针对一个400行*50列的表格的JS处理)

15 如果大量动态改变css,那么使用document.createDocumentFragment,然后将需要修改样式的Dom获取出来appendChild到这个临时的fragment上,修改完css后再append回去即可,这样性能能差好几百倍。

16 浏览器加载网页时,顺序读取html,遇到外部js链接会读进来,然后按顺序执行,边解释边执行,而对于外部css,图片等则是启动另外的线程连接服务器去获取。
IE对于CSS引入有限制,我没试过,但有篇文章讨论:http://blog.csdn.net/ydshang/article/details/4158211

17 表格定位某一行,可以通过改变scrollTop来实现,当然如果出现了滚动条的话

18 IE的Dom用完要记得释放,可以在unload方法中,否则会出现内存泄露

19 unload方法在各个浏览器里各不相同,我之前的文章里有介绍。http://sslaowan.iteye.com/blog/1128209

20 我知道了为什么FE最喜欢的浏览器是FF,最讨厌的是IE6,恨不得IE6去死,其他IE也不怎么样。但是Chrome,Opera也各有各的bug

21 Ajax当使用同步模式时,如果访问的链接是错误的,那么FF会在控制台报错,而IE会直接弹出个对话框,然后就崩溃了。

22 FF支持document.getElementsByClass等方法,IE不支持,可以自己写一个。

23 trim方法在IE和FF下不同,需要自己写一个,可以用正则表达式

24 动态设置元素的css class在IE和非IE浏览器下也不同

25 有时本地字体库会影响你的字体,大小等显示,但是有时甚至会影响你的布局

26 字符串也可以使用><等符号比较大小,但是是字符串比较,不要被骗了

27 JS中this问题非常让人困惑

28 判断浏览器可以有很多方法,主流是两大类,agent判断法和特性法,后者好像更推荐

29 JS是面向对象语言,对象.属性=值 只影响当前对象,而对象.prototype.属性则影响整个类。非IE浏览器可以覆盖DOM对象的类方法,但是IE不行。

30 getComputedStyle,获得外部添加的css,FF支持,IE不支持,具体看这篇文章 http://www.jb51.net/article/16128.htm

31 IE和Chrome支持outerHTML方法,其他浏览器没有。相关讨论:http://walsh.iteye.com/blog/261966http://stackoverflow.com/questions/1700870/how-do-i-do-outerhtml-in-firefox

32 还有一个特悲剧的,IE下会把document.[formname.]控件Id当成那个控件,如果把一个控件比如input的id设为了submit,那么form.submit()就会报错。

33 如果利用全角空格进行布局时,Firefox支持,而IE会去除只剩一个,但是是在某些情况下的,具体看这篇文章:http://w3help.org/zh-cn/causes/BT1025

34 透明度:
filter:alpha(opacity=0); /* IE */
-moz-opacity:0.3; /* Moz + FF */
opacity: 0.3;

至于用不用var的区别,undefined和null的区别,Ajax构建的不同方式,这些一般的Java程序员都了解了。

很多Java程序员也会使用JS框架,比如JQuery,Extjs和Dojo,她们都帮我们屏蔽了很多兼容性问题。Dojo提供了Java一样的面向对象机制。

抛砖引玉,你还遇到过什么陷阱,那些FE都知道,而我们Java工程师不知道?

原文:http://sslaowan.iteye.com/blog/1156214

Chrome浏览器加载XML文档

Chrome浏览器不支持load方法加载XML文档。网上找了下,需要如下解决:

function loadXMLDoc(xml_name)
{
  var xmlDoc;

  try
  {
    xmlDoc = new ActiveXObject("Microsoft.XMLDOM");   // Support IE
  }
  catch(e)
  {
    try
    {
     // Support Firefox, Mozilla, Opera, etc
      xmlDoc = document.implementation.createDocument("", "", null) ;// 创建一个空的 XML 文档对象。
    }
    catch(e)
    {
       alert(e.message);
    }
  }

  // 加载XML文档
  try
  {
    xmlDoc.async = false;   // 关闭异步加载
    xmlDoc.load(xml_name);
  }
  catch(e)
  {
     // alert(e.message)   如果浏览器是Chrome,则会catch这个异常:Object # (a Document) has no method "load",所以,以下实现支持chrome加载XML文档(只是粗略的写下)

    var xhr = new XMLHttpRequest();
    xhr.open("GET", xml_name, false);
    xhr.send(null);
    
    xmlDoc = xhr.responseXML.documentElement;
  }

   return xmlDoc;
}

BTW,各浏览器加载XML字符串也不同。

IE使用 loadXML() 方法来解析 XML 字符串:

xmlDoc.loadXML(xml_str);

FireFox等使用DOMParser 对象解析XML字符串:

var parseXml = new DOMParser();
var doc = parseXml.parseFromString(xml_str,"text/xml");

Ajax的call方法

被以下问题郁闷了下。下面比较抽象简述下这个问题。

index.html文件

Test

test.js文件:

/**
  * 定义一个无类型的对象listInfo
  */
var listInfo = 
{
     // 属性info,为对象类型
     info : {
         name : "ljlwill"
     },

    // 方法getName
     getName : function()
     {
          // 我这个例子这样来设置setName,好像“蛮干”哈,现在我只是简化和抽象,实际项目就是要用这些规则
          Ajax.call(this.setName);

          alert(this.info["name"]);
     },

    // 方法setName
    setName: function(name)
    {
        this.info["name"] = name;    // 大家注意这个this
    }
}


/**
  * 定义无类型的Ajax对象
  */
var Ajax = 
{
     // 创建XMLHttpRequest对象
    createXMLHttpRequest : function() 
   {
        var xhr;

        if (window.ActiveXObject)
        {
             var versions = ['Microsoft.XMLHTTP', 'MSXML6.XMLHTTP', 'MSXML5.XMLHTTP', 'MSXML4.XMLHTTP', 'MSXML3.XMLHTTP', 'MSXML2.XMLHTTP', 'MSXML.XMLHTTP'];

             for (var i=0; i< versions.length; i++)
             {
                  try
                  {
                       xhr = new ActiveXObject(versions(i));
                       break;
                  }
                   catch(ex)
                  {
                       continue;
                  }
             }
             
        }
        else
        {
              xhr = new XMLHttpRequest();
        }
    
        return xhr;
   },

   // call方法
   call : function(callback)
   {
       var xhr = this.createXMLHttpRequest();
       
       // 以下也一切从简
       xhr.open("GET", "index.php", true);  //异步
       
       xhr.onreadysatechange = function()
       {
           // 完成
           if (xhr.readySate == 4) 
           {
               swith (xhr.status) 
               { 
                   case : 200    // OK
                      if (typeof(callback) == "function")
                      {
                           callback.call(this, "ljlwill -- from Ajax");   // 将自身绑定到另外一个对象执行
                      } 
               }

               xhr = null;  // 销毁
           }

       }
       
       if (xhr != null) xhr.send(null);
   }

}

这时,我本意要,点击那个Test链接,先弹出“ljlwill",然后在点击一次的时候是弹出“ljlwill -- from Ajax",可是却不论如何点击,都是弹出"ljlwill"。listInfo对象的setName没有执行?里面加个alert,证明是有执行的。

其实,是这个call方法”捣鬼“。

在JavaScript中,将函数自绑定到另外一个对象上执行,有appliy和call方法,它们只是在参数方面有所不同(具体可相关资料,这里不详述)。

Function.prototype.call(thisArg, [arg1, [arg2, ] ...]),所有函数的内部this指针都会指向thisArg,从以上代码中这个thisArg为Ajax对象,非listInfo对象,这样当然改变不了name值了!

所以,把那callback.call(this, "ljlwill -- from Ajax")该为callback.call(listInfo, "ljlwill -- from Ajax"),问题解决。只是这样有一定的隐患,比如listInfo未定义,或改名,牵动的东西还蛮多!所以,可以就让Ajax对象来运行这函数,而函数的方法内部指明关联哪个对象!

以上也是个人愚见,不是有否不足,或不对,期待讨论~

JavaScript面向对象基础

传统的Web开发模式中,JavaScript一直被当作过程化的语言使用,比如表单验证之类。其实,JavaScript提供了完善的机制来实现面向对象的开发思想,这在Ajax技术上,表现得淋漓尽致。

总结下JavaScript面向对象的基础:(结合了《Web 2.0 开发技术详解》这本书,希望对大家有帮助)

 

1 定义类

用定义函数的方式(即用“function”关键字定义):

function class01 () { //……. }

此处class01是一个函数,也是一个类。作为函数,可以理解为类的构造函数(初始化)。在JavaScript中,函数和类就是一个概念。

 

BTW:函数声明的方法:

(1)function fun1(…)  {…}

(2)var fun1 = function(…) {…};     // 注意无名函数在调用之前,必需先定义

(3)var fun1 = function fun2(…) {…};

(4)var fun1 = new Function(p1, p2, …, pN, body);

 

2 定义对象

1)使用new操作符。– 适用内部类(如Date类,Array类,String类,RegExp,Math,Error,Object)和用户自定义类。

如:

function class01() { // 类成员的定义 }

var obj = new class01();  // 即所有函数都可以用new来操作。

 

e.g:

var obj = new Object();

obj.name = "ljlwill";               // 定义name属性

obj.hello = function(…) {….}    // 定义obj的hello方法

 

有个小技巧,以下大家发现没有

var namespace = new Object();

var namespace.class1 = function() {…..}

var obj1 = new namespace.class1();

>> 对象名起到一个命名空间的作用。先用new出一个namespace对象,把namespace对象的方法定义为类的形式,再new出一个新的obj1

 

2)使用{}大括号创建无类型对象

传统的面向对象语言中,每个对象都会对应到一个类,而JavaScript中的对象,其实就是属性(方法)的一个集合,无严格意义的类的概念。故可用{}的语法创建一个对象。

如:

var user = { name: "ljwill",        // 定义了name属性,初始化为“ljlwill

hobby: ['basketball', 'football', 'ping-pong'],  // 定义了爱好,类型为数组

// 定义hello方法

hello: function() { alert("Hello, " + this.name); },

…… }

可看到形式,其中属性名和其定义之间用:(冒号)隔开,以,(逗号)结尾。很是紧凑,清晰,减少代码体积。

 

3 对象的属性和方法的引用

1) 对象名.属性名(方法名) — 即用.符号引用

2) 对象名["属性(方法)名"]  — 即用[]符号引用

如:

var arr = new Array(); // 为数组添加一个元素a

arr["push"]("a"); arr.push("a");

// 计算数组长度

var len = arr["length"];

var len = arr.length;

用方括号[]的引用对象属性(方法),类似于数组,体现了一个JavaScript对象就是一组属性(方法)的集合这个性质。适用于不确定具体要引用哪个属性(方法)的场合。 在document的集合对象中,也有类似[]的用法,如果引用某一个“myForm"的表单对象:document.forms["myForm"],当然,也可以写成document.forms.myForm。(注意,这里的forms对象是一个内部对象)

 

4 对象的属性和方法的操作

如何为一个对象添加,修改或删除其属性和方法呢?

在一些语言中,要修改一个已生成的对象的属性或方法,必须在对应的类修改,重新实例化,再重新编译。JavaScript却可以灵活的动态添加,修改或删除其属性和方法。

如:先创建一个空对象user:var user = new Object();

1)添加属性。

user.name = "jinlie";   // 为其添加name属性

user.age   = 25;       // 为其添加age属性

user["name"] = "jinle"   // 使用[]

user["age"]   =  "25"

// 可否发现[]方式有个而外特点, 可以使用非标识符字符串作为属性名称,如数字开头或出现,user["007 name"] = "jinlie",如果user.007 name就错误了。

// 这一属性可以很容易实现一个简单的哈希表。在此不详述。 输出试试:alert(user.name);

 

2)添加方法

user.getName = function() { 

     // 可添加参数 return this.name;

} // alert(user.getName());

 

3)修改属性

即用新的属性替换旧的属性

user.name = "hello"; //  测试:alert(user.getName());

 

4)删除属性和方法

将其置为undefined即可。

user.name = undefined;

user.getName = undefined;

 

到此,我们可以感受JavaScript的强大的灵活性。

 

5 prototype原型对象

在JavaScript中,每个函数(function)其实也是一个对象,他们对应的类是“Function”,而每个函数对象都具有一个子对象prototype。所以,prototype表示了该函数的原型,也即是表示一个类的成员的集合。 prototype是一个对象,也可以对其方法进行动态修改:

如:

function class01 { // ….. }

// 对类的prototype对象增加方法

hello class01.prototype.method = function() { alert("Hello Word!"); }

var obj = new class01();

obj.hello();   // 调用hello()方法

 

看个有趣的例子:

// 为所有的Function函数对象添加method1方法

Function.prototype.method1 = function() {

     alert("This is a function.");

}

function func1() { alert("this is func1"); }

func1.method1();                        // 执行了alert("This is a function")

func1.method1.method1();      // 执行了alert("This is a function")

func1.method1.method1()是个递归定义,因为method1本身也是一个函数,便具有了函数对象的属性和方法,所以它调用了method1这个函数对象的method1方法。结论:所有对Function类型的方法扩充都具有这样的递归性质。

 

6 类成员的访问机制

1)公有成员,私有成员

在JavaScript中,并没有特殊的机制(比如用像一些语言中有关键字private,public等)来访问其成员,但可以通过变量的作用域性质来实现这些功能。– 在一函数内部定义的变量称为局部变量,它不可以被函数外边的程序所使用,却可以被其内部定义的嵌套函数所使用。

有思路了吧?如:

function class1() {

var name = 'ljlwill';      // 私有属性

 

// 私有方法

function privateMethod(…) {

   ….

}

 

// 公有方法

this.pubMethod = function(…) {

    ….

}

}

 

// 建以对象obj

var obj = new class1();

obj.pubMethod();

注意,prototype定义的类成员却不可以访问其构造体中定义的局部变量(私有成员)

 

2)静态成员

它可以通过“class.staticMemberName(类名.静态成员名)”访问。

实现:

function class1() {

     ….

}

calss1.staticName = "ljlwil";

class1.staticMethod = function(…) { …. }

 

如果想给所有的对象添加静态成员(比如静态方法):

Function.prototype.staticMethod = function(…) { … }

 

7 类的继承

继承是OOP中很重要的IDEA。很抱歉,JavaScript没有专门的机制(extends)来实现,但还是可以使用以下方式实现继续

1)拷贝一个类的prototype到另外一个类来实现继承。

如:

function class1() {

   …

}

function class2() {

  ..

}

class2.prototype = class1.prototype;    // 这样class2有了其公有类成员的属性或方法

 

下边的语句是成立的:

var obj = new  class2();

obj instanceof class1;     // intanceof 操作符判断一个对象是否是某一类的实例。

obj instanceof class2;

注意:在JavaScript中,除了基本数据类型(数字,字符串,布尔等),所有的赋值或函数传参都是引用传递,所以class2的prototype引用了class2的prototype,如果改变class2的prototype,class2的prototype也随之改变。所以,注意要不允许类成员的重新定义,用prototype实现继承,还是蛮好用的。

 

2)使用发射机制实现正确继承

发射机制指的是程序在运行时能够获取自身的信息。

如:

// 为Object类添加静态方法extend

Object.extend = function(destination, source) {

for(p in source) {

destination[p] = source[p];

}

return destination;

}

 

// 通过Object类为所有对象添加extend方法

Object.prototype.extend = function(object) {

return Object.extend.apply(this, [this, object]);

}

 

// 定义class1

function class1() {…)

 

class1.prototype = {

method1: function(…) {…},

method2: function(…) {….}

}

 

// 定义class2

function class2() {….}

 

// 继承

class2.prototype = (new class1()).extend({         // 不要把new class1()换成class1,这样和prototype实现继承一样的错误哦!

// 重新定义method1

method1: function() {

    ….

}

}

);

 

// 定义对象

var obj1 = new class1();

var obj2 = new class2();

// 试试吧

obj1.method1();

obj1.method2();

obj2.method1();

obj2.method2();

 

8 抽象类

JavaScript的抽象类也是没任何机制支持的。但却还是可以实现。

传统的面向对象语言中,抽象类的概念是,具有虚函数的类。而虚函数指的是,只做了一个声明而未实现的方法。在JavaScript中,虚函数可以看作该类中没有定义的方法,但已经通过this指针使用了(在其他语言中,虚函数必须先声明)。

如:

Object.extend = function(destination, source) {

for(p in source) {

destination[p] = source[p];

}

return destination;

}

 

// 定义一个抽象基类base,无构造函数
function base() {…}

base.prototype = {

initialize: function() {

this.oninit();     // 调用了一个虚方法

}

 

// 如果要在基类中添加虚方法的一个定义,也可以的:

// oninit: function() {}   // 虚方法是一个空方法,由派生类实现

}

 

function class1() {….}

class1.prototype = (new base()).extend({

// 实现抽象类中的oninit虚方法

oninit: function() {

// 实现

}

});

 

好,今天就谈到这,JavaScript一个非常灵活的设计语言。学好基础,看看那些类的设计模式,和一些出名的框架,不禁要;)一下!