JSCORE面試題彙總(一)

第一題

 function fun(){
    for(var i=0,arr=[];i<3;i++){
      arr[i]=function(){
		console.log(i)
	  }
	}
	return arr;
  }
  var funs=fun();
  funs[0]();//3
  funs[1]();//3
  funs[2]();//3

第二題
去掉數組中非數字字符,並給每個數字加+1
var arr=[1,2,3,“a”,4,“b”]

for(var i=arr.length-1;i>=0;i--){
     if(typeof arr[i]==="number"){
           arr[i]++ ;
      }else{
          arr.splice(i,1);
      }
}

第三題
在兩個排好序的數組中,高效率的找出相同的元素,放入新數組
var arr1=[1,3,7,9,12,37,45]
var arr2=[2,4,9,13,45,88,92]

for(var i=0,j=0,arr=[];i<arr1.length&&j<arr2.length;){

            if(arr1[i]>arr2[j]){
                    j++;
            }else if(arr1[i]<arr2[j]){
                i++;
            }else{
                arr.push(arr1[i]);
                i++;
                j++;
            }
        }

第四題
找出一個排好序的數組中,兩個元素相加和爲19的元素組合,考慮程序的執行效率
var arr=[1,2,4,6,7,11,12,15,17]

for(var i=0,j=arr.length-1;i<j;){
    if(arr[i]+arr[j]<19){
        i++;
    }else if(arr[i]+arr[j]>19){
        j--;
    }else{
       console.log(`${arr[i]}+${arr[j]}`);
        i++;
        j--;
    }
}

第五題
統計一個字符串中每種字符出現的次數?出現次數最多的是哪個字?共出現幾次

for(var i=0,arr=[];i<str.length;i++){
      var char=str[i];
      if(arr[char]===undefined){
         arr[char]=1
      }else{
         arr[char]++;
      }
}
/* 這種方法也可以
var res=str.split("").reduce(function(prev,elem){
   if(prev[elem]!==undefined){
       prev[elem]++
   }else{
       prev[elem]=1;
   }
   return prev;
},{})
console.log(res);
*/
var maxChar,count=0;
for(var key in arr){
    if(arr[key]>count){
        maxChar=key;
        count=arr[key];
    }
}

第六題
[]-[], []+[] 分別輸出多少

  • 法計算永遠試圖將左右兩邊的值都轉爲數字,因爲只有數字可以做減法。所以,自動調用Number()
    Number([]) = 0 記住。
    []-[]等於0, []-1等於-1
    + 法則完全不同。兩個對象相加,會自動調用兩個對象的toString方法,將兩個對象轉爲字符串,然後執行字符串拼接。
    [].toStirng() = “”,因爲數組沒有值,所以轉爲空字符串
    []+[],等於""+"",返回""
    [1,2,3]+[4,5,6], 等於"1,2,3"+“4,5,6” 結果:
    “1,2,34,5,6”

第七題

function fun(o){
    o.name="西西";
    o={};
    o.name="小麗";
}
var obj={name:"小紅",age:11};
fun(obj);
console.log(obj);
> {name: "西西", age: 11}

第八題

深克隆

function clone(obj){
   var newObj={};
   
   if(obj==null){
      return null;
   }else if({}.toString.call(obj)==="[object Array]"){
       var newArr=[];
       newArr=obj.slice();
       return newArr;
   }
   
   for(var key in obj){
      if(typeof obj[key]!=="object")//typeof null 也是object
      {
         newObj[key]=obj[key];
      }else{
         newObj[key]=clone(obj[key]);
      }
   }
   
   return newObj;
}

第九題

function fun(){//媽媽
  var n=999;//紅包
  //共生了幾個孩子?
  nAdd=function(){n++};//剖腹產
  //js中一個特徵: 任何情況下給一個從未聲明過的變量賦值,不會報錯!而是自動在全局創建該變量!
  return function(){//順產
    console.log(n)
  }
}
var getN=fun();//媽媽生了一次孩子,包了一個紅包
//getN:function(){console.log(n)}
getN();//999
nAdd();
getN();//1000

第十題

// var a=10;
// function fun(){
//   var a=100;
//   a+=1;
//   console.log(a)
// }
// fun();//101
// console.log(a);//10

