你的位置:首页 > Java教程

[Java教程]网易面试的幸福两小时


  面试中,面试老师耐心讲解每一道题,让自己也深刻认识到,怎样才算是一个合格的程序员,让别人用着你的代码会很放心。“写代码犹如做人。”很受教,特此与大家一同分享。最深感触,就是代码的严谨性。之前总认为有些JS的小细节不重要,就不往心里记,但最终落实到代码的执行上,则是致命性的。

   知识总结:

  一、if条件判断方法小结

  1,在javascript中,哪些值能作为if的条件呢?

      1)布尔变量true/false;
    2)数字非0,非NaN/ (0 或NaN);

    3)对象非null/(null或undefined) 
    4)字符串非空串(“”)/空串("")

        对于字符串,不用写一大堆if(str!=null && str!=undefined && str !=''), 只要用一句  if(!str){  //do something  } 

    5)对于数字的非空判断,则要考虑使用isNaN()函数,NaN不和任何类型数据相等,包括它本身,只能用isNaN()判断。对于数字类型,if(a)语句中的a为0时if(a)为假,非0时if(a)为真;

   2.关于if语句优化的方法 if简写

1 if (foo) bar(); else baz(); ==> foo?bar():baz();2 if (!foo) bar(); else baz(); ==> foo?baz():bar();3 if (foo) return bar(); else return baz(); ==> return foo?bar():baz();

     3.使用and(&&)和or(||)运算符

1 if (foo) bar(); ==> foo&&bar();2 if (!foo) bar(); ==> foo||bar();

   4.if(x==null)简写

