《前端JavaScript面試技巧》筆記一

思考:javascript

  • 拿到一個面試題,你第一時間看到的是什麼 -> 考點
  • 又如何看待網上搜出來的永遠也看不完的題海 -> 不變應萬變
  • 如何對待接下來遇到的面試題 -> 題目到知識再到題目

知識體系:html

JS基礎知識前端

1、變量類型和計算java

題目:jquery

  • JS中使用typeof能獲得哪些類型?
  • 什麼時候使用 === 什麼時候使用 == ?
  • JS中有哪些內置函數
  • JS變量按照存儲方式區分爲哪些類型,並描述其特色
  • 如何理解JSON

知識點:面試

/*1、變量類型*/
  /*值類型vs引用類型*/
  //從內存來講,值類型是把每一個值分塊存放在內存中,而引用類型是好幾個變量公用一個內存塊,節省內存空間。
  //引用類型包括:對象、數組、函數。引用類型的屬性是能夠無限擴展的,屬性多了,就會佔用更多的內存空間,因此引用類型是爲了公用內存空間。
  //值類型
  var a = 100;
  var b = a;
  a = 200;
  console.log(b); //100
  //引用類型
  var a = {age:20};
  var b = a;
  b.age = 21;
  console.log(a.age); //21

  /*typeof運算符詳解*/
  //typeof只能區分值類型,引用類型也只能區分function,由於function的定位很是高。
  typeof undefined //undefined (值類型)
  typeof 'abc' //string (值類型)
  typeof 123 //number (值類型)
  typeof true //boolean (值類型)
  typeof {} //object (引用類型)
  typeof [] //object (引用類型)
  typeof null //object (引用類型)
  typeof console.log //function (引用類型)


/*2、變量計算---強制類型轉換*/ //字符串拼接 var a = 100+10; //110 var b = 100+'10'; //'10010' //運算符 //==會把兩邊的值轉換爲true或false 100 == '100'; //true 0 == ''; //true null == undefined; //true //if語句 //if會把括號裏面的值轉換爲true或false var a = true; if(a){...} var b = 100; if(b){...} var c = ''; if(c){...} //邏輯運算 console.log(10 && 0); //0 console.log('' || 'abc'); //'abc' console.log(!window.abc); //true //判斷一個變量會被看成true仍是false var a = 100; console.log(!!a);

解題:ajax

JS中使用typeof能獲得哪些類型?正則表達式

  undefined、string、number、boolean、object、functionjson

什麼時候使用 === 什麼時候使用 == ?api

if(obj.a==null){
   //這裏至關於 obj.a === null || obj.a ===undefined ,簡寫形式
   //這是 jquery 源碼中推薦的寫法
}

  雙等會進行強制類型轉換,三等不會進行強制類型轉換。

  除了上面的例子用雙等,其它的都用三等。

JS中有哪些內置函數 

  數據封裝類對象
  Object
  Array
  Boolean
  Number
  String
  Function
  Date
  RegExp :正則表達式
  Error

JS變量按照存儲方式區分爲哪些類型,並描述其特色

  值類型和引用類型。

  從內存來講,值類型是把每一個值分塊存放在內存中,而引用類型是好幾個變量公用一個內存塊,節省內存空間。

如何理解JSON  

  JSON只不過是一個JS對象,也是一種數據格式。
  JSON基本的api只有兩個:
  JSON.stringify({a:10,b:20}); //對象轉字符串
  JSON.parse('{"a":10,"b":20}'); //字符串轉對象

 

 2、原型和原型鏈

題目:

  • 如何準確判斷一個變量是數組類型
  • 寫一個原型鏈繼承的例子
  • 描述new一個對象的過程
  • zepto(或其餘框架)源碼中如何使用原型鏈

 知識點:

//大寫開頭的函數基本都是構造函數,這麼寫提升代碼可讀性

/*1、構造函數*/
  function Foo(name,age){
    this.name = name;
    this.age = age;
    this.class = 'class-1';
    //return this //默認有這一行,最好不要寫
  }
  var f = new Foo('zhangsan',20);
  //var f1 = new Foo('lisi',22); //建立多個對象
  //new時把參數傳進去。new函數執行時裏面的this會變成空對象,給this賦值後,再把this給return回來,return回來就把值賦值給了f,這時f就具有f.name = 'zhangsan',f.age = 20,f.class ='' 'class-1'
  