// var a=10;
// function fun(){
//   a=100;
//   a+=1;
//   console.log(a)
// }
// fun();//101
// console.log(a);//101

var a=10;
function fun(a){//局部變量
/**只要函數自己有a,則內部一切操作與全局無關***/
  a=100;
  a+=1;
  console.log(a)
/******************************************/
}
fun(a);//101
console.log(a);//10

第十一題

function ltrim(str){
  return str.replace(/^\s+/,"")
}
function rtrim(str){
  return str.replace(/\s+$/,"")
}
function trim(str){
  return str.replace(/^\s+|\s+$/g,"")
}

第十二題

function fun(){console.log(1)};
fun();//2
function fun(){console.log(2)};
fun();//2
var fun=100;
fun();//報錯
> 2
> 2
>Uncaught TypeError: fun is not a function
    at <anonymous>:6:1

第十三題
內置對象11種
String Boolean Number
Math Date RegExp Array
Function Error Object
Global

第十四題
如何知道現在的瀏覽器中該類型下都有哪些可用的函數?
所有類型的函數列表都保存在原型對象中:
比如: Array.prototype下包含着目前數組對象可用的所有函數
String.prototype 下包含着目前字符串對象可用的所有函數

第十五題
如果經常使用的一個函數,在原形對象中沒有,而我們又想讓所有的孩子都能用上這個函數:
自己定義該函數,並強行放入原型對象中!
比如: 經常對數組求和,但是數組暫時沒有求和的函數sum
Array.prototype.sum=function(){
… …
}
將來: arr1.sum() arr2.sum() … …
強調: 運行對象方法中應該用this指向將來調用該函數的.前的當前類型的子對象。
比如:
Array.prototype.sum=function(){
console.log(“調用了一次自己的sum函數”);
var sum=0;
for(var i=0;i<this.length;i++){
sum+=this[i]
}
return sum;
}
var arr1=[1,2,3];
var arr2=[1,2,3,4,5];
var arr3=[1,2,3,4,5,6,7];
console.log(
arr1.sum(),
arr2.sum(),
arr3.sum()
)

第十六題
自有屬性和共有屬性:
(1). 自有屬性: 直接保存在當前對象內部,僅歸當前對象自己所有的屬性
(2). 共有屬性: 保存在原型對象中,所有子對象共有的屬性
(3). 獲取屬性值: 二者沒有差別,都可用子對象打.訪問
子對象.屬性名
程序會優先在當前對象內部先找自有屬性。如果沒有想要的自有屬性,纔去父對象中查找
(4). 修改屬性值:
a. 自有屬性可用用子對象直接修改:
lilei.sage=26
b. 共有屬性不能用子對象修改,必須用原型對象本身來修改
構造函數.prototype.共有屬性=值
比如: Student.prototype.className=“初二2班”
如果強行用子對象修改共有屬性,不會報錯,而是給這個子對象悄悄添加一個自有同名屬性。從此,這個子對象,在這個屬性的使用上和其它子對象分道揚鑣

第十七題
總結: this 目前4種用法:

  1. obj.fun() this->obj
  2. fun() this->window
  3. new Fun() this->new(正在創建的新對象)
  4. Array.prototype.sum=function(){ this }
    arr1.sum() this->arr1
    arr2.sum() this->arr2

第十八題

function Foo(){
   Foo.a=function(){
      console.log(1);
   }

   this.a=function(){
      console.log(2);
   }
}

Foo.prototype.a=function(){
   console.log(3);
}

Foo.a=function(){
   console.log(4)   
}

Foo.a();
let obj=new Foo();
obj.a();
Foo.a();
> 4
> 2
> 1

第十九題

var x=0;
var foo={
   x:1,
   bar:function(){
      console.log(this.x);
      var that=this;
      return function(){
          console.log(this.x);
          console.log(that.x);
      }
   }
}

foo.bar();
foo.bar()();
> 1
> 1
> 0
> 1

第二十題

function fun(n,o){
   console.log(o);
   return {
     fun:function(m){
         return fun(m,n)
     }
   }
}
var a=fun(0);
    a.fun(1);
    a.fun(2);
    a.fun(3);

