前端開發面試題總結(JS02)

imgres.jpg
  1. 如何控制alert中的換行?
    \n alert(“p\np”);
  2. 請編寫一個JavaScript函數 parseQueryString,它的用途是把URL參數解析為一個對象,如:
    var url = “http://witmax.cn/index.php?key0=0&key1=1&key2=2″;
function parseQueryString(url){
  var params = {},
      arr = url.split("?");
  if (arr.length <= 1)
      return params;
  arr = arr[1].split("&");
  for(var i=0, l=arr.length; i<l; i++){
      var a = arr[i].split("=");
      params[a[0]] = a[1];
  }
  return params;
}
var url = "http://witmax.cn/index.php?key0=0&key1=1&key2=2",
  ps = parseQueryString(url);
console.log(ps["key1"]);
  1. 如何控制網頁在網絡傳輸過程中的數據量?
啟用GZIP壓縮
保持良好的編程習慣,避免重復的CSS,JavaScript代碼,多余的HTML標簽和屬性
  1. 以下代碼運行結果
function say() {
 // Local variable that ends up within closure
 var num = 888;
 var sayAlert = function() { alert(num); }
 num++;
 return sayAlert;
}
var sayAlert = say();
sayAlert();//889
  1. 請實現ECMAScript 5中的Object.getPrototypeOf() 函數
function proto(object) {
  return !object?                null
      : '__proto__' in object?  object.__proto__
      : /* not exposed? */      object.constructor.prototype
}
  1. 如何實現Array.prototype.forEach?
if (!Array.prototype.forEach) {
  Array.prototype.forEach = function(fn){
      for ( var i = 0; i < this.length; i++ ) {
          fn( this[i], i, this );
      }
  };
}
["a", "b", "c"].forEach(function(value, index, array){
  assert( value, "Is in position " + index + " out of " + (array.length - 1) );
});
  1. 如何將arguments轉為數組?
    Object.prototype.slice.call(arguments);
  2. 以下程序運行結果?
var ninja = function myNinja(){
  alert(ninja == myNinja);
};
ninja();
myNinja();
true、報錯(error - myNinja is not defined.)
  1. 如何獲取光標的水平位置?
function getX(e){
  e = e || window.event;
  //先檢查非IE瀏覽器,在檢查IE的位置
  return e.pageX || e.clentX + document.body.scrollLeft;
}
  1. 兼容瀏覽器的獲取指定元素(elem)的樣式屬性(name)的方法
function getStyle(elem, name){
  if(elem.style[name]){//如果屬性存在于style[]中,直接取
      return elem.style[name];
}
else if(elem.currentStyle){//否則 嘗試IE的方法
      return elem.currentStyle[name];
}//嘗試W3C的方式
else if(document.defaultView && document.defaultView.getComputedStyle){ 
      name = name.replace(/([A-Z])/g, "-$1");//W3C中為textAlign樣式,轉為text-align
      name = name.toLowerCase();
      var s = document.defaultView.getComputedStyle(elem, "");
      return s && s.getPropertyValue(name);
  }else{
      return null;
  }
}
  1. Javascript中實現類似PHP的print_r函數
function print_r(theObj) {
  var retStr = '';
   if(typeof theObj == 'object') {
        retStr += '<div style="font-family:Tahoma; font-size:7pt;">';
        for(var p in theObj) {
              if (typeof theObj[p] == 'object') {
                    retStr += '<div><b>['+p+'] => ' + typeof(theObj) + '</b></div>';
                    retStr += '<div style="padding-left:25px;">' +  print_r(theObj[p]) + '</div>';
              } else {
                    retStr += '<div>['+p+'] => <b>' + theObj[p] +  '</b></div>';
              }  
         }
        retStr += '</div>';
    }
    return  retStr;
}
  1. 以下程序運行結果?
var b = parseInt("01");
alert("b="+b);
var c = parseInt("09/08/2009");
alert("c="+c);
b=1、c=0。
  1. 以下程序的運行結果?
var foo = 'hello';
(function() {
     var foo= foo || 'world';
     console.log(foo);
})();
world
  1. 如何規避javascript多人開發函數重名問題?
