1.eval是做什么的?為什么盡量避免使用eval?
- Javascript全局對象,eval()函數(shù)可以計算機(jī)某個字符串,并計算其中的JS代碼。
- eval只在被直接調(diào)用且調(diào)用函數(shù)就是eval本身時才會在當(dāng)前作用域執(zhí)行,否則會在全局作用域中執(zhí)行。
- eval()可以干擾作用域鏈,eval()可以訪問和修改它外部作用域中的變量。
- eval也存在安全問題,因為它會執(zhí)行任意傳給它的代碼, 在代碼字符串未知或者是來自一個不信任的源時,絕對不要使用eval函數(shù)。當(dāng)處理Ajax請求得到的JSON相應(yīng)的時候。在這些情況下,最好使用JavaScript內(nèi)置方法來解析JSON相應(yīng),以確保安全和有效。若瀏覽器不支持JSON.parse(),你可以使用來自JSON.org的庫。
- eval不容易調(diào)試。用chromeDev等調(diào)試工具無法打斷點(diǎn)調(diào)試。
- 說到性能問題,在舊的瀏覽器中如果你使用了eval,性能會下降10倍。在現(xiàn)代瀏覽器中有兩種編譯模式:fast path和slow path。fast path是編譯那些穩(wěn)定和可預(yù)測(stable and predictable)的代碼。而明顯的,eval不可預(yù)測,所以將會使用slow path,所以會慢。(2次,一次解析js,一次執(zhí)行。)
2.null和undefined的區(qū)別?
- undefined類型值只有一個即undefined, 當(dāng)聲明的變量還未被初始化時,變量的默認(rèn)值為undefined。
- Null類型的值只有一個即null,null用來表示尚未存在的對象,常用來表示函數(shù)企圖返回一個不存在的對象。
alert(typeof undefined); //output "undefined"
alert(typeof null); //output "object"
第一行代碼很容易理解,undefined的類型為Undefined;第二行代碼卻讓人疑惑,為什么null的類型又是Object了呢?其實這是JavaScript最初實現(xiàn)的一個錯誤,后來被ECMAScript沿用下來。在今天我們可以解釋為,null即是一個不存在的對象的占位符,但是在實際編碼時還是要注意這一特性。
alert(null == undefined); //output "true"
ECMAScript認(rèn)為undefined是從null派生出來的,所以把它們定義為相等的。但是,如果在一些情況下,我們一定要區(qū)分這兩個值,那應(yīng)該怎么辦呢?可以使用下面的兩種方法。
alert(null === undefined); //output "false"
alert(typeof null == typeof undefined); //output "false"
使用typeof方法在前面已經(jīng)講過,null與undefined的類型是不一樣的,所以輸出"false"。而===代表絕對等于,在這里null === undefined輸出false。
2 寫一個通用的事件偵聽器函數(shù)。
// event(事件)工具集,來源:github.com/markyun
markyun.Event = {
// 頁面加載完成后
readyEvent : function(fn) {
if (fn==null) {
fn=document;
}
var oldonload = window.onload;
if (typeof window.onload != 'function') {
window.onload = fn;
} else {
window.onload = function() {
oldonload();
fn();
};
}
},
// 視能力分別使用dom0||dom2||IE方式 來綁定事件
// 參數(shù): 操作的元素,事件名稱 ,事件處理程序
addEvent : function(element, type, handler) {
if (element.addEventListener) {
//事件類型、需要執(zhí)行的函數(shù)、是否捕捉
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent('on' + type, function() {
handler.call(element);
});
} else {
element['on' + type] = handler;
}
},
// 移除事件
removeEvent : function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.datachEvent) {
element.detachEvent('on' + type, handler);
} else {
element['on' + type] = null;
}
},
// 阻止事件 (主要是事件冒泡,因為IE不支持事件捕獲)
stopPropagation : function(ev) {
if (ev.stopPropagation) {
ev.stopPropagation();
} else {
ev.cancelBubble = true;
}
},
// 取消事件的默認(rèn)行為
preventDefault : function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
// 獲取事件目標(biāo)
getTarget : function(event) {
return event.target || event.srcElement;
},
// 獲取event對象的引用,取到事件的所有信息,確保隨時能使用event;
getEvent : function(e) {
var ev = e || window.event;
if (!ev) {
var c = this.getEvent.caller;
while (c) {
ev = c.arguments[0];
if (ev && Event == ev.constructor) {
break;
}
c = c.caller;
}
}
return ev;
}
};
3.模塊化怎么做?
立即執(zhí)行函數(shù),不暴露私有成員
var module1 = (function(){
var _count = 0;
var m1 = function(){
//...
};
var m2 = function(){
//...
};
return {
m1 : m1,
m2 : m2
};
})();
4."use strict";是什么意思 ? 使用它的好處和壞處分別是什么?
ECMAscript 5添加了第二種運(yùn)行模式:"嚴(yán)格模式"(strict mode)。顧名思義,這種模式使得Javascript在更嚴(yán)格的條件下運(yùn)行。
設(shè)立"嚴(yán)格模式"的目的,主要有以下幾個:
1. 消除Javascript語法的一些不合理、不嚴(yán)謹(jǐn)之處,減少一些怪異行為;
2. 消除代碼運(yùn)行的一些不安全之處,保證代碼運(yùn)行的安全;
3. 提高編譯器效率,增加運(yùn)行速度;
4. 為未來新版本的Javascript做好鋪墊。
注:經(jīng)過測試 IE6,7,8,9 均不支持嚴(yán)格模式。
缺點(diǎn):
現(xiàn)在網(wǎng)站的 JS 都會進(jìn)行壓縮,一些文件用了嚴(yán)格模式,而另一些沒有。這時這些本來是嚴(yán)格模式的文件,被 merge后,這個串就到了文件的中間,不僅沒有指示嚴(yán)格模式,反而在壓縮后浪費(fèi)了字節(jié)。
怎么寫
首先嚴(yán)格模式可以寫在整個腳本或模塊中,也可以寫在函數(shù)中.如果寫在全局環(huán)境,可以直接在文件的第一句加入"use strict"就可以了. 但是如果這么寫的話你就慘了.
假如你的文件引入其它腳本文件時.假如其它腳本沒有啟用嚴(yán)格模式你將面臨很多問題.所以建議把嚴(yán)格模式寫在函數(shù)中,寫在函數(shù)內(nèi)的第一句就可以了.
作用
去除with關(guān)鍵字,使用嚴(yán)格模式后,with關(guān)鍵字會報錯不支持
with(){
}
這樣的寫法了.
防止意外的全局變量,這樣不帶var的聲明變量也不可以了.
a = 2;
函數(shù)中未定義或者為null的this不在指向全局變量.防止依賴函數(shù)中的默認(rèn)this行為代碼出錯.
//"use strict"
this.color = "red";
function sayColor() {
console.log(this.color);
}
sayColor();\\undefined
sayColor.call(null);\\undefined
嚴(yán)格模式
"use strict"
this.color = "red";
function sayColor() {
console.log(this.color);
}
sayColor();
sayColor.call(null);
console.log(this.color);//TypeError: Cannot read property 'color' of undefined
另一種情況
"use strict"
function Person(name) {
this.name = name;
}
var me = Person("Nicholas");
this.name = name;
^
TypeError: Cannot set property 'name' of undefined
原型繼承
"use strict"
function Person(name) {
this.name = name;
}
var me = new Person("Nicholas");
沒有報錯. 原來這樣. this = proto = prototype 這些屬性都是在new 一個新的對象. 就是在原型繼承的時候賦值的.
重命名變量會報錯,這個不多說了,都理解.
安全的eval()
``js
//"use strict";
var y = eval("var x=10;");
console.log(x); //10
```js
"use strict";
var y = eval("var x=10;");
console.log(x);
console.log(x);
^
ReferenceError: x is not defined
禁止對只讀屬性賦值
// "use strict";
var person = {};
Object.defineProperty(person, "name",{
writable: false,
value: "Nicholas"
});
person.name = "John";
以上正確
"use strict";
var person = {};
Object.defineProperty(person, "name",{
writable: false,
value: "Nicholas"
});
person.name = "John";
報錯:
c:\Users\Feng Huang\WebstormProjects\MemberManagement\test4.js:13
person.name = "John";
^
TypeError: Cannot assign to read only property 'name' of #<Object>
提示只讀屬性不能賦值.
new操作符具體干了什么呢?
1、創(chuàng)建一個空對象,并且 this 變量引用該對象,同時還繼承了該函數(shù)的原型。
2、屬性和方法被加入到 this 引用的對象中。
3、新創(chuàng)建的對象由 this 所引用,并且最后隱式的返回 this 。
var obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
Javascript中,有一個函數(shù),執(zhí)行時對象查找時,永遠(yuǎn)不會去查找原型,這個函數(shù)是?
hasOwnProperty()
["1", "2", "3"].map(parseInt) 答案是多少?
[1, NaN, NaN] 因為 parseInt 需要兩個參數(shù) (val, radix),其中 radix 表示解析時用的基數(shù)。map 傳了 3 個 (element, index, array),對應(yīng)的 radix 不合法導(dǎo)致解析失敗。
談?wù)凾his對象的理解。
this是js的一個關(guān)鍵字,隨著函數(shù)使用場合不同,this的值會發(fā)生變化。 但是有一個總原則,那就是this指的是調(diào)用函數(shù)的那個對象。 this一般情況下:是全局對象Global。 作為方法調(diào)用,那么this就是指這個對象.
js延遲加載的方式有哪些?
defer和async、動態(tài)創(chuàng)建DOM方式(用得最多)、按需異步載入js.
defer
定義和用法
defer 屬性規(guī)定是否對腳本執(zhí)行進(jìn)行延遲,直到頁面加載為止。
有的 javascript 腳本 document.write 方法來創(chuàng)建當(dāng)前的文檔內(nèi)容,其他腳本就不一定是了。
如果您的腳本不會改變文檔的內(nèi)容,可將 defer 屬性加入到 <script> 標(biāo)簽中,以便加快處理文檔的速度。因為瀏覽器知道它將能夠安全地讀取文檔的剩余部分而不用執(zhí)行腳本,它將推遲對腳本的解釋,直到文檔已經(jīng)顯示給用戶為止。
瀏覽器支持
只有 Internet Explorer (9以前)支持 defer 屬性。
async
定義和用法
async 屬性規(guī)定一旦腳本可用,則會異步執(zhí)行。
注釋:async 屬性僅適用于外部腳本(只有在使用 src 屬性時)。
注釋:有多種執(zhí)行外部腳本的方法:
- 如果 async="async":腳本相對于頁面的其余部分異步地執(zhí)行(當(dāng)頁面繼續(xù)進(jìn)行解析時,腳本將被執(zhí)行)
- 如果不使用 async 且 defer="defer":腳本將在頁面完成解析時執(zhí)行
- 如果既不使用 async 也不使用 defer:在瀏覽器繼續(xù)解析頁面之前,立即讀取并執(zhí)行腳本
語法
<script async="async">
HTML 4.01 與 HTML 5 之間的差異
async 屬性是 HTML5 中的新屬性
async和defer 的區(qū)別
defer 屬性標(biāo)注的腳本是延遲腳本,使得瀏覽器延遲腳本的執(zhí)行,也就是說,腳本會被異步下載但是不會被執(zhí)行,直到文檔的載入和解析完成,并可以操作,腳本才會被執(zhí)行。
async 屬性標(biāo)注的腳本是異步腳本,即異步下載腳本時,不會阻塞文檔解析,但是一旦下載完成后,立即執(zhí)行,阻塞文檔解析。
延遲腳本會按他們在文檔里的出現(xiàn)順序執(zhí)行
異步腳本在它們載入后執(zhí)行,但是不能保證執(zhí)行順序。
使用async的意義就在于使得下載腳本時,不會阻塞文檔的解析。因為async的腳本執(zhí)行順序是沒有保證的,因此要確認(rèn)腳本間沒有依賴關(guān)系。
現(xiàn)在呢基本上都是在文檔的最后寫腳本,那么這和 defer 的區(qū)別在哪里呢?
第一點(diǎn)當(dāng)然是異步下載腳本了,第二點(diǎn)就是 使用async或defer任何一個都意味著在腳本里不能出現(xiàn) document.write。