/*2、構造函數-擴展*/
  /*
  var a = {} 實際上是 var a = new Object() 的語法糖。 構造函數是Object函數。
  var a = [] 實際上是 var a = new Array() 的語法糖。 構造函數是Array函數。
  function Foo(){...} 實際上是 var Foo = new Function(...)。 構造函數是Function。
  推薦前面的書寫方式。
  使用instanceof判斷一個函數是不是一個變量的構造函數。好比:判斷一個變量是否爲「數組」:變量 instanceof Array
  */

/*3、原型規則和示例*/ //5條原型規則-原型規則是學習原型鏈的基礎 //一、全部的引用類型(數組、對象、函數),都具備對象特性,便可自由擴展屬性(除了null之外) var obj = {}; obj.a = 100; var arr = []; arr.a = 100; function fn(){}; fn.a = 100; //二、全部的引用類型(數組、對象、函數),都有一個__proto__屬性,屬性值是一個普通的對象。 __proto__ 隱式原型 console.log(obj.__proto__); console.log(arr.__proto__); console.log(fn.__proto__); //三、全部的函數,都有一個prototype屬性,屬性值也是一個普通的對象。 prototype顯式原型 console.log(fn.prototype); //四、全部的引用類型(數組、對象、函數),__proto__屬性值指向它的構造函數的"prototype"屬性值。 console.log(obj.__proto__ === Object.prototype); //五、當試圖獲得一個對象的某個屬性時,若是這個對象自己沒有這個屬性,那麼會去它的 __proto__(即它的構造函數的prototype)中尋找。 //構造函數 function Foo(name,age){ this.name = name; } Foo.prototype.alertName = function(){ alert(this.name); } //建立示例 var f = new Foo('zhangsan'); f.printName = function(){ console.log(this.name); } //測試 f.printName(); //zhangsan f.alertName(); //zhangsan //補充 -- 循環對象自身的屬性 var item; for(item in f){ //高級瀏覽器已經在 for in 中屏蔽了來自原型的屬性 //可是這裏建議仍是加上這個判斷,保證程序的健壯性 if(f.hasOwnProperty(item)){ console.log(item); } } /*4、原型鏈*/ //構造函數 function Foo(name,age){ this.name = name; } Foo.prototype.alertName = function(){ alert(this.name); } //建立示例 var f = new Foo('zhangsan'); f.printName = function(){ console.log(this.name); } //測試 f.printName(); //zhangsan f.alertName(); //zhangsan f.toString(); //要去f.__proto__.__proto__中查找 /*5、instanceof*/ //用於判斷引用類型屬於哪一個構造函數的方法 //構造函數 function Foo(name,age){ this.name = name; } Foo.prototype.alertName = function(){ alert(this.name); } //建立示例 var f = new Foo('zhangsan'); f.printName = function(){ console.log(this.name); } //測試 f.printName(); //zhangsan f.alertName(); //zhangsan f.toString(); //要去f.__proto__.__proto__中查找 //instanceof //f instanceof Foo 的判斷邏輯是: //一、f 的 __proto__ 一層一層往上,可否對應到 Foo.prototype //二、再試着判斷 f instanceof Object

 

  

 

 

解題:

如何準確判斷一個變量是數組類型 

var arr = [];
arr instanceof Array; //true
typeof arr; //object   typeof是沒法判斷是不是數組的 

寫一個原型鏈繼承的例子

 //動物
  function Animal(){
      this.eat = function(){
          console.log('animal eat');
      }
  }
  
  //狗
  function Dog(){
      this.bark = function(){
          console.log('dog bark');
      }
  }
  Dog.prototype = new Animal();
  //哈士奇
  var hashiqi = new Dog();

  /*面試時千萬不要寫這個例子,要寫更貼近於實戰的原型鏈例子*/
/*用下面的例子*/

//寫一個封裝DOM查詢的例子
function Elem(id){
  this.elem = document.getElementById(id);
}

Elem.prototype.html = function(val){
  var elem = this.elem;
  if(val){
    elem.innerHTML = val;
    return this; //鏈式操做
  }else {
    return elem.innerHTML;
  }
}

