1.JS找字符串中出現最多的字符
例如:求字符串'nininihaoa'中出現次數最多字符
var str = "nininihaoa";
var o = {};
for (var i = 0, length = str.length; i < length; i++) {var char = str.charAt(i);if (o[char]) {o[char]++; //次數加1} else {o[char] = 1; //若第一次出現,次數記為1}
}
console.log(o); //輸出的是完整的對象,記錄著每一個字符及其出現的次數
//遍歷對象,找到出現次數最多的字符的次數
var max = 0;
for (var key in o) {if (max < o[key]) {max = o[key]; //max始終儲存次數最大的那個}
}
for (var key in o) {if (o[key] == max) {//console.log(key);console.log("最多的字符是" + key);console.log("出現的次數是" + max);}
}
結果如下:
Object {n: 3, i: 3, h: 1, a: 2, o: 1}
最多的字符是n
出現的次數是3
最多的字符是i
出現的次數是3
方法二,當然還可以使用reduce
方法來實現:
var arrString = 'abcdaabc';
arrString.split('').reduce(function(res, cur) {res[cur] ? res[cur] ++ : res[cur] = 1return res;
}, {})
想詳細了解reduce()方法,可以參考:《JS進階篇--JS數組reduce()方法詳解及高級技巧 》
2.JS實現九九乘法表
jQuery實現方式:
var sum=0;
var wite;
for (var i = 1; i < 10; i++){var div=$('<div class="class'+i+'"></div>');$("body").append(div);for(var j = i; j > 0; j--){sum = j * i;wite = (j+"X"+i+"="+sum);div.prepend($('<span style="padding-right:10px">'+wite+'</span>'));}}
實現結果如圖所示:
原生js實現方式:
css代碼:
html,body,ul,li {padding: 0; margin: 0; border: 0;
}
ul { width: 900px;overflow: hidden;margin-top: 4px;font-size: 12px; line-height: 36px;
}
li { float: left; width: 90px; margin: 0 4px; display: inline-block; text-align: center; border: 1px solid #333; background:yellowgreen;
}
js代碼:
for(var i = 1; i <= 9; i++){var myUl = document.createElement('ul');for(var j = 1; j <= i; j++){var myLi = document.createElement('li');var myText = document.createTextNode(j + " × " + i + " = " + i*j);myLi.appendChild(myText);myUl.appendChild(myLi);}document.getElementsByTagName('body')[0].appendChild(myUl);
}
原生js實現效果如圖所示:
3.這幾道前端面試題很繞嗎?做對了幾道?
第一題
var fun = function(){this.name = 'peter';return {name: 'jack'};
}
var p = new fun();
//請問p.name是:
第二題
var fun = function(){this.name = 'peter';return 'jack'; }var p = new fun();
//請問p.name是:
第三題
var fun = function(){}fun.prototype = {info : {name : 'peter',age : 25}
}var a = new fun();
var b = new fun();a.info.name = 'jack';
b.info.name = 'tom';//請問a.info.name和b.info.name分別是:
第四題
var fun = function(){this.info = {name : 'peter',age : 25}
}var a = new fun();
var b = new fun();a.info.name = 'jack';
b.info.name = 'tom';
//請問a.info.name和b.info.name分別是:
第五題
var fun = function(){}fun.prototype = { name : 'peter', age : 25
}var a = new fun();
var b = new fun();a.name = 'jack';
b.name = 'tom';
//請問a.name和b.name分別是:
第六題
var fun = function(){this.info = {name : 'peter',age : 25}
}fun.prototype = {info : {name : 'peter',age : 25}
}var a = new fun();
var b = new fun();a.info.name = 'jack';
b.info.name = 'tom';
//請問a.info.name和b.info.name分別是:
解答:
1,2題考察的是構造函數的返回值的問題。
每個函數都有返回值,如果使用了return
語句,則返回return
后跟的值,如果沒有使用return
,則默認返回undefined
.
特別的,如果這個函數是構造函數,則默認返回this
對象,如果構造函數內使用了return
語句,并且return
后跟的是一個對象,則這個構造函數返回的是這個對象,否則返回this
.
所以1題中的p = {name: 'jack'},而2題中的p = {name: 'peter'}.
3, 4, 5, 6題都是考察prototype的知識。
3.兩個都輸出tom。首先你要知道原型模式的執行流程:
1.先查找構造函數實例里的屬性或方法,如果有,就立即返回。
2.如果構造函數的實例沒有,就去它的原型對象里找,如果有,就立即返回
4 .a.info.name 為jack,b.info.name為tom。原因我想你從第三題已經得出來了。
5.a.name輸出jack,b.name輸出tom。原因我想你從第三題已經得出來了。
4.通過示例搞懂js閉包
例1
function sayHello(name)
{var text = 'Hello ' + name;var sayAlert = function() { console.log(text); }sayAlert();
}
sayHello("Bob") // 輸出"Hello Bob"
在sayHello()函數中定義并調用了sayAlert()函數;sayAlert()作為內層函數,可以訪問外層函數sayHello()中的text變量。
例2
function sayHello2(name)
{var text = 'Hello ' + name; // 局部變量var sayAlert = function() { console.log(text); }return sayAlert;
}var say2 = sayHello2("Jane");
say2(); // 輸出"Hello Jane"
例3
function buildList(list) {var result = [];for(var i = 0; i < list.length; i++) {var item = 'item' + list[i];result.push( function() {console.log(item + ' ' + list[i]);} );}return result;
}var fnlist = buildList([1,2,3]);
for (var j = 0; j < fnlist.length; j++) {fnlist[j]();
}
得到的結果:連續輸出3個"item3 undefined"
解析:通過執行buildList函數,返回了一個result,那么這個result存放的是3個匿名函數。然而這三個匿名函數其實就是三個閉包,因為它可以訪問到父函數的局部變量。所以閉包內的保留的i是最終的值為3.所以list[3]肯定是undefined. item變量值為item3.
改成如下代碼:
function buildList(list) {var result = [];for(var i = 0; i < list.length; i++) {var item = 'item' + list[i];result.push( (function(i) {console.log(item + ' ' + list[i]);})(i));}return result;
}var fnlist = buildList([1,2,3]);
得到的結果:
item1 1
item2 2
item3 3
解釋:這兒雖然傳遞了一個數組進去,但是返回的是三個自執行的函數。
例4
function newClosure(someNum, someRef)
{var anArray = [1,2,3];var num = someNum;var ref = someRef;return function(x) {num += x;anArray.push(num);console.log('num: ' + num + "; " + 'anArray ' + anArray.toString() + "; " + 'ref.someVar ' + ref.someVar);}
}
closure1 = newClosure(40, {someVar: "closure 1"});
closure2 = newClosure(1000, {someVar: "closure 2"});
closure1(5); // 打印"num: 45; anArray 1,2,3,45; ref.someVar closure 1"
closure2(-10); // 打印"num: 990; anArray 1,2,3,990; ref.someVar closure 2"
每次調用newClosure()都會創建獨立的閉包,它們的局部變量num與ref的值并不相同。
例5
function sayAlice()
{var sayAlert = function() { console.log(alice); }var alice = 'Hello Alice';return sayAlert;
}var sayAlice2 = sayAlice();
sayAlice2(); // 輸出"Hello Alice"
alice變量在sayAlert函數之后定義,這并未影響代碼執行。因為返回函數sayAlice2所指向的閉包會包含sayAlice()函數中的所有局部變量,這自然包括了alice變量,因此可以正常打印”Hello Alice”。
例6
function setupSomeGlobals() {var num = 666;gAlertNumber = function() { console.log(num); }gIncreaseNumber = function() { num++; }gSetNumber = function(x) { num = x; }
}
setupSomeGlobals();
gAlertNumber(); // 輸出666
gIncreaseNumber();
gAlertNumber(); // 輸出667
gSetNumber(5);
gAlertNumber(); // 輸出5
解釋:首先gAlertNumber,gIncreaseNumber,gSetNumber是三個全局變量,并且其三個值都是匿名函數,然而這三個匿名函數本身都是閉包。他們操作的num都是保存在內存中的同一個num,所有會得出上面的結果。
6.a.info.name 為jack,b.info.name為tom。原因我想你從第三題已經得出來了。
5.JS重復輸出一個給定的字符串
如下:
重復輸出一個給定的字符串(str第一個參數)n 次 (num第二個參數),如果第二個參數num不是正數的時候,返回空字符串。
function repeatStringNumTimes(str, num) {return str;
}
repeatStringNumTimes("abc", 3);
提供測試情況:
repeatStringNumTimes("*", 3) //應該返回 "***".
repeatStringNumTimes("abc", 3) //應該返回 "abcabcabc".
repeatStringNumTimes("abc", 4) //應該返回 "abcabcabcabc".
repeatStringNumTimes("abc", 1) //應該返回 "abc".
repeatStringNumTimes("*", 8) //應該返回 "********".
repeatStringNumTimes("abc", -2) //應該返回 "".
解題思路
我將介紹三種方法:
- 1.使用
while
循環 - 2.使用遞歸
- 3.使用ES6
repeat()
方法1:通過 while
循環重復輸出一個字符串
function repeatStringNumTimes(string, times) {var repeatedString = "";while (times > 0) {repeatedString += string;times--;}return repeatedString;
}
repeatStringNumTimes("abc", 3);
不過這里還可以有幾個變種:
對于老前端來說,首先一個可能會將字符串拼接,修改為 數組join()拼接字符串,例如:
function repeatStringNumTimes(string, times) {var repeatedArr = []; //while (times > 0) {repeatedArr.push(string);times--;}return repeatedArr.join("");
}
repeatStringNumTimes("abc", 3)
很多老前端都有用數組join()拼接字符串的“情懷”,因為很早以前普遍認為數組join()拼接字符串比字符串+拼接速度要快得多。不過現在未必,例如,V8 下+拼接字符串,要比數組join()拼接字符串快。我用這兩個方法測試了3萬次重復輸出,只相差了幾毫秒。
另一個變種可以用 for 循環:
function repeatStringNumTimes(string, times) {var repeatedString = "";for(var i = 0; i < times ;i++) {repeatedString += string;}return repeatedString;
}
repeatStringNumTimes("abc", 3)
方法2:通過條件判斷和遞歸重復輸出一個字符串
遞歸是一種通過重復地調用函數本身,直到它達到達結果為止的迭代操作的技術。為了使其正常工作,必須包括遞歸的一些關鍵特征。
function repeatStringNumTimes(string, times) {if(times < 0) return "";if(times === 1) return string;else return string + repeatStringNumTimes(string, times - 1);
}
repeatStringNumTimes("abc", 3);
方法3:使用ES6 repeat()
方法重復輸出一個字符串
這個解決方案比較新潮,您將使用 String.prototype.repeat() 方法:
repeat() 方法構造并返回一個新字符串,該字符串包含被連接在一起的指定數量的字符串的副本。 這個方法有一個參數 count 表示重復次數,介于0和正無窮大之間的整數 : [0, +∞) 。表示在新構造的字符串中重復了多少遍原字符串。重復次數不能為負數。重復次數必須小于 infinity,且長度不會大于最長的字符串。
function repeatStringNumTimes(string, times) {if (times > 0)return string.repeat(times);elsereturn "";
}
repeatStringNumTimes("abc", 3);
您可以使用三元表達式作為 if/else 語句的快捷方式,如下所示:
function repeatStringNumTimes(string, times) {return times > 0 ? string.repeat(times) : "";
}
repeatStringNumTimes("abc", 3);
轉載地址:http://www.css88.com/archives/7045
6.函數聲明相關
var x=1,y=0,z=0;
function add(n){n=n+1;
}
y=add(x);
z=x+y;
console.log("y1:"+y);
console.log("z1:"+z);function add(n){n=n+3;
}
y=add(x);
z=x+y;
console.log("y2:"+y);
console.log("z2:"+z);
求y,z的值。
結果為:
y1:undefined
z1:NaN
y2:undefined
z2:NaN
變化一下:
var x=1,y=0,z=0;
function add(n){return n=n+1;
}
y=add(x);
z=x+y;
console.log("y1:"+y);
console.log("z1:"+z);function add(n){return n=n+3;
}
y=add(x);
z=x+y;
console.log("y2:"+y);
console.log("z2:"+z);
求y,z的值
答案:
y1:4
z1:5
y2:4
z2:5
7.作用域范圍(Scope)
思考以下代碼:
(function(){var a = b = 5;
})();
console.log(b);
控制臺(console)
會打印出什么?
答案
上述代碼會打印出5
。
這個問題的陷阱就是,在立即執行函數表達式(IIFE)中,有兩個命名,但是其中變量是通過關鍵詞var來聲明的。這就意味著a是這個函數的局部變量。與此相反,b是在全局作用域下的。
這個問題另一個陷阱就是,在函數中他沒有使用"嚴格模式
" ('use strict';)。如果 嚴格模式 開啟,那么代碼就會報出未捕獲引用錯誤(Uncaught ReferenceError
):b沒有定義。記住,嚴格模式要求你在需要使用全局變量時,明確地引用該變量。因此,你需要像下面這么寫:
(function(){'use strict'var a = window.b = 5;
})();
console.log(b);
再看如下一個例子:
var a = 6;
setTimeout(function () {alert(a);a = 666;
}, 1000);
a = 66;
結果:66
8.創建 “原生(native)” 方法
在String
對象上定義一個repeatify
函數。這個函數接受一個整數參數,來明確字符串需要重復幾次。這個函數要求字符串重復指定的次數。舉個例子:
console.log('hello'.repeatify(3));
應該打印出hellohellohello
.
答案:
String.prototype.repeatify = String.prototype.repeatify || function(times){var str = '';for(var i = 0; i < times; i++){str += this;}return str;
};
這個問題測試了開發人員對于JavaScript中繼承的掌握,以及prototype
這個屬性。這也驗證了開發人員是否有能力擴展原生數據類型的功能(雖然不應該這么做)。
這個問題的另一個重點是驗證你是否意識到并知道如何避免覆蓋已經存在的函數。這可以通過在自定義函數之前判斷該函數是否存在來做到。
String.prototype.repeatify = String.prototype.repeatify || function(times){/*code here*/
};
當你需要為舊瀏覽器實現向后兼容的函數時,這一技巧十分有用。
9.變量提升(Hoisting)
執行以下代碼會有什么結果?為什么?
function test(){console.log(a);console.log(foo());var a = 1;function foo(){return 2;}
}
test();
答案
這段代碼的執行結果是 undefined
和 2
。
這個結果的原因是,變量和函數都被提升了(hoisted)。因此,在a被打印的時候,它已經在函數作用域中存在(即它已經被聲明了),但是它的值依然是 undefined。換言之,上述代碼和以下代碼是等價的。
function test(){var a;function foo(){return 2;}console.log(a);console.log(foo());a = 1;}
test();
再看如下代碼:
(function() {console.log(typeof foo); console.log(typeof bar); var foo = 'hello',bar = function() {return 'world';};function foo() {return 'hello';}}());
結果:
function
undefined
10.this 在 JavaScript 中是如何工作的
以下代碼的結果是什么?請解釋你的答案。
var fullname = 'John Doe';
var obj = {fullname: 'Colin Thrig',prop: {fullname: 'Aurelio De Rosa',getFullname: function(){return this.fullname;}}
};console.log(obj.prop.getFullname());var test = obj.prop.getFullname;console.log(test());
答案
上面的代碼打印出 Aurelio De Rosa
和 John Doe
。原因是在 JavaScript 中,一個函數的上下文環境,也就是this關鍵詞所引用對象,是依賴于函數是如何被調用的,而不是依賴于函數如何被定義的。
在第一個 console.log() 調用中, getFullname() 是作為 obj.prop 的函數被調用的。因此,這里的上下文環境指向后者并且函數返回this對象的 fullname 屬性。相反,當 getFullname() 被賦為test變量的值時,那個語境指向全局對象(window)。這是因為,test 被隱式設置為全局對象的屬性。因此,函數調用返回 window 的 fullname 屬性值,在此段代碼中,這個值是通過第一行賦值語句設置的。
11.call() 和 apply()
修復上一個問題,讓最后一個 console.log() 打印出 Aurelio De Rosa。
要解決這個問題,可以通過為函數 call() 或者 apply() 強制函數調用的上下文環境。如果你不知道 call() 和 apply() 之間的區別,在以下代碼中,我會用 call(),但是在這里,用 apply() 也可以獲得相同的結果:
console.log(test.call(obj.prop));
12.閉包(Closures)
考慮下面的代碼:
var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {nodes[i].addEventListener('click', function() {console.log('You clicked element #' + i);});
}
請問,如果用戶點擊第一個和第四個按鈕的時候,控制臺分別打印的結果是什么?為什么?
答案:
兩次打印都是nodes.length
的值。
那么修復上題的問題,使得點擊第一個按鈕時輸出0,點擊第二個按鈕時輸出1,依此類推。
有多種辦法可以解決這個問題,下面主要使用兩種方法解決這個問題。
第一個解決方案使用立即執行函數表達式(IIFE
)再創建一個閉包,從而得到所期望的i的值。實現此方法的代碼如下:
var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {nodes[i].addEventListener('click', (function(i) {return function() {console.log('You clicked element #' + i);}})(i));
}
另一個解決方案不使用IIFE,而是將函數移到循環的外面。這種方法由下面的代碼實現:
function handlerWrapper(i) {return function() {console.log('You clicked element #' + i);}
}var nodes = document.getElementsByTagName('button');
for (var i = 0; i < nodes.length; i++) {nodes[i].addEventListener('click', handlerWrapper(i));
}
代碼片段一:
var name = "The Window";
var object = {name : "My Object",getNameFunc : function(){return function(){return this.name;};}};
alert(object.getNameFunc()());
結果:The Window
代碼片段二:
var name = "The Window";
var object = {name : "My Object",getNameFunc : function(){var that = this;return function(){return that.name;};}
};alert(object.getNameFunc()());
結果:My Object
文章地址:http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
13.數據類型問題
考慮如下代碼:
console.log(typeof null);
console.log(typeof {});
console.log(typeof []);
console.log(typeof undefined);
答案:
object
object
object
undefined
14.事件循環
下面代碼運行結果是什么?請解釋。
function printing() {console.log(1);setTimeout(function() { console.log(2); }, 1000);setTimeout(function() { console.log(3); }, 0);console.log(4);
}
printing();
答案:
1
4
3
2
想知道為什么輸出順序是這樣的,你需要弄了解setTimeout()
做了什么,以及瀏覽器的事件循環原理。瀏覽器有一個事件循環用于檢查事件隊列,處理延遲的事件。UI事件(例如,點擊,滾動等),Ajax回調,以及提供給setTimeout()
和setInterval()
的回調都會依次被事件循環處理。因此,當調用setTimeout()
函數時,即使延遲的時間被設置為0,提供的回調也會被排隊。回調會呆在隊列中,直到指定的時間用完后,引擎開始執行動作(如果它在當前不執行其他的動作)。因此,即使setTimeout()
回調被延遲0毫秒,它仍然會被排隊,并且直到函數中其他非延遲的語句被執行完了之后,才會執行。
15.算法問題
寫一個isPrime()
函數,當其為質數時返回true
,否則返回false
。
答案:
我認為這是面試中最常見的問題之一。然而,盡管這個問題經常出現并且也很簡單,但是從被面試人提供的答案中能很好地看出被面試人的數學和算法水平。
首先, 因為JavaScript不同于C或者Java,因此你不能信任傳遞來的數據類型。如果面試官沒有明確地告訴你,你應該詢問他是否需要做輸入檢查,還是不進行檢查直接寫函數。嚴格上說,應該對函數的輸入進行檢查。
第二點要記住:負數不是質數。同樣的,1和0也不是,因此,首先測試這些數字。此外,2是質數中唯一的偶數。沒有必要用一個循環來驗證4,6,8。再則,如果一個數字不能被2整除,那么它不能被4,6,8等整除。因此,你的循環必須跳過這些數字。如果你測試輸入偶數,你的算法將慢2倍(你測試雙倍數字)。可以采取其他一些更明智的優化手段,我這里采用的是適用于大多數情況的。例如,如果一個數字不能被5整除,它也不會被5的倍數整除。所以,沒有必要檢測10,15,20等等。
最后一點,你不需要檢查比輸入數字的開方還要大的數字。我感覺人們會遺漏掉這一點,并且也不會因為此而獲得消極的反饋。但是,展示出這一方面的知識會給你額外加分。
現在你具備了這個問題的背景知識,下面是總結以上所有考慮的解決方案:
function isPrime(number) {// If your browser doesn't support the method Number.isInteger of ECMAScript 6,// you can implement your own pretty easilyif (typeof number !== 'number' || !Number.isInteger(number)) {// Alternatively you can throw an error.return false;}if (number < 2) {return false;}if (number === 2) {return true;} else if (number % 2 === 0) {return false;}var squareRoot = Math.sqrt(number); //平方根,比如Math.sqrt(9)為3for(var i = 3; i <= squareRoot; i += 2) {if (number % i === 0) {return false;}}return true;
}
其中代碼中用到了Number.isInteger()
,該方法是ES6
方法,用來判斷一個值是否為整數。
例如:
Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false
Number.isInteger("15") // false
Number.isInteger(true) // false
需要注意的是,在JavaScript內部,整數和浮點數是同樣的儲存方法,所以
25
和25.0
被視為同一個值。
16.記騰訊一次糟糕的筆試面試經歷(轉)
JS考察
1、基本數據類型:undefined、null、String、Number、boolean
。
2、有以下兩個函數,定義一個對象使其擁有這兩個函數屬性。
function mobile(){return 'mobile';
}
function phone(){return 'phone';
}
var a = {};
a.mobile = mobile();
a.phone = phone();
console.log(a);
3、(考察了對象變量和堆內存)
var a = {n:10,m:20};
var b = a;
b.n = 30;
console.log(a.n);
console.log(b);
結果:
30
Object {n: 30, m: 20}
4、(考察閉包)
var x = 20;
var a = {x : 15,fn : function(){var x = 30;return function(){return this.x;};}
};
console.log(a.fn());
console.log((a.fn())());
console.log(a.fn()());
console.log(a.fn()() == (a.fn())());
console.log(a.fn().call(this));
console.log(a.fn().call(a));
結果:
1)、function(){return this.x;}
2)、20
3)、20
4)、true
5)、20
6)、15
5、(數組去重復項)
var arr = ['a','g','q','d','a','e','q'];
Array.prototype.unique = function(){for(var i = 0; i < this.length; i++){for(var j = i+1; j < this.length; j++){if(this[i] == this[j]){this.splice(j,1);}}}return this;
};
console.log(arr.unique());
此方法有缺陷,比如var arr = ['a','a','a','g','q','d','a','e','q']
; 那么得到的結果:["a", "a", "g", "q", "d", "e"]
。知道原因吧?不知道請查看數組去重的方法《JS基礎篇--JS實現數組去重方法整理》
6、編寫一個函數fn(Number n)
,將數字轉為大寫輸出,如輸入123,輸出一百二十三
function fn(n){if(!/^([1-9]\d*)/.test(n)){return '非法數據';}var unit = '千百十億千百十萬千百十個';if(n.length > unit.length){return '數據過長';}var newStr = '';var nlength = n.length;unit = unit.substr(unit.length - nlength);for(var i = 0; i < nlength; i++){newStr += '零一二三四五六七八九'.charAt(n[i]) + unit.charAt(i);}newStr = newStr.substr(0,newStr.length-1);newStr = newStr.replace(/零(千|百|十)/g,'零').replace(/(零)+/g,'零').replace(/零(億|萬)/g,'$1');return newStr;
}
console.log(fn('205402002103'));
CSS
1、考察了盒子模型
2、內聯元素、塊元素
3、css3的貝塞爾曲線(張鑫旭大神的解說)
4、彈性盒子flexbox
綜合考察
1、js跨域問題
算法考察
1、有36輛自動賽車和6條跑道,沒有計時器的前提下,最少用幾次比賽可以篩選出最快的三輛賽車?
2、一面墻,單獨工作時,A花18小時砌好,B花24小時,C花30小時,現A, B, C的順序輪流砌,每人工作1小時換班,完工時,B總共干了多少小時?
- 9小時
- 8小時
- 7小時
- 6小時48分
答案:B,C
原因:
按照A,BC輪流砌,沒有說明誰先開始。
1/18 + 1/24 + 1/30 = 47/360;
共同完成7小時:7*47/360 = 329/360,還差31/360;
如果A先砌:則B砌了7小時44分鐘。
如果B先砌:則B砌了8小時。
如果C先砌:則B砌了7小時。
17.語義化標簽
1)tite與h1的區別
2)b與strong的區別
3)i與em的區別PS:不要小看這些題,80%人答不上來
title與h1的區別
定義:title是網站標題,h1是文章主題
作用:title概括網站信息,可以直接告訴搜索引擎和用戶這個網站是關于什么主題和內容的,是顯示在網頁Tab欄里的;h1突出文章主題,面對用戶,更突出其視覺效果,指向頁面主體信息,是顯示在網頁中的。
b與strong的區別
定義:b(bold)是實體標簽,用來給文字加粗,而strong是邏輯標簽,作用是加強字符語氣
區別:b標簽只是加粗的樣式,沒有實際含義,常用來表達無強調或著重意味的粗體文字,比如文章摘要中的關鍵詞、評測文章中的產品名稱、文章的導言; 而strong表示標簽內字符重要,用以強調,其默認格式是加粗,但是可以通過CSS添加樣式,使用別的樣式強調。
建議:為了符合CSS3的規范,b應盡量少用而改用strong
i與em的區別
定義:i(italic)是實體標簽,用來使字符傾斜,而em(emphasis)是邏輯標簽,作用是強調文本內容
區別:i標簽只是斜體的樣式,沒有實際含義,常用來表達無強調或著重意味的斜體,比如生物學名、術語、外來語(比如「de facto」這樣的英語里常用的拉丁語短語);而em表示標簽內字符重要,用以強調,其默認格式是斜體,但是可以通過CSS添加樣式
建議:為了符合CSS3的規范,i應盡量少用而改用em
下面擴展一些其它的標簽屬性區別:
img中的alt與title屬性
alt
屬性是在你的圖片因為某種原因不能加載時在頁面顯示的提示信息,它會直接輸出在原本加載圖片的地方
title
屬性是在你鼠標懸停在該圖片上時顯示一個小提示,鼠標離開就沒有了,有點類似jQuery的hover
src與href的區別
定義:href指定網絡資源的位置建立鏈接或關系,用在link和a等元素上。src將外部資源嵌入到當前標簽所在位置,如img圖片和js腳本等
區別:我們在可替換的元素上使用src,然而把href用于在涉及的文檔和外部資源之間建立一個關系。 瀏覽器解析src屬性時,會暫停其他資源的下載和處理,直至將該資源加載,編譯,執行完畢。 瀏覽器解析到href的時候會識別該鏈接內容,對其進行下載不會停止對當前文檔的處理
18.事件綁定相關
addEventListener
,第三個參數是用來表示事件是以事件冒泡還是事件捕獲這個各位都知道!但是他問的問題是:
我們給一個dom同時綁定兩個點擊事件,一個用捕獲,一個用冒泡,你來說下會執行幾次事件,然后會先執行冒泡還是捕獲!!!
來吧,誰能說出來。。。。
19.CSS選擇器問題
考察優先級問題,反正會出很多莫名其妙的變形,比如將style標簽寫在body后與body前有什么區別,比如同一dom應用多個class其應該如何表現,比如class a定義顏色為blue,class b定義顏色為red,同時應用到dom上,dom作何顯示。。。
好吧各位去回答吧。。。。。
20.一段關于JS中this應用奇葩代碼引發的思考
function DemoFunction(){this.init = function(){var func = (function(va){this.va = va;return function(){va += this.va;return va;}})(function(va1, va2){var va3 = va1 + va2;return va1;}(1,2));console.log(func(20));this.func = func;console.log(this.func(100));}
}
var a = new DemoFunction();
a.init();
首先我們得有如下幾個概念:
- 執行上下文:每次當控制器轉到ECMAScript可執行代碼時,即會進入一個可執行上下文,參考文獻:深入理解JavaScript系列(11):執行上下文(Execution Contexts)
- this:this的創建是在 “進入執行上下文” 時創建的,在代碼執行過程中是不可變的,參考文獻:深入理解JavaScript系列(13):This? Yes,this!
- 自執行函數:準確來說應該叫:立即調用函數表達式。因為他聲明后即執行,參考文獻:深入理解JavaScript系列(4):立即調用的函數表達式
詳細解釋此段代碼
一、首先看DemoFunction的構造函數
這是代碼的重點,第一層代碼可以縮減為如下:
function DemoFunction(){this.init = function(){//省略代碼....}
}
表示為DemoFunction的實例提供init方法(聲明:此處有誤導成份,方法應盡可能放在原型鏈接上,也就是prototype上。),對外公開的接口。
二、在init方法中,再次省略代碼如下:
var func = (function(va){this.va = va;return function(){va += this.va;return va;}
})(/*省略代碼...*/);//省略代碼....
上面代碼介紹:
- 首先定義了一個立即執行函數,并把此函數的執行結果賦值給func。
- 需要注意立即執行函數中this.va=va這行代碼,由于立即執行函數沒有調用者,所以在進入可執行上下文時,this會被賦值為Global(瀏覽器中為window對象)。
- 更需要注意立即執行函數,返回的是一個匿名函數,也是一個閉包,在這里一定要注意一個問題:this是在進入可執行上下文時創建的。
三、在init方法中,注意如下代碼:
var func = (function(va){this.va = va;return function(){va += this.va;return va;}
})(function(va1, va2){var va3 = va1 + va2;return va1;
}(1,2));
//省略代碼....
va的實際參數是一個自執行匿名函數,這個匿名函數接受了兩個參數va1,va2,但只返回了va1。以此為據,那么可以確定va的值也就為1。接著就執行this.va=va這句代碼,由于當前this為window,所以參數va的值被賦值到了window的一個叫va的屬性上。
四、在init方法中,加上輸出語句:
var func = (function(va){this.va = va;return function(){va += this.va;return va;}})(function(va1, va2){var va3 = va1 + va2;return va1;}(1,2));console.log(func(20));this.func = func;console.log(this.func(100));
}
結果分析:
- 第一個console.log輸出的是func(20),這里一定要注意調用者是沒有具體指定的,此時默認的就是Global(也就是widnow對象),因此輸出為:2
- 第二個console.log輸出的是this.func(100),可以看到this.func與func是指向同一個函數的引用,但此時的調用者則指定為this,也就是當前對象的實例,因此輸出為:NaN。原因:this(當前對象的實例)作為調用者,在func的函數中va += this.va這句代碼中的this是指向當前對象的實例,但當前對象的實例上是沒有va屬性的。但是va是有值的,當前值為2了。是因為閉包把va值存到內存中了。那么如何讓第二次得到的值也是2呢,結果很簡單,如下:
function DemoFunction(){this.va = 0;this.init = function(){var func = (function(va){this.va = va;return function(){va += this.va;return va;}})(function(va1, va2){var va3 = va1 + va2; return va1;}(1,2));console.log(func(20));this.func = func;console.log(this.func(100));}}var a = new DemoFunction();a.init();