if(x==null)或if (typeof (x) == 'undefined')可以简写为if(!x),未验证。反之if(x)表示x非空  

    5.有关NaN的知识点太碎,大家可以访问链接  http://ourjs.com/detail/5383eb8f7610019548000012 

     二、关于事件对象与事件冒泡

   1、事件对象:  js的事件对象中保存了当前被触发事件的一些相关的属性信息,如事件源、事件发生时的鼠标位置、事件按键等。

    兼容写法: function(e) { var event = window.event || e; } 

 

    2、事件源: 事件源即事件发生所在的元素(是最里层元素),在IE中用event.srcElement获取,在Firefox中用event.target获取。

    兼容写法: var targetObj = event.srcElement || event.target; 

   3、事件冒泡:在默认情况下,发生在一个子元素上的单击事件(或者其他事件),如果在其父级元素绑定了一个同样的事件,此时点击子元素,click事件会首先被子元素捕获,执行绑定的事件程序,之后会被父级元素捕获,再次激发一段脚本的执行,这就是所谓的“事件冒泡”。

      但有的时候,在一个子元素上处理完单击事件后,不想触发其父元素的相同事件,则需要阻止冒泡的发生。

    兼容写法: if (event.stopPropagation) { event.stopPropagation(); } else { event.cancelBubble = true; }  

  4.W3C模型

       W3C模型是将两者进行中和,在W3C模型中,任何事件发生时,先从顶层开始进行事件捕获,直到事件触发到达了事件源元素。然后,再从事件源往上进行事件冒泡,直到到达document。

  程序员可以自己选择绑定事件时采用事件捕获还是事件冒泡,方法就是绑定事件时通过addEventListener函数,它有三个参数,第三个参数若是true,则表示采用事件捕获,若是false,则表示采用事件冒泡。

  ele.addEventListener('click',doSomething2,true)

  true=捕获

  false=冒泡

  5.所以,类似链接上的focus或blur事件仅发生于链接自身上,而它的任何父节点上的事件都不会产生,所有不会冒泡,表单事件也不会冒泡。

 

  三、本地存储与cookie

  1.我们之前总认为cookie不能跨域访问,其实不然。通过查文档:淘宝就是这么做的。

    1)淘宝跨域获取cookie:访问地址  http://developer.51cto.com/art/201104/255729.html

    2)sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此                sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。

    3)HTML5的本地存储是兼容IE8以上,这个我知道的,为啥当时没选对呢?

  总结:有关更多本地存储,可以访问链接,介绍与使用方法都介绍特别好:http://blog.csdn.net/fdipzone/article/details/25517615/

  

  四、作用域问题 

 1 var User = { 2   count: 1, 3   getCount: function() { 4     return this.count; 5   } 6 }; 7 console.log(User.getCount());   8 var func = User.getCount; 9 console.log(func()); 10 VM2467:7 111 VM2467:9 undefined12 undefined

 

  这里涉及到两个知识点:

  1.一般我们都习惯了直接使用  User.getCount()调用;这时的调用者是User,this指向User;

  但现在是 var func = User.getCount; 这时func是在winodw的上下文中被执行的,return中的this指向是window,所以会访问不到count属性。

  2.如果这里想要访问到count属性怎么办?这时bind方法就很有用了,可以改变this的不同指向。将func改写成这样: var func = User.getCount.bind(User); 

  就可以将this指向转向User。 有关JavaScript 中的 Function.prototype.bind方法可以访问网址,写的特别好:http://blog.jobbole.com/58032/

 

 

  

  五、freeMaker,之前没有认识过

    1.获取服务器时间,因为使用JS:freemarker是个模板引擎,她的作用是用来解析你定制的模板,结构是模板加商数据,将数据放入Map中,在ftl模板中来用${name} 来取当中的值,你想在页面获得系统时间,你可以在map中加入一个entry ,key是sysTime,value是new Date(), 然后在页面中用${sysTime?String("yyyy-MM-dd")}来进行系统时间的获得; 

     2.使用特殊变量 .now ,如:Today is ${.now?date}

    总结:有关freeMaker完全陌生,需要抽时间好好看一下。这个网址是freeMaker是使用:http://www.mamicode.com/info-detail-506871.html

 

  六、移动端开发遇到的问题

    移动端问题有很多,另辟空间,好好说道说道。

  七、原型与数据转换(自我总结)

  1.继承:子类继承父类,且不影响父类,也是一种代码复用的方法;

               function Person(name,age) = { this.name = "haha";this.age = "18' };  Person.prototype.show () = { alert(this.name)};
        
              【a:属性的继承;使用call】 这时想要Student想要继承父类的name与age属性;一种想法是:直接使用Person()调用的方法放在函数体内,但这时有个this指向的            问题, 直接调用Person()是在全局调用,这时this指向是window,而我们是想让它指向Student实例化的对象,所以不能直接使用调用Person的方法。
           function Student() = {this.job = "study"; }     【  这时call的意义就出现了,直接使用Person.call( this,name,age ); call将this指向指向了Student;
               【b:原型方法上的继承,使用extend =》for in 拷贝方法 】    因为直接使用原型赋值, 即Student.prototype = Person.prototype,这样可以使子类继承父类。但            这样做,就相当于把原型上的地址告诉了子类,子类做任何修改都会影响到父类,所以对象间的继承不能通过直接赋值的方式。 这时就想到使用值类型的赋值就不                      会改变地址值,只是赋值给了另一个值类型指向地址的指针而已。这时通过for in遍历对象里a的属性或方法赋值给 b[attr] = a[attr]的方式。这时封装函数extend =                  function(b,a){ b[arrt] = a[attr]; } ; 调用时 extend( Student.prototype = Person.prototype; ) 就可以完成继承。 【思考:函数赋值,不也是引用类赋值,              如此赋值不会修改地址内容么? 对象可以赋值,但不可以被修改,比如 var a = [ 1, 2, 3]; var b = a ; b.push(4); 这时 a = [ 1,2,3,4 ]; 因为b.push()是修改动作,            但如果直接写成  b = [ 1,2,3,4 ]; 则a还是等于 [1,2,3],没有发生变化,因为 [ 1,2,3,4 ]是直接赋值,已经与a没有关系了,现在b已经不是指向a所在地址区域了 。】
 
      2.类式继承:使用构造函数(类)继承的方式,JS中没有类这个概念,就看成是构造函数就好:
      有父类Aaa,子类Bbb,直接 Bbb.prototype = new Aaa(),就实现了类式继承,但这里存在一个问题,因为链一直连着,子类做任何修改,都会影响到父类,直接这样做有问题。解决方法:
  【继承方法:var F = function(){};  F.prototype = Aaa.prototype;  Bbb.prototype = new F();Bbb.prototype.constructor = Bbb; //修正指向问题】
  【继承属性: Aaa.call(this); 】
 
 1 //类 : JS是没有类的概念的 , 把JS中的构造函数看做的类 2  3 //要做属性和方法继承的时候,要分开继承 4  5 function Aaa(){ //父类 6 this.name = [1,2,3]; 7 } 8 Aaa.prototype.showName = function(){ 9 alert( this.name );10 };11 12 function Bbb(){ //子类13 14 Aaa.call(this);15 16 }17 18 var F = function(){};19 F.prototype = Aaa.prototype;20 Bbb.prototype = new F();21 Bbb.prototype.constructor = Bbb; //修正指向问题22 23 var b1 = new Bbb();24 //b1.showName();25 //alert( b1.name );26 //alert( b1.constructor );27 b1.name.push(4);28 29 var b2 = new Bbb();30 31 alert( b2.name );




 
3.原型继承:                                
 
 1 var a = { 2 name : '小明' 3 }; 4  5 var b = cloneObj(a); 6  7 b.name = '小强'; 8  9 //alert( b.name );10 alert( a.name );11 12 function cloneObj(obj){13 14 var F = function(){};15 16 F.prototype = obj;17 18 return new F();19 20 }


 
 
拷贝继承: 通用型的 有new或无new的时候都可以
 
类式继承: new构造函数
 
原型继承: 无new的对象


 

4.判断类型:1)typeof; 
                      2)Object.prototype.toString.call (arr);
                      3)hasOwnProperty(),看是不是自身上面的属性,原型上的不算; 
                         var arr = [] ;arr.num = 10; arr.prototype.num1 = 20; 这里 arr.hasOwnPrototype('num') == true;  arr.hasOwnPrototype('num1') == false;
                      4)constructor(), 检查对象的构造函数。可以更改。
                          function Aaa( )= {};   Aaa.prototype.name = 'haha'; Aaa.prototype.age = 18;  var a1 = new Aaa(); console.log(a1.construtor);  
                                     【构造函数是Aaa】
                                                     Aaa.prototype = { name = 'haha', age = 18};  var a2 = new Aaa();  console.log(a2.constructor); 【构造函数是Object】
                                                        因为a1中的写法是直接给Aaa原型上赋值,  而a2中的写法是将一个Json对象赋值给了Aaa的原型,那这时就改变了
                                                        构造函数的指向。 在JQuery中也一样,需要手动在原型上写constructor : Aaa, 如此才可以重新指向原来构造函数。这是极容易
                                                        出现错误的地方。  【在每个函数中,都会自懂生成这个函数 Aaa.prototype.constructor = Aaa;】                                         
                      5)for in ,系统自带的属性是找不到的,例如constructor自己写也找不到;
                      6)instanceof  指对象与构造函数在原型链上是否有关系;  alert (a1 instanceof Array);
                      7) toString() Object上面的方法,是将对象转换成字符串;
                                例如:var a1 = new Aa(); a1.toString == Object.prototype.toString;   【true】
                                            var arr = [];    arr.toString == Object.prototype.toString;  【false】
                           这里就出现了一个区别:就是这个toString方法,系统内置对象都是自带的toString方法,而自己创建出来的对象使用的toString方法是通过 原型链查找                               的。所以虽然名字都是toString,但自己都有自己的方法,搜索机制不同。
                                【这也是引申出。使用toString方法可以精确判断数据类型:Object.prototype.toString.call (arr);】