Elem.prototype.on = function(type,fn){
  var elem = this.elem;
  elem.addEventListener(type,fn);
  return this;
}

var div1 = new Elem('div1');
console.log(div1.html());
div1.html('<h2>新內容</h2>').on('click',function(){
alert(div1.html());
}).html('<h2>新內容新內容新內容</h2>').on('click',function(){
alert('第二次');
}); //鏈式操做


/*div1.html('<h2>新內容</h2>')
div1.on('click',function(){
alert(div1.html());
})*/

 

描述new一個對象的過程

/*
  一、建立一個新對象
  二、this指向這個新對象
  三、執行代碼,即對this賦值
  四、返回this
 */
 /*構造函數*/
  function Foo(name,age){
    this.name = name;
    this.age = age;
    this.class = 'class-1';
    //return this //默認有這一行
  }
  var f = new Foo('zhangsan',20);
  //var f1 = new Foo('lisi',22); //建立多個對象

zepto(或其餘框架)源碼中如何使用原型鏈

  1. 閱讀源碼是高效提升技能的方式。如zepto
  2. 但不能「埋頭苦鑽」,有技巧在其中
  3. 慕課網搜索「zepto設計和源碼分析」

 

3、做用域和閉包

題目:

  • 說一下對變量提高的理解
  • 說明this幾種不一樣的使用場景
  • 建立10個<a>標籤,點擊時彈出對應的序號
  • 如何理解做用域
  • 實際開發中閉包的應用

知識點:

/*1、執行上下文*/
 //範圍:一段<script>或者一個函數
 //全局:變量定義、函數聲明(一段<script>)
 //函數:變量定義、函數聲明、this、arguments(函數)
 //PS:注意「函數聲明」和「函數表達式」的區別
 //實際代碼中不要下面這種寫法,都是先定義,再執行,提升代碼可讀性。
 console.log(a); //undefined
 var a = 100;

 fn('zhangsan'); //'zhangsan' 20
 function fn(name){ //函數聲明
  age = 20;
  console.log(name,age);
  var age;
 }
 var fn = function(){} //函數表達式


/*2、this*/
	//this要在執行時才能確認值,定義時沒法確認。
	//做爲構造函數執行
	//做爲對象屬性執行
	//做爲普通函數執行
	//call、apply、bind
	var a = {
		name:'A',
		fn:function(){
			console.log(this.name);
		}
	}
	a.fn(); //this===a
	a.fn.call({name:'B'}); //this==={name:'B'}
	var fn1 = a.fn;
	fn1(); //this===window


/*做用域*/
	/*無塊級做用域*/
	//沒有塊級做用域,寫在裏面和外面是同樣的。不建議下面這種寫法,程序不易讀。
	if(true){
		var name = 'zhangsan';
	}
	console.log(name); //zhangsan
	/*函數和全局做用域*/
	var a = 100; //全局變量
	function fn(){
		var a = 200; //局部變量
		console.log('fn',a);
	}
	console.log('global',a);
	fn();


/*做用域鏈*/
	//函數的父級做用域是函數定義時的做用域,不是函數執行時的做用域。
	var a = 100;
	function fn(){
		var b = 200;

		//當前做用域沒有定義的變量,即「自由變量」
		console.log(a); //100
		console.log(b); //200
	}
	fn();
	//例子
	var a = 100;
	function F1(){
		var b = 200;
		function F2(){
			var c = 300;
			console.log(a); //100 //自由變量
			console.log(b); //200 //自由變量
			console.log(c); //300
		}
		F2();
	}
	F1();



/*閉包*/
	function F1(){
		var a = 100;

		//返回一個函數(函數做爲返回值)
		return function(){
			console.log(a);
		}
	}
	//f1獲得一個函數
	var f1 = F1();
	var a = 200;
	f1();
	//f1執行的是return裏的函數,return裏的a是個自由變量,要去父級做用域尋找,父級做用域F1裏面定義了a,因此打印出來的a的值是100.
	/*閉包的使用場景
	一、函數做爲返回值(上一個demo)
	二、函數做爲函數傳遞(下面這個例子)
	*/
	function F1(){
		var a = 100;
		return function(){
			console.log(a);
		}
	}
	var f1 = F1();
	function F2(fn){
		var a = 200;
		fn();
	}
	F2(f1);