(1) 可以開發前規定命名規范,根據不同開發人員開發的功能在函數前加前綴
(2) 將每個開發人員的函數封裝到類中,調用的時候就調用類的函數,即使函數重名只要類名不重復就行
  1. 前端開發有哪些優化問題?
減少http請求次數:cssspirit,data uri
JS,CSS源碼壓縮
前端模板JS+數據,減少由于HTML標簽導致的帶寬浪費,前端用變量保存AJAX請求結果,每次操作本地變量,不用請求,減少請求次數
用innerHTML代替DOM操作,減少DOM操作次數,優化javascript性能
用setTimeout來避免頁面失去響應
用hash-table來優化查找
當需要設置的樣式很多時設置className而不是直接操作style
少用全局變量
緩存DOM節點查找的結果
避免使用CSS Expression
圖片預載
避免在頁面的主體布局中使用table,table要等其中的內容完全下載之后才會顯示出來,顯示比div+css布局慢
  1. AJAX請求總共有多少種CALLBACK
Ajax請求總共有八種Callback
onSuccess
onFailure
onUninitialized
onLoading
onLoaded
onInteractive
onComplete
onException
  1. 請給出異步加載js方案,不少于兩種
異步加載方式:
defer,只支持IE
async:
創建script,插入到DOM中,加載完畢后callBack,見代碼:
function loadScript(url, callback){
    var script = document.createElement("script")
    script.type = "text/javascript";
    if(script.readyState){ //IE
        script.onreadystatechange = function(){
             if (script.readyState == "loaded" ||script.readyState == "complete"){
                    script.onreadystatechange = null;
                    callback();
             }
       };
   } else {
//Others: Firefox, Safari, Chrome, and Opera
       script.onload = function(){
          callback();
       };
  }
  script.src = url;
  document.body.appendChild(script);
}
  1. 函數記憶,判斷是不是質數.
方法一:
function isPrime1(n){
    if(n<=3){return true}
    else{
      for(var i=2;i<Math.sqrt(n);i++){
        if(n%i==0){return false;}
      }
      return true;
    }
};
方法二:hash
  var isPrime2=(function(){//hash
    var hash={};
    return function(n){
      if(n<=3){return true}
      else if(hash[n]!==undefined){
        return hash[n];
      }else{
        for(var i=2;i<Math.sqrt(n);i++){
          if(n%i==0){return hash[n]=false}
        }
        return hash[n]=true;
      }
    }
})();
  1. 數組去重
方法一:
var arr1=[1,2,3,2,1,2];
  function repeat1(arr){
    for(var i=0,arr2=[];i<arr.length;i++){
      if(arr2.indexOf(arr[i])==-1){
        arr2.push(arr[i]);
      }
    }//(遍歷結束)
    return arr2;
}
方法二:hash
function repeat2(arr){
    //遍歷arr中每個元素,同時聲明hash
    for(var i=0,hash={};i<arr.length;i++){
     //hash中是否包含當前元素值的建
  //如果不包含,就hash添加一個新元素,以當前元素值為key,value默認為1
      if(hash[arr[i]]===undefined){
        hash[arr[i]]=1;
      }
    }//(遍歷結束)
    //將hash轉為索引:
    var i=0;
    var arr2=[];
    for(arr2[i++] in hash);
    return arr2;
}
方法三:
function repeat3(arr){
    return arr.sort()
             .join(",,")
             .replace(
              /(^|,,)([^,]+)(,,\2)*/g,
              "$1$2")
             .split(",,");
  }
console.log(repeat3(arr1));
  1. 插入排序
var arr=[2,4,1,5,3];
  function insertSort(arr){
    //遍歷arr中每個元素(i從1開始)
    for(var i=1;i<arr.length;i++){
      //將當前元素臨時保存在變量t中
      var t=arr[i];
      var p=i-1;//聲明變量p=i-1
      //循環:(arr[p]>t&&p>=0){
      while(arr[p]>t&&p>=0){
     //將p位置的值,賦值給p+1位置
        arr[p+1]=arr[p];
        p--;//p--
      }//(循環結束)
      arr[p+1]=t;//將t放在p+1的位置上
    }//(循環結束)
  }
  insertSort(arr);
