JavaScript筆試知識點整理
JavaScript筆試知識點整理
2018.09.28
2018.09.29
2018.09.30
定義函式
在Javascript定義一個函式f有三種方式:第1種最常用,後兩種都是把一個匿名函式複製給變數f
- 函式宣告:
function
f(x){ alert(x); } - 函式表示式: var f =
function
(x){ alert(x); } - 建構函式: var f = new
Function
(‘x’, ‘alert(x);’)
var f = function g() {// 函式外部無法通過 g 訪問到函式
return 23;
};
typeof g;// undefined
typeof f();// "number"
typeof g();// Error
函式執行完一次,若無return 返回值和宣告變數接受返回值,都會立即消失成為undefined
output(typeof (function() {output(“Hello World!”)})());// Hello World! undefined
變數提前
函式宣告可以被提前,但函式表示式不能被提前
(function() {
//var foo; 被提前的foo
var x=foo();
var foo=function foo() {//函式宣告foo(等號左邊)被提前
return “foobar”
};
return x;// foo未被定義為函式,報錯
})();
this指向
this是在函式執行時被繫結的,它始終代表的是呼叫當前函式的那個物件。4種函式呼叫模式
- 方法呼叫
函式被儲存為一個物件的屬性時,稱其為該物件的方法。方法被呼叫時,this被繫結到這個物件上。
var name = "window";
var obj_0 = {
name: "goozy",
sayName: function() { //函式作為物件的屬性稱為方法
console.log(this.name); // this繫結到obj_0
}
};
obj_0.sayName(); // goozy
var f = obj_0.sayName;
f();// window
- 函式呼叫
函式不是物件的屬性時,那麼它就是被當做函式呼叫。this被繫結為全域性物件,瀏覽器環境下即
window
物件。
var name = "window";
function sayName() {
console.log(this.name);
}
sayName();
- 建構函式
函式加上
new
來呼叫,會建立一個連線到該函式prototype成員的新物件,同時,this會被繫結到這個新物件上。這個函式就稱為此物件的建構函式。
function Obj_1() {
this.name = "goozy";
}
var person = new Obj_1();//Obj_1作為建構函式被呼叫,this被繫結為新建立的物件person
console.log(person.name); //goozy
- apply呼叫
所有函式物件的
apply
和call
方法可以讓我們構建一個引數陣列/列表傳遞給呼叫函式,也允許改變this的值。
var name = "window";
var person = {
name: "goozy"
};
function sayName() {
console.log(this.name);
}
sayName(); //window
sayName.apply(person); //goozy(apply模式呼叫sayName,傳入第一個引數為person,this被繫結到person物件)
sayName.apply(); //window
- 練習
person2.sayName(); 這還是
方法呼叫
模式,物件為person2,sayName函式體最終執行
的函式是fun,fun是用函式呼叫
模式呼叫的。this繫結為window,結果為window。
var name = "window";
function showName() {
console.log(this.name);
}
var person1 = {
name: "goozy",
sayName: showName
}
var person2 = {
name: "Jake",
sayName: function() {
var fun = person1.sayName;
fun();
}
}
person1.sayName(); //goozy
person2.sayName(); //window
JSONP的優缺點
- 優點
- 不像XMLHttpRequest物件的Ajax請求那樣受到同源策略的限制
相容性更好
,在老版本瀏覽器中都可以執行,不需要XMLHttpRequest或ActiveX的支援- 請求完畢後可
呼叫callback回傳
結果。
- 缺點
只支援GET
請求而不支援POST等其它型別的HTTP請求- 只支援跨域HTTP請求,不能解決不同域的兩個頁面之間如何呼叫JavaScript的問題
運算子
1. 優先順序
console.log('Value is ' + (val != '0') ? 'define' : 'undefine');//define
//+優先順序大於?,所以('Value is ' + (val != '0')) ? 'define' : 'undefine'
if(! "a" in window){// !"a"先執行
var a = 1;
}
alert(a);
2.常見運算子
進行運算時,+號,數字 隱式轉換成字串。其餘的運算子號是字串隱式轉換成數字。
型別轉換
三元運算子先"分清是非","=="運算子比較"喜歡"Number"型別。
null與undefined在與其他數相等運算時不進行型別轉換
console.log(([])?true:fasle);// => console.log((true)?true:false);
console.log([]==false?true:false); // => console.log(0==0?true:false);
console.log(({}==false)?true:false);//=>console.log((NaN==0)?true:false);
console.log(undefined == null);// true
console.log(undefined === null);// false
console.log(1+ +"2"+"2");// 1+2 +"2" => 32
console.log(1+ +"b"+"2");// NaN + "2" => NaN2
同步與非同步
事件
(click,focus等等),定時器
(setTimeout和setInterval),ajax
,都是會觸發非同步
,js是單執行緒的,優先處理同步
任務;
常見非同步:回撥函式(callback)、事件監聽(click,focus等等)、釋出/訂閱、Promise物件
var elements=document.getElementsByTagName('li');
var length=elements.length;
for(var i=0;i<length;i++){// for迴圈是同步任務,onclick是非同步任務
elements[i].onclick=function(){// for迴圈執行完了,全域性的變數i通過i++變成4了
alert(i);// 4 4 4 4
// 解決方式使用:let限制i;給匿名函式後面加()
}
}
回撥時,被回撥的函式會被放在event loop裡,等待執行緒裡的任務執行完後才執行event loop裡的程式碼
function foo() {
console.log('first');
setTimeout(function(){
console.log('second');
},5);
}
for (var i = 0; i < 439; i++) {
foo();
}
// 首先全部輸出first,然後全部輸出second
Ajax工作原理
Ajax技術核心就是
XMLHttpRequest
物件。1.建立xhr物件=>2.傳送請求(open,send)=>3.獲取響應
- 建立物件:
var xhr = new XMLHttpRequest();
- xhr 傳送請求
xhr.open('get','test.html','true');
xhr.send();
- xhr獲取響應
xhr.onreadystatechange = function(){
if(xhr.readystate == 4){//請求的狀態碼
/*
0:請求還沒有建立(open執行前)
1:請求建立了還沒傳送(執行了open)
2:請求正式傳送(執行了send)
3:請求已受理,有部分資料可以用,但還沒有處理完成
4:請求完全處理完成
*/
alert(xhr.responseText);//返回的資料
}
}
Ajax和Flash
Ajax的優缺點
- 優點
- 可搜尋性
- 開放性
- 費用
- 易用性
- 易於開發。
- 缺點
- 可能破壞瀏覽器的後退功能
- 使用動態頁面更新使得使用者難於將某個特定的狀態儲存到收藏夾中
Flash的優缺點
- 優點
- 多媒體處理
- 相容性
- 向量圖形
- 客戶端資源排程
-缺點 - 二進位制格式
- 格式私有
- flash檔案經常會很大,使用者第一次使用的時候需要忍耐較長的等待時間
- 效能問題
前端效能指標
分頁面、區域、瀏覽器、效能指標,以下主要是頁面的效能指標
前端效能
-
白屏時間(first Paint Time)——使用者從開啟頁面開始到頁面開始有東西呈現為止
-
首屏時間——使用者瀏覽器首屏內所有內容都呈現出來所花費的時間
-
使用者可操作時間(dom Interactive)——使用者可以進行正常的點選、輸入等操作,預設可以統計domready時間,因為通常會在這時候繫結事件操作
-
總下載時間——頁面所有資源都載入完成並呈現出來所花的時間,即頁面 onload 的時間
Promise
一個promise可能有三種狀態:等待(pending)、已完成(fulfilled)、已拒絕(rejected)
一個promise的狀態只可能從“等待”轉到“完成”態或者“拒絕”態,不能逆向轉換,同時“完成”態和“拒絕”態不能相互轉換.
JavaScript Promise 啟示錄
同步與非同步-思否
易錯題
- 變數
var x = 10;
var a,b;
(function(){
alert(a);// undefined
alert(b);// undefined
var a=b=3;//相當於區域性變數var a = 3;全域性變數b = 3;
alert(a);// 3
alert(b);// 3
alert(x)// 10
})();
alert(a);// undefined
alert(b);// 3
- 原型繼承
js 的繼承靠的是
__proto__
,並不是prototype
var F=function(){};
Object.prototype.a=function(){};// (F.prototype)[的建構函式] === Object
Function.prototype .b=function(){};// F[的建構函式] === Function
var f=new F();// f可以取到a,不能取到b
-
f.
__proto__
=== f[的建構函式].prototype === F.prototype -
F.prototype.
__proto__
=== (F.prototype)[的建構函式].prototype === Object.prototype (所以a能夠 通過f.a訪問) -
f.constructor === F
-
F.
__proto__
=== F[的建構函式].prototype === Function.prototype (所以b可以通過, f.constructor.b訪問到) -
閉包
test構成了一個
閉包
,r1跟r2各自有自己的test作用域
JavaScript閉包-阮一峰
function test(){
var n = 4399;
function add() {// 閉包
n++;
console.log(n);
}
return {
n: n,
add: add
}
}
var r1 = test();
var r2 = test();
r1.add();// 4400
r1.add();// 4401
console.log(r1.n)// 4399
r2.add();// 4400
- 區域性變數和引數傳遞
var bb = 1;
var cc = 1;
function aa(bb) {
bb = 2;//這裡的bb賦值給了函式aa的引數bb,不影響全域性的bb
alert(bb);
};
function dd() {
cc = 2;
alert(cc);
};
aa(bb);// 2
alert(bb);// 1
dd();// 2
alert(cc);// 2
var foo = {n:1};
(function(foo){ //形參foo同實參foo一樣指向同一片記憶體空間,這個空間裡的n的值為1
var foo; //優先順序低於形參,無效。
console.log(foo.n); //輸出1
foo.n = 3; //形參與實參foo指向的記憶體空間裡的n的值被改為3
foo = {n:2}; //形參foo指向了新的記憶體空間,裡面n的值為2.
console.log(foo.n); //輸出新的記憶體空間的n的值
})(foo);
console.log(foo.n); //實參foo的指向還是原來的記憶體空間,裡面的n的值為3.
- 同名函式
同名的函式後者會覆蓋前者
var m= 1, j = k = 0;
function add(n) { // 前
return n = n+1;
}
y = add(m);// 應用後者的add(),4
function add(n) { // 後
return n = n + 3;
}
z = add(m); // 4
- 陣列的長度
arr.length
是對arr物件的length屬性進行一個訪問
var arr = [];
arr[0] = 0;
arr[1] = 1;
arr.foo = 'c';// 為arr物件建立一個屬性,不在length屬性範疇
console.log(arr.length);// 2
RegExp物件的3個方法
-
test():檢測一個字串是否匹配某個正則表示式,如果匹配成功,返回true,否則返回false;
-
exec():檢索字串中與正則表示式匹配的值,返回一個數組,存放匹配的結果;如果未找到,返回null;
-
compile():可以在指令碼執行過程中編譯正則表示式,也可以改變已有表示式。
Number轉換
console.log(Number("")); //0
console.log(Number(null)); //0
console.log(Number(undefined)); //NaN
console.log(parseInt("")); //NaN
console.log(parseInt(null)); //NaN
console.log(parseInt(undefined)); //NaN
DNS域名系統
將域名解析成IP地址
- 域名必對應一個ip地址,而ip地址不一定有域名
- DNS主要是UDP協議,但是當請求位元組過長超過512位元組時,是用TCP協議,它可以分割成多個片段
- 預設埠號是53
- 瀏覽器的DNS快取:chrome對每個域名會預設快取60s;IE將DNS快取30min;Firefox預設快取時間只有1分鐘;Safari約為10S
判斷一個物件是否為Array
typeof(arr);// 返回的是 Object而不是Array
arr instanceof Array;// true,但跨 frame 物件構建的場景下會失效
Object.prototype.toString.call(arr) === '[object Array]';// 最正確的判斷方式
作用域
JavaScript的跨域
只要 協議 、 域名 、 埠 有任何一個 不同, 都被當作是 不同 的域
- 修改document.domain來跨子域
- 使用window.name來進行跨域
- js可以使用jsonp進行跨域
sessionStorage 、localStorage 和 cookie 之間的區別
-
共同點
- 都儲存在瀏覽器端,且同源
-
區別
1.cookie
在瀏覽器和伺服器間來回傳遞
。而sessionStorage和localStorage不會自動把資料發給伺服器,僅在本地儲存。cookie資料還有路徑(path)的概念,可以限制cookie只屬於某個路徑下。
2. 儲存大小限制也不同,cookie資料不能超過4k,只適合儲存很小的資料,如會話標識。sessionStorage和localStorage 雖然也有儲存大小的限制,但比cookie大得多,可以達到5M或更大。
3. 資料有效期不同,sessionStorage
:僅在當前瀏覽器視窗關閉前有效
,自然也就不可能持久保持;localStorage
:始終有效
,視窗或瀏覽器關閉也一直儲存,因此用作持久資料;cookie只在設定的cookie過期時間之前
一直有效,即使視窗或瀏覽器關閉。
4. 作用域不同,sessionStorage不在不同的瀏覽器視窗敏感詞享,即使是同一個頁面;localStorage在所有同源視窗中都是共享的;cookie也是在所有同源視窗中都是共享的。
5. Web Storage支援事件通知機制,可以將資料更新的通知傳送給監聽者。
6. Web Storage 的 api 介面使用更方便。
GET和POST的區別
- GET請求的資料會附在URL之後(就是把資料放置在HTTP協議頭中),以?分割URL和傳輸資料,引數之間以&amp;相連,提交的資料不大於1024位元組
- POST把提交的資料則放置在是HTTP包的包體中,POST沒有限制,可傳較大量的資料
- 在ASP中,服務端獲取GET請求引數用Request.QueryString,獲取POST請求引數用Request.Form
- POST的安全性要比GET的安全性高
Object屬性判斷
hasOwnProperty
: 是用來判斷一個物件是否有你給出名稱的屬性或物件。此方法無法檢查該物件的原型鏈中是否具有該屬性,該屬性必須是物件本身
的一個成員。isPrototypeOf
: 是用來判斷要檢查其原型鏈
的物件是否存在於指定物件例項中,是則返回true,否則返回false。
函式原型重寫
重寫原型物件切斷了現有原型與任何之前
已經存在的例項之間的聯絡,他們引用的仍然是最初的原型
只有例項物件上不存在的屬性和方法才會去原型上查詢
- 重寫原型後例項化
function Person(){}
Person.prototype = {
name :"goozy",
add :function(){
alert(this.name);
},
}
var p2 =new Person();//例項化
p2.add();//goozy
- 先例項化再重寫原型
function Person(){}
var p2 =new Person();//例項化
Person.prototype = {// 切斷與例項p2的聯絡
name :"goozy",
add :function(){
alert(this.name);
},
}
p2.add();//error:p2.add is not a function
- 練習
function A() {
this.do=function() {return 'foo';};
}
A.prototype=function() {
this.do=function() {return 'bar'};
};
var x=new A().do();
console.log(x);// foo
變量回收
-
全域性變數不會被回收。
-
區域性變數會被回收,也就是函式一旦執行完以後,函式內部的東西都會被銷燬。
-
只要被另外一個作用域所引用就不會被回收
var i = 1;
var i = 2;// 第二個全域性i覆蓋前一個 =>1
var add = function() {// 全域性的add
var i = 0;
return function()
{
i++;// 閉包作用域鏈中的i
console.log(i);
}
}();
add();
//3個變數未回收
i++ 與 ++i 的主要區別
- i++ 返回原來的值,++i 返回加1後的值。
- i++ 不能作為左值,而++i 可以。
var x=0;
switch(++x)
{
case 0: ++x;
case 1: ++x;
case 2: ++x;
}
console.log(x);//3
//沒有break,會一直執行
雜七雜八
零散的知識點
- call, apply方法第一個引數,即執行時上下文物件相同,call傳遞一個引數列表,而apply則傳遞一個引數陣列。
- concat返回原陣列的一個
副本
,不會改變現有的陣列
- 域名不同不能使用ajax
- 基本型別變數(num, string, boolean, null, undefined)用
八位元組
記憶體,引用型別變數(物件、陣列和函式)則只儲存值的引用(即記憶體地址) - img標籤若src無指定地址,將觸發onerror事件
- 所有物件都有
__proto__
,所有函式物件都有prototype
- isNaN()在接受一個值後,會嘗試將這個值轉換為數值。任何
不能被轉換為數值
的值都會導致這個函式返回true。 typeof
返回的是string- 物件和數組裡的for-in,物件裡用來列舉物件的屬性,數組裡用來