解題:

說一下對變量提高的理解 

變量定義
函數聲明(注意和函數表達式的區別)
執行上下文的概念。
各個函數中,它的變量的聲明和定義,以及函數的聲明都會提早,放在前面,由此就是變量提高主觀上、形象上的理解。

說明this幾種不一樣的使用場景

做爲構造函數執行

做爲對象屬性執行

做爲普通函數執行

call、apply、bind

建立10個<a>標籤,點擊時彈出對應的序號

var i;
for(i=0;i<10;i++){
	(function(i){
		var a = document.createElement('a');
		a.innerHTML = i+'<br>';
		a.addEventListener('click',function(e){
			e.preventDefault();
			alert(i);
		})
		document.body.appendChild(a);
	})(i);
}

如何理解做用域

要領:
一、自由變量
二、做用域鏈,即自由變量的查找
三、閉包的兩個場景

實際開發中閉包的應用

//閉包實際應用中主要用於封裝變量,收斂權限
	function isFirstLoad(){
		var _list = [];
		return function(id){
			if(_list.indexOf(id)>=0){
				return false;
			}else {
				_list.push(id);
				return true;
			}
		}
	}
	//使用
	var firstLoad = isFirstLoad();
	firstLoad(10); //true
	firstLoad(10); //false
	firstLoad(20); //true

//在 isFirstLoad 函數外面,根本不可能修改掉 _list 的值

  

4、異步和單線程

題目: 

  • 同步和異步的區別是什麼?分別舉一個同步和異步的例子
  • 一個關於setTimeout的筆試題
  • 前端使用異步的場景有哪些

知識點:

/*什麼是異步(對比同步)*/
	//同時執行,不會阻塞程序執行
	console.log(100);
	setTimeout(function(){
		console.log(200);
	},1000);
	console.log(300);
	setTimeout(function(){
		console.log(400);
	},1000);
	//下面這個例子相似同步
	console.log(100);
	alert(200);
	console.log(300);



/*前端使用異步的場景*/
	/*什麼時候須要異步:
	在可能發生等待的狀況
	等待過程當中不能像alert同樣阻塞程序進行
	所以,全部的「等待的狀況」都須要異步
	一、定時任務:setTimeout、setInterval
	二、網絡請求:ajax請求、動態<img>加載
	三、事件綁定
	*/
	//ajax請求代碼示例
	console.log('start');
	$.get('./data1.json',function(data1){
		console.log(data1);
	})
	console.log('end');
	//<img>加載示例
	console.log('start');
	var img = document.createElement('img');
	img.onload = function(){
		console.log('loaded');
	}
	img.src = '/xxx.png';
	console.log('end');
	//事件綁定示例
	console.log('start');
	document.getElementById('btn1').addEventListener('click',function(){
		alert('clicked');
	})
	console.log('end');
	



/*異步和單線程*/
	console.log(100);
  setTimeout(function(){
    console.log(200);
  });
  console.log(300);
  //執行結果:100、300、200
  //setTimeout是異步,最後執行。這個例子的setTimeout沒有等待時間,因此待其它執行完以後立馬執行setTimeout。
  //單線程就是一次只能作一件事
  /*解析:
  一、執行第一行,打印100
  二、執行setTimeout後,傳入setTimeout的函數會被暫存起來,不會當即執行(單線程的特色,不能同時幹兩件事)
  三、執行最後一行,打印300
  四、待全部程序執行完,處於空閒狀態時,會立馬看有沒有暫存起來的要執行。
  五、發現暫存起來的setTimeout中的函數無需等待時間,就當即拿過來執行。
  */

 

解題:

同步和異步的區別是什麼?分別舉一個同步和異步的例子

同步會阻塞代碼執行,而異步不會。
alert是同步,setTimeout是異步。

例子:

//異步
	console.log(100);
	setTimeout(function(){
		console.log(200);
	},1000);
	console.log(300);
//同步
	console.log(100);
	alert(200);
	console.log(300);

 

一個關於setTimeout的筆試題

console.log(1);
  setTimeout(function(){
    console.log(2);
  },0)
  console.log(3);
  setTimeout(function(){
    console.log(4);
  },1000)
  console.log(5);
  
  //1 3 5 2 4

 