console.log(String(arr));
  1. 快速排序:
 function quickSort(arr){
    //如果arr的length<=1
    if(arr.length<=1){
      return arr;//就直接返回arr
    }
    //計算參照位p
    var p=Math.floor(arr.length/2);
    var left=[];
    var right=[];
    //刪除p位置的元素
    var center=arr.splice(p,1)[0];
    //遍歷arr中每個元素
    for(var i=0;i<arr.length;i++){
      if(arr[i]>=center){
        right.push(arr[i]);
      }else{
        left.push(arr[i]);
      }
    }
    return quickSort(left) .concat(center,quickSort(right))
  }
  var sortedArr=quickSort(arr);
  console.log(String(sortedArr));
  1. 正則表達式
(1) "ryan5 is6 not7 a8 good9 man10"
var n=5;
var str="ryan is not a good man";
str=str.replace(/\b[a-z]+\b/g,function(kw){ return kw+n++;});
console.log(str);
  1. 統計字符串中每種字符出現的次數,出現次數最多的是? 出現?次
 var str="helloworld";
  方法一:用hash
  for(var i=0,hash={};i<str.length;i++){
    if(hash[str[i]]){
      hash[str[i]]++
    }else{
      hash[str[i]]=1;
    }
  }
  console.dir(hash);
方法二:用正則
var arr=str.split("")
  .sort()
  .join("")
  .match(/([a-z])\1*/g)
  .sort(function(a,b){
return b.length-a.length; })
console.log("出現最多的是: "+arr[0][0]
  +"共"+arr[0].length+"次");
var hash={};
  arr.forEach(function(val){
    hash[val[0]]=val.length;
  });
  console.dir(hash);
  1. 數組降維
var arr=[
    [0,0,0,0],
    [0,0,0,0],
    [0,0,0,0],
    [0,0,0,0],
  ];
  //method 1:
  for(var r=0,arr1=[];r<arr.length;r++){
    for(var c=0;c<arr[r].length;c++){
      arr1.push(arr[r][c]);
    }
  }
  console.dir(arr1);
  //method 2: 
  for(var r=0,arr2=[];r<arr.length;r++){
    arr2=arr2.concat(arr[r]);
  }
  console.dir(arr2);
//method 3:
  var arr2=[].concat.apply([],arr);
  console.dir(arr2);
  1. Function賦值
  var f=function(){var a=b=1;}
  f();
  console.log(b);//1
  console.log(a);//報錯
  var f=function(){var a=b=1;}
  setTimeout(f,0);
  console.log(b);//報錯
  f();
  var a,b=0, fn=function(){var a=b=2;}
  fn();
  console.log(a);//undefined
  console.log(b);//2
  1. 函數currying(柯里華)
  var getN;
  function add(n){
    getN=function(){console.log(n);}
    return function(m){
      n+=m;
    arguments.callee.toString=function(){
        return n;
      }
      return arguments.callee;
    }
  }
  add(1)(2)(3); getN();//6
  add(1)(2)(3)(4); getN();//10
  alert(add(1)(2)(3));//6
  alert(add(1)(2)(3)(4));//10
  1. 遞歸
var emp={
 work:function(){//3,2,1
  var  sum=0;//+3+2+1 +2+1  +1
  for(vari=0; i<arguments.length&&arguments[0]>0;
        i++){
        sum+=arguments[i]
            +arguments.callee(
              --arguments[i]
            );
      }
      return sum;
    }
  }
  console.log(emp.work(3,2,1));//10
  1. 閉包
(1)function fun(n,o){//外層函數
    console.log(o);
    return {
      fun:function(m){//內層函數 n
        return fun(m,n);
      }
    }
  }
  var a=fun(0);a.fun(1); a.fun(2); a.fun(3);
   //undefined  0      0       0
var a=fun(0).fun(1).fun(2).fun(3);
//undefined   0    1    2
var a=fun(0).fun(1); a.fun(2); a.fun(3);
//undefined  0       1      1
(2)var a=0,b=0;
  function A(a){
    A=function(b){alert(a+b++)};
    alert(a);
  }
  A(1);//1
  A(12);//13
  1. OOP
(1)
window.a=300;
  function fn1(){
    this.a=100;
    this.b=200;
    return function(){
              alert(this.a)
            }.call(arguments[0])
  }
  function fn2(){ this.a=new fn1(); }