> undefined
> 0
> 0
> 0
var b=fun(0)
      .fun(1)
      .fun(2)
      .fun(3);
> undefined
> 0
> 1
> 2
var c=fun(0).fun(1);
    c.fun(2);
    c.fun(3);
> undefined
> 0
> 1
> 1

第二十一題

function A(){

}

function B(){
   return new A();
}

A.prototype=new A();
B.prototype=new B();
var a=new A();
var b=new B();
console.log(a.__proto__==b.__proto__);

在這裏插入圖片描述
第二十二題

function Foo(){
    getName=function(){
       console.log(1);
    }
    return this;
}
Foo.getName=function(){
    console.log(2);
}
Foo.prototype.getName=function(){
   console.log(3);
}
var getName=function(){
   console.log(4);
}
function getName(){
    console.log(5);
}
Foo.getName();//2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName(); //2
new Foo().getName();//3
new new Foo().getName();//3

在這裏插入圖片描述
第二十三題
判斷一個對象是不是數組類型,一共有幾種方法:

//不正確的方法:typeof
var n=10,str='hello',b=true,nu=null,un;
var f=function(){};
var obj1={},obj2=[1,2,3],obj3=new Date();
console.log(
   typeof(n),//number
   typeof(str),//string
   typeof(b),//boolean
   typeof(nu),//object
   typeof(un),//undefined
   typeof(f),//function
   typeof(obj1),//object
   typeof(obj2),//object
   typeof(obj3)//object
)

//判斷爹:3種
//1.用__proto__獲得對象的爹,然後再和數組的爹做比較
console.log(
  obj1.__proto__==Array.prototype,//false
  obj2.__proto__==Array.prototype,//true
  obj3.__proto__==Array.prototype //false
)
//2.因爲__proto__可能被瀏覽器禁用,所以有等效的函數來完成__proto__的任務:Object.getPrototypeOf(child)
console.log(
  Object.getPrototypeOf(obj1)==Array.prototype,//false
  Object.getPrototypeOf(obj2)==Array.prototype,//true
  Object.getPrototypeOf(obj3)==Array.prototype//false
)
//3.還有一個更直接的函數:father.isPrototypeOf(child)
console.log(
   Array.prototype.isPrototypeOf(obj1),//false
   Array.prototype.isPrototypeOf(obj2),//true
   Array.prototype.isPrototypeOf(obj3)//false
)


//判斷媽媽
//4.用父級原型對象中的constructor屬性
console.log(
   obj1.constructor==Array,//false
   obj2.constructor==Array,//true
   obj3.constructor==Array//false
)
//用"child instanceof 媽媽"
console.log(
  obj1 instanceof Array,//false
  obj2 instanceof Array,//true
  obj3 instanceof Array//false
)
//當obj1.__proto__=Array.prototype時,以上的判斷方法均失效

//輸出對象中的DNA:內部隱藏屬性class
//.call()可讓任意一個對象,搶到原本不屬於它的任何一個函數
console.log(Object.prototype.toString.call(obj1)==="[object Array]");//false
console.log(Object.prototype.toString.call(obj2)==="[object Array]");//true
console.log(Object.prototype.toString.call(obj3)==="[object Array]");//false

//ES5中新增了一個專門判斷一個對象是不是數組的函數:Array.isArray(obj)>bool
console.log(
   Array.isArray(obj1),//false
   Array.isArray(obj2),//true
   Array.isArray(obj3)//false
)

第二十四題

var number=2;
var obj={
   number:4,
   fn1:(function(){
	     this.number*=2;
	     number*=2;
	     var number=3;
	     return function(){
	         this.number*=2;
	         number*=3;
	         console.log(number)
	      }
    })()

}
var fn1=obj.fn1;
console.log(number);//4
fn1();//9
obj.fn1();//9
console.log(number);//8
console.log(obj.number);//16

在這裏插入圖片描述
第二十五題

