思考:javascript
知識體系:html
JS基礎知識前端
1、變量類型和計算java
題目:jquery
知識點:面試
/*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、原型和原型鏈
題目:
知識點:
//大寫開頭的函數基本都是構造函數,這麼寫提升代碼可讀性 /*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(或其餘框架)源碼中如何使用原型鏈
3、做用域和閉包
題目:
知識點:
/*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、異步和單線程
題目:
知識點:
/*什麼是異步(對比同步)*/
//同時執行,不會阻塞程序執行
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
前端使用異步的場景有哪些
5、其它知識點
題目:
知識點:
/*日期*/
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);
})