var a=new fn1().b;//300
var v=new fn1(fn2());//[object Object]
(2)
var number=2;//4  8
  var obj={
    number:4,//8
    fn1:(function(){
      //var number;
      this.number*=2;
number*=2; //聲明提前  undefined
      var number=3;
      return function(){
        this.number*=2;
        number*=3;
        alert(number);
      }
    })()
  }
  var fn1=obj.fn1;
  alert(number); fn1(); obj.fn1(); 
  //4           9      27
  alert(window.number);//8
  alert(obj.number);//8
(3)
function Foo(){
  getName=function(){alert(1);};
    return this;
}
Foo.getName=function(){alert(2);};
Foo.prototype.getName=function(){
  alert(3);
};
var getName=function(){alert(4);};
function getName(){ alert(5); };
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
new new Foo().getName();//3
(4)
var a=1;
var b={
  a:2,
  b:function(){
    console.log(this.a);//1
  }(), 
  f:this.f=function(){
    console.log(this.a);
  }
};
function f(){ console.log(3); }
f();//1
b.f();//2
(b.f)();//2
(0,b.f)();//1
(5)
var foo=function(){
  console.log(this.a);
}
var obj={a:2,foo:foo};
var a=10;
var bar=obj.foo;
var bar2=foo.bind(obj);
bar();//10
bar2();//2
foo();//10
obj.foo();//2
setTimeout(bar,0);//10
(6)
function MyObj(){ 
  this.p.pid++; 
}
MyObj.prototype.p={"pid":0}//2
MyObj.prototype.getNum=function(num){
  return this.p.pid+num;
}
var _obj1=new MyObj(); //創建新對象,繼承原型pid+1
var _obj2=new MyObj(); //創建新對象,繼承原型pid+2
console.log(
  _obj1.getNum(1)+_obj2.getNum(2)
);//7      2+1   +    2+2
  1. 判斷一個對象是不是數組類型,有五種方法:
(1) typeof 無法判斷 只能判斷原始類型的值和函數
(2)isPrototypeOf 判斷父及對象   可檢查整個原型鏈 //可能繼承自數組
  console.log(Array.prototype.isPrototypeOf([])?"是數組":"不是數組");
  console.log(Array.prototype.isPrototypeOf({})?"是數組":"不是數組");
  console.log(Array.prototype.isPrototypeOf(function(){})?"是數組":"不是數組");?
(3)constructor 檢查指定對象的構造函數 可檢查整個原型鏈  //可能繼承自數組
  var father={};
  var son={};
  father.__proto__=Array.prototype;
  son.__proto__=father;
  console.log(son.contructor==Array?"是數組":"不是數組")
  console.log({}.contructor==Array?"是數組":"不是數組");
  console.log(function(){}.contructor==Array?"是數組":"不是數組");?
(4)instanceof 檢查一個對象是否是制定構造函數的實例 可檢查整個原型鏈 //可能繼承自數組
  var father={};
  var son={};
  father.__proto__=Array.prototype;
  son.__proto__=father;
  console.log(son instanceof Array?"是數組":"不是數組");
  console.log({} instanceof Array?"是數組":"不是數組");
  console.log(function(){} instanceof Array?"是數組":"不是數組");
(5)強行用要檢查的對象,調用原始的toString方法  不檢查整個原型鏈
      //[object class]: class-Array Date Object
      //只能檢查最初就是數組創建的對象。
      console.log(Object.prototype.toString.call([])=="[object Array]"?"是數組":"不是數組");
      console.log(Object.prototype.toString.call({}));
      console.log(Object.prototype.toString.call(function(){}));
      console.log(Object.prototype.toString.call(/\d/));
      var father={};
       var son={};
       father.__proto__=Array.prototype;
       son.__proto__=father;
      console.log(Object.prototype.toString.call(son)=="[object Array]"?"是數組":"不是數組");//不是
      //結論: 對象一旦創建,class屬性就無法修改
             //修改繼承關系,也無法修改class屬性