console.log(window.a)輸出undefined,而console.log(a),就報錯,難道window.a是全局,a就不是全局?
答:所有全局變量一定是保存在window中的
保存在window中的變量其實有兩種訪問方式:
可以以變量語法方式: 變量名
可以以window對象的成員形式使用: window.變量
比如: var a=10;
console.log(a) //10
因爲所有沒有前綴的,js都會自動加上window.前綴——僅限於全局作用域中執行的程序
比如: alert() -> 執行時被補全爲window.alert()
再比如: parseInt() -> 執行時被補全爲window.parseInt()
console.log(window.a) //10
如果沒有聲明a,執行console.log(a)和console.log(window.a),一個報錯,一個不報錯?
語法規定:
如果直接訪問一個不存在的變量,會報錯!ReferenceError: a未定義
如果強行訪問對象中一個不存在的屬性,或訪問數組中一個不存在的位置,不報錯!而是返回undefined。
全局變量a,其實都有兩個角色,一個是單純的變量a,同時也是window對象中的成員。所以,以單獨變量方式訪問不存在的變量,則參考第一條規則,會報錯。如果以window.a成員的方式訪問變量a,永遠不會報錯!而是返回undefined。
補: var a和 window.a
1. 如果未聲明變量a,則單獨使用a會報錯,而使用window.a不報錯。
2. var a的變量不能用delete徹底刪除
而用window.a強行添加的變量,才能被delete徹底刪除
總結: 今後即使用全局變量,也要用window.變量。不要用var。因爲如果不想用了,還可以用delete徹底刪除。

第二十六題
pay=null後,爲什麼變量pay還在?
答: 給pay變量賦值爲null,只是清空變量的內容,而變量在window中不會被刪除。
如果希望徹底刪除變量: delete window.變量
但是: 刪除不掉!
原因: pay是var pay創建的。如果想用delete徹底刪除變量,創建變量時,必須用window.pay

第二十七題

   console.log(a) //報錯,爲什麼不是undefine?
   a=10;
   console.log(a)
   //因爲a=10前,沒有var。沒有var,就不是聲明語法,就不會會被聲明提前。不會被聲明提前,第一次使用時就沒有a可用,就報錯。a=10,只是一個賦值語句。賦值語句會強行創建變量a,但是,也只能在語句所在位置才創建a。因爲聲明提前規定,“”賦值留在原地“

第二十八題

爲什麼加入overflow:hidden或添加元素設置爲display:table,可防止高度坍塌?BFC?
答: Block Formatting Context
以塊的形式,格式化顯示元素的子內容
爲什麼: 啓用BFC模式都是爲了避免子元素被隱藏或遮擋。
如何啓用BFC:
浮動元素:float 除 none 以外的值。
絕對定位元素:position (absolute、fixed)。
display 爲 inline-block、table-cells、flex。
overflow 除了 visible 以外的值 (hidden、auto、scroll)
後果:
1. 父元素啓用BFC,則範圍必須包含所有子元素的範圍。
2. 平級子元素啓用BFC,則其他兄弟子元素不能覆蓋在它之上。

第二十九題

var tom='tom';
tom.money=100;
//new String(tom).money=100;
//調用後自動釋放
console.log(tom.money);//undefined
//new String(tom).money

var tom=new String("tom");
tom.monry=10;
console.log(tom.money);//10

第三十題
閉包的外層函數向外拋出內層函數共有幾種方式?

答: 3種:
1. return function(){ … }
2. 全局變量=function(){ … }
3. return [ function, …]
return { 方法: function(){ … } }

第三十一題
一共講了幾種this的情況?

答: 4種:
1. obj.fun() -> this->obj
2. fun() 或(function(){ … })() this->window
3. new fun() -> this->新對象
4. Student.prototype.intr=function(){ … this.sname …}
this-> 將來調用intr()的.前的子對象

第三十二題

在這裏插入圖片描述
第三十三題
在這裏插入圖片描述
第三十四題
判斷是否爲升序數組?

var arr1=[1,2,3,4,5];
var arr2=[2,4,6,4,2];
var result1=arr1.every(function(elem,i,arr){
    return i<arr.length-1?elem<arr[i+1]:true;
});
var result2=arr2.every(function(elem,i,arr){
    return i<arr.length-1?elem<arr[i+1]:true;
})
console.log(result1,result2);//true  false

第三十五題
在這裏插入圖片描述

var arr=[1,2,3,4,5];
arr.forEach(function(elem,i,arr){
  // elem*=2//按值傳遞改不了
  arr[i]*=2;
})
console.log(arr);
arr=[{x:1},{x:2},{x:3},{x:4},{x:5}];
arr.forEach(function(elem){
   elem.x*=2//引用類型,改變的了
})
console.log(arr);