前端使用異步的場景有哪些  

  1. 定時任務:setTimeout、setInterval
  2. 網絡請求:ajax請求、動態<img>加載
  3. 事件綁定

 

5、其它知識點

題目:

  • 獲取2017-06-10格式的日期
  • 獲取隨機數,要求是長度一致的字符串格式
  • 寫一個能遍歷對象和數組的通用forEach函數

知識點: 

/*日期*/
 Date.now(); //獲取當前時間毫秒數
 var dt = new Date();
 dt.getTime(); //獲取毫秒數
 dt.getFullYear(); //年
 dt.getMonth(); //月(0-11)
 dt.getDate(); //日(0-31)
 dt.getHours(); //小時(0-23)
 dt.getMinutes(); //分鐘(0-59)
 dt.getSeconds(); //秒(0-59)



/*Math*/
	Math.random(); //獲取隨機數。(返回的是 >0 和 <1 的小數)。有清除緩存的做用。



/*數組API*/
	//forEach //遍歷全部元素
	var arr = [1,2,3];
	arr.forEach(function(item,index){
		//遍歷數組的全部元素。item:元素的值。index:元素的位置
		console.log(index,item);
	})
	//every   //判斷全部元素是否都符合條件
	var arr = [1,2,3];
	// var arr = [1,2,3,4,5]; 
	var result = arr.every(function(item,index){
		if(item<4){
			return true;
		}
	})
	console.log(result); //true
	//some    //判斷是否有至少一個元素符合條件
	var arr = [1,2,3];
	var result = arr.some(function(item,index){
		if(item<2){
			return true;
		}
	})
	console.log(result); //true
	//sort    //排序
	var arr = [1,4,2,5,3];
	var arr2 = arr.sort(function(a,b){
		//從小到大排序
		return a -b;

		//從大到小排序
		//return b-a;
	})
	console.log(arr2);
	//map     //對元素從新組裝,生成新數組
	var arr = [1,2,3,4];
	var arr2 = arr.map(function(item,index){
		return '<b>' + item + '</b>';
	})
	console.log(arr2);
	//filter  //過濾符合條件的元素
	var arr = [1,2,3,4];
	var arr2 = arr.filter(function(item,index){
		if(item>=2){
			return true;
		}
	})
	console.log(arr2);



/*對象API*/
	var obj = {
		x:100,
		y:200,
		z:300
	}
	var key;
	for(key in obj){ //key是obj的屬性名
		//注意這裏的 hasOwnProperty ,再講原型鏈時候講過了
		if(obj.hasOwnProperty(key)){ //判斷key是obj原生的屬性,而不是原型裏面的屬性
			console.log(key,obj[key]);
		}
	}

 

解題:

獲取2017-06-10格式的日期

function formatDate(dt){
  if(!dt){
    dt = new Date();
  }
  var year = dt.getFullYear();
  var month = dt.getMonth() + 1;
  var date = dt.getDate();
  if(month<10){
    //強制類型轉換
    month = '0'+month;
  }
  if(date<10){
    //強制類型轉換
    date = '0'+date;
  }
  //強制類型轉換
  return year + '-' + month + '-' + date;
}
var dt = new Date();
var formatDate = formatDate();
console.log(formatDate);

獲取隨機數,要求是長度一致的字符串格式

var random = Math.random();
var random = random + '0000000000'; //後面加上10個零,爲了確保長度一致
var random = random.slice(0,10); //截取前10位
console.log(random);

寫一個能遍歷對象和數組的通用forEach函數

function forEach(obj,fn){
    var key;
    if(obj instanceof Array){
      //準確判斷是否是數組
      obj.forEach(function(item,index){
        fn(index,item);
      })
    }else{
      //不是數組就是對象,對象用for in循環
      for(key in obj){
        fn(key,obj[key]);
      }
    }
  }
  var arr = [1,2,3]; 
  //注意,這裏參數的順序換了,爲了和對象的遍歷格式一致
  forEach(arr,function(index,item){
    console.log(index,item);
  })
  var obj = {x:100,y:200};
  forEach(obj,function(key,value){
    console.log(key,value);
  })
相關文章
相關標籤/搜索