(6) Array.isArray(obj)  不檢查整個原型鏈
      console.log(Array.isArray([]));
      console.log(Array.isArray({}));
  //如果瀏覽器不支持isArray
  if(Array.prototype.isArray===undefined){//if(!Array.isArray)
      //給?添加isArray方法
      Array.prototype.isArray=function(arg){
          //強行調用原始toString方法,和"[object Array]"比較
          return Object.prototype.toString.call(arg)
          =="[object Array]"?"是數組":"不是數組";
      }
  }
  1. 自定義Object.create()——手寫
Object.create=function(father,props){
      console.log("我的create");
      /*使用setPrototypeOf方法
      var o=Object();//1. 創建空對象
      Object.setPrototypeOf(o,father);//2. 繼承father
      */
      /*不使用setPrototypeOf方法
      function Constructor(){}
      Constructor.prototype=father;
      var o=new Constructor();
      */
      Object.defineProperties(o,props);//3. 定義新屬性
      return o;
  }
  1. 深克隆原理
Object.clone=function(obj){//深克隆
if(typeof(obj)=="object"){//如果obj是對象
  var o=//有必要區分數組和普通對象
  Object.prototype.toString.call(obj)=="[object Array]"?[]:{};
      for(var key in obj){//遍歷obj的自有屬性
          //如果key是obj的自有屬性
          if(obj.hasOwnProperty(key)){
              o[key]=arguments.callee(obj[key]);//arguments.callee調的是當前的Object.clone函數
              }
      }
      return o;
      }else{//如果obj是原始類型的值,就直接返回副本
          return obj;
      }
  }
  1. 如果瀏覽器不支持every屬性,every的實現原理
  if(Array.prototype.every===undefined){
     Array.prototype.every=function(fun){
      //遍歷當前數組中每個元素
      for(var i=0;i<this.length;i++){
          if(this[i]!==undefined){
//調用fun,依次傳入當前元素值,位置i,當前數組作為參數  ,將返回值,保存在變量r中
          var r=fun(this[i],i,this);
          if(r==false){//如果r為false
             return false;//返回false
          }
          }
           }//(遍歷結束)
       return true;//返回true
     }
  }
  1. 如果瀏覽器不支持some屬性,some的實現原理
 if(Array.prototype.some===undefined){
     Array.prototype.some=function(fun){
        for(var i=0;i<this.length;i++){
        if(this[i]!==unefined){
          var r=fun(this[i],i,this);
              if(r==true){ return true; }
                }
            }
        return false;
     }    
  }
  1. 瀏覽器不支持map屬性,map的實現原理
 if(Array.prototype.map===undefined){
     Array.prototype.map=function(fun){
      //創建空數組: newArr
      var newArr=[];
      //遍歷當前數組中每個元素
      for(var i=0;i<this.length;i++){
         //如果當前元素不是undefined
         if(this[i]!==undefined){//判斷稀疏數組
//調用fun傳入當前元素值,位置i,當前數組,將結果保存在r中
              //將newArr的i位置賦值為r
          var r=fun(this[i],i,this);
                  newArr[i]=r;
         }
      }//(遍歷結束)
      return newArr;//返回newArr
     }
  }
  1. 如果瀏覽器不支持reduce屬性,reduce的實現原理
  if(Array.prototype.reduce===undefined){
     Array.prototype.reduce=function(fun,base){
       base===undefined&&(base=0);
       for(var i=0;i<this.length;i++){
      if(this[i]!==undefined){
         base=fun(base,this[i],i,this);
      }
           }
       return base;
         }
  }
  1. 如果瀏覽器不支持bind屬性, bind函數的實現原理
    if(Function.prototype.bind===undefined){
     Function.prototype.bind=function(obj/*,參數列表*/){
      var fun=this;//留住this
              //*****將類數組對象,轉化為普通數組
      var args=Array.prototype.slice.call(arguments,1);
      //args保存的就是提前綁定的參數列表
      /*function slice(1){
         var sub=[];
         for(var i=0;i<length;i++){
          sub.push(arguments[i]);
         }
         return sub;
      }*/
      return function(){
                 //將后傳入的參數值,轉為普通數組      
         var innerArgs=Array.prototype.slice.call(arguments);//將之前綁定的參數值和新傳入的參數值,拼接為完整參數之列表
         var allArgs=args.concat(innerArgs)
        //調用原始函數fun,替換this為obj,傳入所有參數
        fun.apply(obj,allArgs);
      }
     }
  }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容