第三十六題
頁面上五個完全相同的按鈕,點哪個按鈕,讓按鈕彈出自己是第幾個?
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
第三十七題
在這裏插入圖片描述
在這裏插入圖片描述
第三十八題
打散數組
在這裏插入圖片描述
第三十九題
在這裏插入圖片描述
第四十題
數組去重複,有幾種方法,哪種方法最好(考慮數組中包含上萬個元素的情況)

var arr=[];
for(var i=0;i<100000;i++){
     arr.push(parseInt(Math.random()*10000));
}

//第一種:傳統,利用對象的屬性名不能重複的特點
function unique1(arr){
      var obj={};
      for(var n of arr){
         obj[n]=1;
      }
      /*var newArr=[];
      for(var key in obj){
           newArr.push(parseInt(key));
      }*/
      //如果字符串內容的數組去重
      var newArr=Object.keys(obj);
      return newArr;
}
console.time("unique1")
unique1(arr);
console.timeEnd("unique1");

//第二種:利用新ES標準中的新類型Set---最優
//Set類型的對象:是值不允許重複的集合
//向Set類型對象中添加新值,如果Set中沒有這個新值,才能添加進去,如果Set中已經有這個新值了,則不再添加
function unique2(arr){
   //將原數組arr放入一個new Set()對象中,利用new Set()不允許重複值的特點,自動去重複
   //var set=new Set();
   //將set打散後,放入新數組
   //var newArr=[...set];
   //return newArr
   return [...new Set(arr)]
}
console.time("unique2")
unique1(arr);
console.timeEnd("unique2");

第四十一題
在這裏插入圖片描述
在這裏插入圖片描述
第四十二題
在這裏插入圖片描述
第四十三題
將一個類數組對象轉化爲數組的幾種方法
1.slice
語法:slice(begin,end)方法選擇一個從開始到結束(不包括結束)的數組的一部分淺拷貝到一個新的數組對象,方法不會改變原數組。如果是對象則拷貝對象的引用到新數組,如果是基本類型則會拷貝這些值到新數組。

如果省略begin則會從0開始。如果end被省略則會抽取到最後一個元素,如果end數值大於數組長度則會抽取到最後一個元素。
使用Array.prototype.slice.call(arguments)可以將類數組轉化爲數組對象,[].slice.call(arguments)亦可

function list(){
   return Array.prototype.slice.call(arguments);
}
var list=list(1,2,3);//[1,2,3]

2.splice
語法:splice(start)
splice(start,deleteCount)
splice(start,deleteCount,item1,item2…)
返回一個包含被刪除元素的數組,start是必須值,其他是可選值,item表示要添加的元素,splice方法會直接對數組進行修改
Array.prototype.splice.call(arguments,0)
3.ES6 Array.from
語法:Array.from(arguments)
4.Array.prototype.concat.apply([],arguments)

