最近看到有人分享16屆前端進阿里(前端學習群的群主),17屆前端杭州收割offer(優秀的路人)。剛好同為17屆的我最近也很輕松拿了2個offer,但是我看到他們寫的題目回答并不是很詳細,所以強迫癥的我也想來和大家分享下,我會把所有沒掛掉的和掛掉的都分享出來lol客戶端組件加載中請耐心等待,遇到的每一道題目都做詳細的分析,所以文章有點長哦。
長文慎入哈,但是有酒有故事,小板凳我都給你搬好啦,快坐下!
故事開始咯~
本來想等過完年回來再換工作的,但是前段時間有獵頭在簡書私信我,說看我的文章寫得還行,問我想不想換工作。 然后我就更新了簡歷,發過去了,邀請我面試,但是這家公司在北京 /西安,后來就沒去,但是故事就此開始了,這反而促使我走上了換工作的道路。
貼一下自認為寫得不錯的幾篇文章:
??CSS3動畫卡頓性能優化解決方案??
??深度剖析0.1 +0.2===0.的原因??
??如何解決0.1 +0.2===0.類問題??
??記一次簡單的DOM XSS攻擊實驗??
??你真的理解==和===的區別嗎???
??經典CSS坑:如何完美實現垂直水平居中???
自己從大三暑假實習到現在工作半年多,接近快1.5+年的時間,一門心思扎到前端開發領域,高強度式的工作和學習,買書啃書,寫代碼看代碼,寫博客看博客,提問題回答問題,投入了幾乎是大一到大三學習時間總和的時間學習前端開發。
最近陰差陽錯開始筆試,面試,雖然都沒怎么準備,但是很輕松就收獲了一家阿里出來創業的公司,一家浙大系公司的offer,再加上昨天被第三家面試官的贊賞,之前的妄自菲薄一下煙消云散。
由于自己這次換工作,希望能夠在一家公司呆至少2年以上,非常希望能和一幫對前端技術有見解有思考有追求的小伙伴們,一起去探索鉆研有趣的前端世界。所以我決定嘗試更多的面試,加入到一個更適合自己的團隊。
同時也希望通過這篇面試分享,能夠給和我一樣努力的前端小伙伴們一些鼓勵,也希望能夠把最真實的自己展現給大家。
面試1 - 天道酬勤,付出終有回報
拒絕了第一家主動找到我的公司后,又有家阿里子創業公司在 BOSS 直聘里私信我,然后抱著測試水平的心態面了。現場筆試不怎么樣,但是他們看到我簡書文章還算可以,就讓我重做了一遍題目: ??一些特別棒的面試題[0]??, 最后一道單詞與字符串匹配的題的拓展,都是面試官一步步引導我去深入的lol客戶端組件加載中請耐心等待,感覺學習到很多。
沒想到結果是比較讓人驚喜的,前輩說我的學習能力比較強,所以愿意給我這個機會,給的薪資比現在高 2K,關鍵是聽說有許多項目可以做,據說面試我的老板以前也是在阿里的技術專家。
貼一下面試題和我的回答。
1.說一下你熟悉的設計模式
2.說一下你理解的模塊機制
3.MVVM原理
4.最熟悉的框架路由機制
5.狀態管理
6.統計字符串中單詞出現次數
1.說一下你熟悉的設計模式
我最熟悉的設計模式:工廠模式(ES5),組件設計模式(ES6)工廠模式(ES5,基于。此例中基類Base,子類)
var Factory = function () {
if(!(this instanceof Factory)){
return new Factory();
}
}
Factory.prototype = Object.assign(new Base(), {
version: '0.0.1',
defaultOption:{
title:'標題'
},
init:function (cfg) {
this.title = cfg.title || '';
this.currentOption = Object.assign(this.defaultOption,{
//...
})
},
render: function () {
var option = this.currentOption;
this.chart.setOption(option);
},
showTitle: function () {
this._showTitle();
}
})
組件設計模式(ES6,基于class,方便繼承和初始化,也是React組件的推薦寫法,我比較喜歡。此例中父類,子類)
class Retrive extends Component {
constructor (props) {
super(props);
this.state = {
name:''
};
this.getRemoteData = this.getRemoteData.bind(this);
}
getRemoteData (data) {
this.state.retriveResult = data;
}
render(){
return (
);
}
}
2.說一下你理解的模塊機制
AMD: 異步模塊加載規范。a.js,定義一個依賴和的組件。
define(['jquery', 'echarts'], function ($, echarts) {
var AMD = function(){}
AMD.prototype = {
title:'',
foo: function(){}//AMD類或者繼承AMD類的子類的屬性
}
function bar(){}//返回,公共屬性
function baz(){} //未返回,私有屬性
return {
main:AMD,
bar: bar
}
});
如果b.js依賴a.js,可以這樣
define(['./a'], function (a) {
//調用構造函數,foo
var instance_amd = new a.main();
instance_amd.foo()
//調用bar
a.bar()
});
ES6 : 和的包機制很類似,導入,導出。
1.場景:vue,react推薦機制,需要babel轉義成es5以兼容瀏覽器。
2.關于import...(from...)
①.import...from...的from命令后面可以跟很多路徑格式,若只給出vue,axios這樣的包名,則會自動到node_modules中加載;若給出相對路徑及文件前綴,則到指定位置尋找。
②.可以加載各種各樣的文件:.js、.vue、.less等等。
③.可以省略掉from直接引入。
3.關于export
①.導出的可以是對象,表達式,函數,類
②.導出是為了讓別人導入
4.言外話:使用es6的話,有一個特別好的規范去遵守,airbnb的es6規范(https://github.com/airbnb/javascript)
:中使用較多,關鍵詞是,沒寫過node包,只引用過別人的模塊,所以內部實現原理不是很清楚。
3.MVVM原理
MVVM是一種軟件架構模式,MVVM有助于前后端分離。View:視圖層,粗略理解為DOM。Model:與數據庫對應的model,一般為json格式,作為req的body通過http(s)與數據庫實現通信。:View與Model通過實現雙向綁定。
核心是提供對View和的雙向數據綁定,這樣使得的改變View立即變化,MVVM在前端的實現有:,vue,react。
vue中的常用數據雙向綁定。
view:{{message}}
viewModel v-model="message"
model:message
{{ message }}
var app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
})
單文件組件中的話,就多了一個用html5的標簽將view和包裹起來,model部分停留在標簽部分。
view
viewModel
<script>
model
</script>
為了讓view好看點
react的話,我在使用的過程中,沒有聽說過雙向綁定的東西,對redux 推薦寫為純函數印象深刻,純函數的話,感覺應該有點單項數據流的意思。
既然說到框架了,說一個最讓我感覺有趣的點,那就是組件間的通信,對于簡單組件,只涉及父子級別的通信的,vue使用on emit的方式,react使用props。對于復雜級別通信,爺爺父親兒子孫子等等時,vue推薦使用vuex,react推薦使用redux,統一的全局狀態樹用來做狀態管理非常好,可以使得邏輯非常清晰。vue項目文件結構研究不深,react的項目文件結構的話,和的設計方法感覺非常有道理,一個負責視圖一個負責數據,非常清爽。
4.最熟悉的框架路由機制
vue路由依賴:vue-通過組合組件來組成單頁應用程序,只需要將組件映射到路由即可。前端路由的核心,就在于 —— 改變視圖的同時不會向后端發出請求。需要注意2種模式的區別:hash模式和模式,hash模式會在后面加一個很丑的#,可以開啟去掉。hash模式原理:它的特點在于:hash 雖然出現在 URL 中,但不會被包括在 HTTP 請求中,對后端完全沒有影響,因此改變 hash 不會重新加載頁面。hash可以理解為錨點,例如./index.html/#/foo,hash值為#/foo,這樣不會跳轉頁面。就相當于統一頁面的不同錨點,頁面間跳轉與 ./index.html/#foo到./index.html/#bar類似。
./store/index.js
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/common',
name: 'common',
component: Common
}
]
路由層面還會包括嵌套路由,動態路由以及重定向,相當于自己模仿瀏覽器請求然后服務器響應模式,其實不涉及向后端請求,僅在瀏覽器就可以實現頁面跳轉,前段時間我做的用戶權限控制就用到了vue-,相比MVC結構下的后端路由,清晰了不少,這樣后端只要負責路由編寫api就好。
5.狀態管理
下面是我在用vuex做項目時的一些思考,簡單修改了一下,也添加了一些關于redux的思考。
,前端,前端,用戶操作,引起data變化從而導致DOM變化。
多個組件(視圖)共享狀態:通俗來講,就是多個組件間會通信時,導致從后端拿來的數據發生變化,當組件較多時,如果兄弟組件間的通信都依賴父組件進行通信,會導致組件間的耦合非常高,從而導致項目邏輯混亂,難以維護。
多個組件(視圖)依賴于同一狀態。來自不同視圖的行為需要變更同一狀態。
全局單例模式管理,把組件的共享狀態抽取出來不管在組件樹的哪個位置,任何組件都能獲取狀態或者觸發行為!
實踐出真知:
1.state存放在index.js中,創建的Store實例getter,mutations,actions等,可以分離出來
2.getters存放在getter.js中,數據流為state→getter→組件,getter相當于一個數據獲取過濾器,從倉庫拿特定數據到組件,相當于對computed的集中處理。
3.mutations存放在mutations.js中,數據流為組件→mutations→state,mutations相當于一個數據提交發射器,從組件提交數據到倉庫
4.actions存放在actions.js中,數據流為組件→actions→mutations→state,異步操作的主要場所。
5.modules是開發大型應用時需要用到的,每個module都有單獨的states,getters,actions以及mutation,有一股nodejs模塊的味道。
vuex三原則:
1.唯一數據源
2.保持狀態只讀
3.數據改變只能通過純函數完成 更改 Vuex 的 store 中的狀態的唯一方法是提交 mutation。
一定要注意和的區別!
只變更本地的狀態,也就是說,直接只去修改store中的數據。包含異步操作,直接調用api,通過api的數據,再提交。
可以說,只比多了一個異步調用api的操作,因為調用api后,一般有2種返回結果,或者error,或者是的多種狀態,根據不同的。
最近在學習redux,組件一個到store,相當于發送一個http請求,然后store做出響應,返回一個給組件。和vuex大致類似,唯一有區別的是,vuex還需要引入react-redux,引入和連接組件和store。
6.統計字符串中單詞出現次數
" hi how are you i am fine thank you am am ",統計"you"出現的次數。
function wordCount(str,word){
var str = str || "";
var word = word || "";
var strArr = str.split(" ");
var count = 0;
for(var i=0;iif(word===strArr[i]){
count++
}
}
return count;
}
wordCount("hi how are you i am fine thank you youtube am am","you");
如果字符串沒有空格怎么辦?
function wordCount(str,word){
var str = str || "";
var word = word || "";
var count = 0;
var index = str.indexOf(word);
while(index!==-1){
count++;
str = str.substr(index+word.length);
index = str.indexOf(word)
}
return count;
}
wordCount("hihowareyouiamfinethankyouyoutubeamam","you");
如果不用js內置字符串函數,自己用每個字符對比呢?
function wordCount(str,word){
var num = 0;
var str = str+" " || "";
var word = word || "";
var strArr = str.split("");
var wordArr = word.split("");
var count = 0;
function compare(arr1,a,arr2,b){
if(b+a if(arr1[a]===arr2[b+a]){
num++;
return compare(arr1,a+1,arr2,b+1)
}
if(num===arr1.length){
count++
num = 0;
}
}
}
for(var i=0;ifor(var j=0;j if(wordArr[wordArr.length-1]===strArr[i+wordArr.length-1]){
compare(wordArr,0,strArr,i+0)
}
}
}
return count;
}
wordCount("hihowareyouiamfinethankyouyoutubeamam","am");
可以更加高效一些嗎?
function wordCount (str,word) {
var str = str+" " || "";
var word = word || "";
var strArr = str.split("");
var wordArr = word.split("");
var wordArrLen = wordArr.length;
var count = 0;
var num = 0;
function compare (arr1,a,arr2,b) {
if(b+a if(arr1[a]===arr2[b+a]){
num++;
return compare(arr1,a+1,arr2,b+1)
}
if(num===arr1.length){
count++;
num = 0;
}
}
}
var j = 0;
while(jvar i = 0;
while(iif(wordArr[wordArrLen -1]===strArr[i+wordArrLen -1]){
compare(wordArr,0,strArr,i+0);
}
i++;
}
j++;
}
return count;
}
wordCount("hihowareyouiamfinethankyouyoutubeamam","a");
//1.調整最高層級遍歷數組,從37的2次方降到3的2次方,從1369降到9
//2.合并控制變量和控制條件,使用while替代for,去除JS引擎查詢i,j是否存在的消耗,會稍微降低代碼可讀性
//3.對重復引用的wordArr.length,賦值給局部變量wordArrLen,在這里,Array.prototype.length的查詢次數從3次降低到1次
面試2 - 莫愁前路無知己,天下誰人不識君
我本來就不想再繼續找了,但是今天朋友給我一個建議,跳槽前多投幾家,說不定可以找到更好的,然后我就想到 V 站上看到好多求職貼,所以就索性再試試看有沒有更好的坑。
簡歷: ??前端開發-簡書-趁你還年輕233??
簡書 : ??趁你還年輕233??
: ????
:??趁你還年輕??
坐標:杭州
然后我在V站上發了貼,很有緣分,一個V友加了我的好友,約好時間進行了一次電話面試,后面了解好公司技術氛圍和商議好薪資待遇后,成功拿到了offer,薪資待遇和第一家差不多,這家是浙大系的公司。
我和面試官很聊得來,最后甚至都聊到了吃雞,由于電話面試太愉快了,所以這次電話面試到現在我僅記得一道跨域題了。第三家公司面試官也很贊,天氣寒冷,友情提醒我注意路上冰凍,不過由于第三家面試在明天晚上才進行,所以我把第三家的BOSS直聘題也總結在一起了:??一些特別棒的面試題[1]??
貼一下面試題和我的回答。
1.平時有遇到過跨域問題嗎?
2.下面這段代碼最終輸出什么?
3.["1","2","3"].map(parseInt)返回的是什么?
4.下面代碼中“入庫”的顏色是?
1.平時有遇到過跨域問題嗎?
說到跨域問題,就一定要說到同源,什么是同源,相同協議,相同域名,相同端口,即為同源。
不同源之間的通信就會有跨域問題,一般來說是客戶端訪問服務器,服務器上去配置跨域。我遇到的跨域問題都是后端去配置一下就可以解決的,比如我前端在用vue的官方推薦異步請求庫axios,去請求后端的koa開啟的后端服務時,就會遇到跨域的問題,例如koa使用依賴koa-cors就可以,具體的話,就是--Allow-: 源名,可以為*或者是特殊的源。或者是傳統的maven或者nginx上,也可以很方便的配置跨域。
JSONP有用過嗎?JSONP沒用過,但是原理貌似是通過js加載一個 DOM標簽進來,然后在新的的src中引入想要執行的代碼。其實跨域問題在后端中也有類似的,只不過是叫做進程間通信,有IPC,RPC等等方式進行進程間通信。
2.下面這段代碼最終輸出什么?
let O = function(name){
this.name = name || 'world';
};
O.prototype.hello = function(){
return function(){
console.log('hello ' + this.name);
};
};
let o = new O;
let hello = o.hello();
hello();
年輕的我的答案是:hello world。
答案顯然是不對的,因為這是一道陷阱題,陷阱就在于O..hello調用后,的是一個函數,這么做的話,在執行新實例o的hello方法是,this其實已經變成了。
那么答案是hello 嗎?
年輕的你又錯了,并不是。
而是 hello。
請注意,是hello,而不是hello ,而是空字符串
原因就在于.name是事先是有定義的,而且其值為空。
不信的話你可以在控制臺打印.name,返回的是"",你再打印.試試看,比如.frank,返回的就是了。
感謝@ygh1的提醒,打印結果和運行環境也是有關的,因為node中全局是,中全局是。
剛在node里跑了下有陷阱的題目,打印出來確實是hello ,因為node中的對象沒有初始的name屬性。
所以最正確的答案應該是:
node環境:hello undefined
browser環境:hello _____(非零寬空字符)
而我在工作中,遇到的更多的常見的像上面一樣的工廠函數式的寫法是這樣的。
let O = function(name){
this.name = name || 'world';
};
O.prototype.hello = function(){
console.log('hello ' + this.name);
};
let o = new O("frank");
let hello = o.hello("frank");
打印結果為:hello frank。
如果不傳入frank的話,打印出的是默認值hello world。
3.["1","2","3"].map()返回的是什么?
A. [1,2,3] B.["1","2","3"] C.[1,1,1] D.其他
這特么又是一道陷阱題,還好我之前在看MDN的map函數時,看到過這個陷阱。
正確答案是D:其他。
其他的具體值為多少?[1,NaN,NaN]。
不敢相信吧,為什么不是可愛的[1,2,3]呢?
因為map的有3個參數,,index和array,有2個參數,和radix(進制),只傳入到map中的話,會自動忽略第三個參數array,但是不會忽略index,所以就會把0,1,2作為第二個參數傳給。
如果還不明白的話,我們把["1","2","3"].map()的每一步都拆開來。
parseInt("1",0) 此時將字符"1"轉換為O進制數,由于0進制數不存在,所以返回Number類型的1。
parseInt("2",1) 此時將字符"2"轉換為1進制數,由于超出進制數1,所以返回NaN。
parseInt("3",2) 此時將字符"3"轉換為2進制數,由于超出進制數2,所以返回NaN。
至此,真相大白。那么常用的非陷阱式map寫法是怎樣的呢?
像這樣:??["1","2","3"].map(x=>(x))??
傳一個完整的函數進去,有形參,有,這樣就不會造成因為參數傳入錯誤而造成結果錯誤了,最后返回一個漂漂亮亮的經由純函數處理后的新數組回來。
其實這里如果再深入的話,可以再考察純函數是什么?
純函數其實就是一個不改變輸入,但是可以借助輸入,產生一個以輸入為原材料,經過加工處理后,輸出一個全新的輸出的函數,關鍵在于不改變輸入,純函數是編寫redux的必須具備的技能點。
剛才公司的大牛過來,說他從來不用,他用加號,+"1"返回1,+"2"返回2。大牛果然大牛,黑科技是真的多。
4.下面代碼中“入庫”的顏色是?
A.red B.blue C.black
我的答案是:我猜一下,可能是A,因為A的權重是最大的,偽類選擇器的權值應該比較小吧。
面試官發來一個,明天可以來公司面談嗎?已經約好明天面試。
這道題的解答到此為止,因為我是真的真的對CSS不感興趣,各位看官老爺請原諒我。
面試-3 未通過1.說下下面兩種font-size單位的異同?
em rem
二者的為了保證用戶修改字體大小時,保持垂直方向上的字體大小一致。與px不同,二者都是字體計算大小單位,也就是說,需要通過計算得出其大小,轉換成px,微信小程序的rpx也是這樣,最后還是轉換成了px,可能是借鑒了rem的思想吧。
但是em相對于繼承來的父元素,rem相對于根元素。聽大牛說,rem在國內使用比較多,可能侍使用習慣問題。我自己也覺得rem使用起來更簡單,為根元素的font-size賦一個初始值,再配合css的媒體查詢,可以動態的改變這個全局的單位,可以說是牽一發而動全身,使用起來非常方便,而em的可閱讀性就很差了,有的時候為了算字體大小,需要一級一級找上去,非常不直觀。
現代的常用的瀏覽器,1rem等于16px,但是可以通過??html{font-size:/num }??來控制。
舉2個 rem和em例子對比下。
html簡寫結構:
rem 例子:
html { font-size:62.5%; } /* =10px */
body { font-size: 2.0rem; } /* =20px */
div { font-size: 1.0rem; } /* =10px */
em 例子:
html { font-size:62.5%; } /* =10px */
body { font-size: 2.0em; } /* =20px */
div { font-size: 1.0em; } /* =20px */
MDN的font-size章節給出了em和rem的非常好的解釋,英文原版非常直觀,我這里再貼一下:
em
the font-size of the . If used on the font-size , it the font-size of the .
rem
the font-size of the root ( ). When used the root font-size, it its value (a is 16px, but user- may this).
其實em和rem與MVVM框架的組件間通信有些類似,都有逐級繼承和全局影響的概念。em是逐級傳遞的,也就是繼承,框架中用props和事件訂閱發布的方式也是這樣,爺,父,孫的傳遞都是要一級一級去傳遞的,爺爺想直接傳授點技能給孫子必須先傳授給父親,爺爺→父親→孫子;而rem就和框架中的狀態管理庫很像,例如vuex和redux,抽取出一個全局的狀態樹,不用一級一級的去很復雜的去繼承,爺爺想教教孫子,直接就可以傳授給孫子,爺爺→孫子。
2.只用一個div 實現定時紅綠燈
僅用一個DIV實現紅綠燈
面試-4 未通過
由于種種原因,開始了新一輪的面試,這一輪面試可謂收獲頗豐。與各種各樣的面試官交流下來,除了收獲到一些疏漏的知識點外,發現面試其實非常考驗面試官的水平。揣摩出一些如何成為一名合格的前端面試官方法。
以及很重要的老哥的經驗:進大廠前必須要做的準備,提前一個月刷題。
1.與函數調用棧
console.log(1);
setTimeout(function(){
console.log(2);
},0);
console.log(3);
輸出:1 3 2原因:Call Stack會最后調用的,中的是一個異步函數。函數調用棧的部分可以參考這里:??/node-js-at-…??
2. foo 與 var foo的提升優先級
console.log(typeof foo);
var foo = "foo";
function foo(){}
輸出:
console.log(typeof foo);
function foo(){}
var foo = "foo";
輸出:
優先級比var高,無論在其前后,都會覆蓋掉同名的var聲明。
3.let 塊作用域 與
for(let i=0;i<6;i++){
setTimeout(function(){
console.log(i)
},0)
}
console.log(i)
輸出:
0
Uncaught ReferenceError: i is not defined
1
2
3
4
5
為什么在debug的過程中,打印順序是混亂的? (等把規范的章節翻譯完,再來解決)打在.log(i)上。
Uncaught ReferenceError: i is not defined
0
2
5
4
3
1
如果將let替換成var呢?
for(var i=0;i<6;i++){
setTimeout(function(){
console.log(i)
},0)
}
console.log(i)
輸出:6個6原因:
4.為什么..call([1,2,3])返回[ Array]?[].()可以返回[ Array]嗎?
若想回答這個問題,需要深入理解...call()。
難道真的像自己理解的那樣,是通過call將[1,2,3]作為.的實參傳遞了進去嗎?不是。直接.([1,2,3])不能實現同樣的功能嗎?不能。而實際上也有Array.proto.()這種形式,所以是可以直接調用arr.()的,這樣能檢測出嗎?不行。
那到底是什么原因?先來肝一個表格。
數據類型
例子
字符串
"foo".()
"foo"
數字
1.()
: or token
布爾值
false.()
"false"
.()
: read '' of
null
null.()
: read '' of null
.()
" () { [ code] }"
.()
" () { [ code] }"
.()
" () { [ code] }"
Array
Array.()
" Array() { [ code] }"
.()
" () { [ code] }"
Date
Date.()
" Date() { [ code] }"
.()
" () { [ code] }"
Error
Error.()
" Error() { [ code] }"
.()
" () { [ code] }"
.()
" () { [ code] }"
Math
Math.()
"[ Math]"
為什么會出現下面的情況?
Object.toString.call(Array)//"function Array() { [native code] }"
Object.prototype.toString.call(Array)//"[object Function]"
答案在這里!
Object.toString()//"function Object() { [native code] }"
Object.prototype.toString()//"[object Object]"
對象和它的原型鏈上各自有一個()方法,第一個返回的是一個函數,第二個返回的是值類型。
既然知道了不同,現在我們再來分析下??...call(Array)//"[ ]"???。Array對象本身返回一個構造函數,Array//? Array() { [ code] },而..()返回的是//"[ Type]"的形式,通過call將Array的this上下文切換到,從而調用了..(),因此返回???[ ]??。
需要注意的是:Math.()直接返回"[ Math]"。
實際開發中,我們用到最多的可能是:...call([1,2,3])//"[ Array]"這種。
總結:
那么不可以直接Array...call([1,3,4])嗎?不行!因為Array,,Date雖然是基于進行創建的,但是他們繼承的是.(),而不是..()。再加深一遍印象:
Object.toString()//"function Object() { [native code] }"
Object.prototype.toString()//"[object Object]"
所以這就是必須用..()去檢測類型的原因。
至于..()內部是怎么實現的,等到時機成熟再去深入。
5.綜合考察bind,call和apply的面試題
var obj = {
a: 1,
name: 'world',
objSayName: function (fn) {
fn();
}
}
function sayName () {
return console.log(this.name);
}
obj.objSayName(sayName);
// 輸出:undefined
為什么?在obj的內部,沒有修改this指向到當前調用對象。
題目一:對象內部方法,調用全局的函數適用:多個對象(局部方法)復用同一全局函數精簡:局部(方法)復用全局函數方法:修改this指向,通過..bind()去顯式修改this指向到當前調用對象。原因: f.bind() a new with the same body and scope as f, but where this in the ,in the new it is bound to the first of bind, of how the is being used.bind only works once!
var obj = {
name: '1',
objSayName: function (f) {
var g = f.bind(this);
console.log(g());
}
};
function sayName(){
return this.name;
}
obj.objSayName(sayName);
輸出:'1'
拓展:題目二:如果全局方法想輸出對象的局部屬性,該怎么辦?適用:同一全局函數輸出多個對象(內部變量)精簡:全局函數輸出局部(變量)方法:使用apply或者call修改this指向到被調用對象原因:An can be as the first to call or apply and this will be bound to it.
var obj = {
name: '1',
say: function (fn) {
fn();
}
};
function sayName(){
return this.name;
}
sayName.apply(obj);
sayName.call(obj);
// 輸出:'1'
參考:??/en-US/docs/…??
面試-5 offer 3 整個江湖都任我闖,我的生命像一首歌
現東家的面試題,是我最欣賞的一套面試題,在這里已經工作了接近1年時間,成長許多。
題目主要分為4個部分:
答案未驗證準確性,有待驗證并更新。我將按照“1 year ”和“today”的角度去進行解答,也是對自己成長的一個記錄。
HTML1.請描述, 和的區別
1 year :,需要與后端協作,一種認證方式,失效時間,當前會話有效,本地緩存,失效時間today:
.請解釋?????放置在????之前?
1 year :防止阻塞瀏覽器渲染,先執行CSSOM,再繪制DOM,再操作DOM。主線程單線程渲染UI。
today從技術實現的角度講,先加載并且繪制,DOM渲染結束后再加載并執行可能涉及DOM操作的js文件,避免js的執行導致渲染阻塞。從用戶體驗的角度講,優先加載樣式表減少用戶面對空白網頁的時間,提升用戶體驗。
CSS1.CSS中類()和ID的區別
1 year ①ID優先級高②ID唯一標識,不能重復
today①語法不同,#, .②影響元素不同,#作用單個元素,.作用所有元素③選擇器權重不同,#權值高于.
2.有哪些隱藏DOM的方法
1 year
today??[譯]如何隱藏DOM元素???
3.請解釋??*{ box-: -box }??的作用,并且說明使用它有什么好處?
1 year 怪異盒模型。計算方便,width包含了,響應式百分比布局。
-的值有2種,一個是-box,一個是-box,-box僅僅包含。-box的width會將, 和包含在內,例如width:100%指的是包含了,和的寬度,布局時更好控制。
例如子元素繼承了父元素的width:100%,此時設置了子元素,,若子元素的box-是-box,會導致溢出,而-box的話,width:100%會很舒服地包含了和。
因為這樣的應用場景很多,所以索性就為所有標簽都設置成-box,有特殊情況的再手動設置成-box。
有一篇墻推IE怪異盒模型的文章:??把所有元素的box-都設置成-box吧!??
4.請問在確定樣式的過程中優先級是如何決定的(請舉例)?如何使用此系統?
1 year
每個選擇器都有權值,權重為和,#foo>.class:: 三者和為權重,權值id>標簽>class>偽類。
today優先級由高到低
一個很優秀的說明css選擇器優先級的圖:??/?
通用選擇器(*),組合符(+,>,?,'',||)和否定偽類(:not())對權重沒有影響。
5.請問為何要使用()而非 ,或反之的理由?為什么?
1 year
減少了計算,()不影響其他元素,性能更好,GPU計算次數更少
today在我的這篇博問中有答案:??CSS3動畫卡頓性能優化解決方案??
()涉及到的是合成器線程,與主線程是相互獨立的,所以會比較快。而 涉及到的是主線程,會導致主線程負責的布局重繪和js執行,所以會比較慢。
JS1..call和.apply的區別是什么?
1 year
today關于這個問題曾經產出2篇博客:??從規范去看..apply到底是怎么工作的?????從規范去看..call到底是怎么工作的???call是索取,apply是付出。從call和apply的字面意思就可以看出,call調用,apply應用,調用函數,應用參數。call和apply的主要區別在于,call僅僅切換this上下文到其他類,從而調用自己不存在的方法;而apply主要是為了將其他類型的參數傳遞到自己內部,再調用自己的方法。
假設有foo,bar。??foo.call(bar) ???bar調用foo的方法,實例.([1,2,3])->"[ Array]",數組實例調用了類的方法。???foo.apply(null, bar) ??foo的方法應用bar的參數,Math.max.apply(null, [1,2,3])->3,Math的max方法應用了[1,2,3]中的每個參數。
2.請解釋JSONP的工作原理,以及它為什么不是真正的Ajax?
1 year 原理:異步插入一個????,會有XSS問題原因:沒有調用XMR對象today一種比較古老的不安全的跨域請求訪問方式,沒有調用XMR對象,服務器允許瀏覽器在query 中傳遞瀏覽器內定義的函數,而這個函數是有概率被XSS攻擊改寫的。
來自高票答案:??//2…??
JSONP不是一個很復雜的問題。假設我們在?????域名下,此時我們想給????域名發送一個請求。為了請求成功,需要跨越域名邊界,這對于瀏覽器來說是禁忌。
繞開這個限制的一種方式是?????放置在????之前?