第四十四題
arr1.every(function(elem,i,arr){ })內,如果想使用.前的arr1,爲什麼不能用this直接找到.前的對象,而只能用形參中的arr呢?
答:所有回調函數的執行,都是自動執行的,且沒有.前綴。所以,絕大多數回調函數中的this,都指window。
再比如:
var lilei={
sname:“Li Lei”,
intr:function(){ console.log(I'm ${this.sname})}
};
lilei.intr(); //this->.前的lilei,所以可以正常輸出lilei.sname
但是:
setTimeout(lilei.intr,3000); //3秒後輸出的卻是undefined
1. 爲什麼lilei.intr不加()?因爲定時器不是立刻調用。而僅僅是給定時器拿走,等3秒後,由定時器自動調用。
2. 爲什麼輸出undefined,而不是lilei.sname?
答: 因爲定時器中的函數,也是回調函數。定時器在拿走函數時,只是單純的拿走了函數的地址,而沒有同時拿走.前的對象lilei。3秒後執行函數時,是直接用函數的地址加()調用的函數。早就不知道函數的所有者是誰了。僅相當於匿名函數自調。匿名函數自調中的this->window,而window.sname當然返回undefined。
在這裏插入圖片描述
第四十五題
匿名函數和回調函數有什麼差別和關係?
答: 回調函數不一定是匿名函數,匿名函數也不一定是回調函數。
只有當回調函數只使用一次時,纔會定義爲匿名函數。如果回調函數可能反覆使用,也要定義爲有名稱的函數。
比如: setTimeout(function(){ … }, 3000)
如果這句話需要反覆使用:
不好的做法: 將setTimeout(連同裏邊的function(){}定義,反覆複製多次!
就應該: 只定義一次函數,然後再定時器中用函數名反覆引用函數:
function task(){ … }
setTimeout(task,3000)
setTimeout(task,2000)
setTimeout(task,1000)
總結: 是否使用匿名函數,取決於將來這個函數被幾處使用。如果只被一處使用,則就用匿名函數。如果多處都需要使用這個函數,則必須起名!
另一方面: 匿名函數也有主動自調的情況,就不屬於回調。
總結: 之所以大多數回調函數都是匿名函數,只是因爲多數回調函數只在一個位置使用一次!所以,沒必要起名。
第四十六題
fromi=fromi||0,按理說,邏輯運算應該返回bool值纔對呀?爲什麼會返回fromi的值或者數字0呢?
答: 邏輯運算有一個特殊的情況,就是,如果邏輯運算前後,都是值時,就不再返回bool值,而是先嚐試轉bool類型做判斷,然後,決定具體返回左邊還是右邊的值
比如: 1||0, 返回1,而不是true
1&&0 返回0, 而不是false

第四十六題
total>=500&&(total*=0.8),可不可以換成三目?
答: 按語義分支結構分爲三種情況:
1. 一件事,滿足條件就執行,不滿足條件就不執行
if實現: if(條件){ 操作 }
比如: if(total>=500){ total*=0.8 }
可簡寫爲: total>=500&&(total*=0.8)
2. 兩件事,根據條件二選一執行
if實現: if(條件){操作1}else{操作2}
比如: if(score>=60){ 輸出及格 }else{ 輸出不及格 }
可用三目簡寫: score>=60?輸出及格:輸出不及格
3. 多件事,根據條件多選一執行
if實現: if(條件1){操作1}
else if(條件2){ 操作2 }

else { 默認操作 }
比如: if(score>=90){ 輸出A }
else if(score>=80){ 輸出B }
else if(score>=60){ 輸出C }
else { 輸出D }
可用三目簡寫:
score>=90?輸出A:
score>=80?輸出B:
score>=60?輸出C:
輸出D
所以,選擇何種簡寫,需要根據其語義來選擇。如果只有一件事,選擇做與不做,最好使用短路,而不是三目。三目至少要有兩件事,二選一執行時,才適用。

第四十七題

//1. concat可以將單個元素和數組,都打散後拼接到一個新的數組中
var arr1=[].concat(1,[2,3],4);
//arr1:[1,2,3,4]
console.log(arr1);

//2. 二維數組降維,應該先將數組打散一次後,再將數字和數組混合的參數交給concat,再打散一次拼接。
var arr=[1,[2,3],4,[5,6]]
//錯誤: arr=[].concat(arr); //只能打散一次!
//console.log(arr);
//正確: 先讓apply打散arr,在將打散後的混合數字和數組的多個值交給concat
//arr=Array.prototype.concat.apply(?,arr);
//問題: apply()第一個參數寫誰?
//原理: apply()第一個參數替換concat裏的this,等效於替換concat.前的對象。
//因爲concat函數的主語只能是數組,所以替換concat.前主語的對象只能是一個數組
//arr=Array.prototype.concat.apply([],arr);
//運行時,等效於: [].concat(1,[2,3],4,[5,6])
//3. 簡寫: 從孩子搶方法比從爹搶方法簡單
//第一個[]爲了找到concat方法,而隨便創建的空數組
//      |
//    __|
//    ↓
//arr=[].concat.apply([],arr);
//                    |
//      ______________|
//      ↓
//第二個[]是創建一個空數組,代替concat.前的主語,作爲盛放拼接後的結果數組
//4. 用es6代替apply()
arr=[].concat(...arr);
console.log(arr);//[1,2,3,4,5,6]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章