23. 監聽輸入:
1. oninput > onchange: onchange在離焦事件是觸發。不如input靈敏 ( IE9+ )
2. 中文輸入時(即非直接輸入),input獲取的值不正確,需加判斷。( IE9+ )
compositionstart:當瀏覽器有非直接的文字輸入時, compositionstart事件會以同步模式觸發.
compositionEnd: 當瀏覽器是直接的文字輸入時, compositionend會以同步模式觸發.
var cpLock = false;
input.addEventListener('compositionstart', function(){
cpLock = true;
})
input.addEventListener('compositionend', function(){
cpLock = false;
})
input.addEventListener('input', function(){
if(!cpLock)console.log(this.value);
});
3. 需要兼容IE9一下的,只能使用keyPress,keyDown等事件,判斷keyCode
(參考做法:http://jyren-rachel.iteye.com/blog/1886275)
24. 遞歸中的性能:
遞歸是處遍歷外最常用的循環方法。鑑於其性能問題,一般能用while,for等循環的儘量不用遞歸。 若必須用遞歸方法,一般把遞歸中的執行代碼放入setTimeout方法中,以避免棧溢出(setTimeout總是在下一次的tick中執行)。
setInterval的不靠譜:當每次執行的時間小於循環時間時,不會出現異常;而當代碼執行時間較長,超出循環時間時,下一次的循環將被延後,這樣每次的循環間隔將不統一,且任務會堆積在隊列中。
更詳細的介紹https://www.cnblogs.com/simonbaker/p/5707270.html
25. es6屬性:
1. let , const
let : a. 不存在變量提升, 必須先聲明 後使用。(會報錯 is not defined ;var 中則不報錯,返回值爲 undefined)
b. 存在塊作用域內,同域內不可重複聲明
c. 暫時性死區:一旦在作用域內聲明瞭次變量,若提前訪問會報錯,(即使外域也聲明瞭同名變量)
const : 與 let 特點相同,聲明時必須賦值,且不能更改賦值,若是對象保存的是對象的地址。
2. 結構賦值 : 等號右邊的值會賦予左邊的變量。
3. 模板字符串: ‘字符串’,按照字符串處理拼接。
a. 反引號爲特殊字符,使用的話需加 \ 轉義。
b. 花括號內可以進行 js 運算
c. 空格、縮進都會被保留
`${1}+${2}` // '1+2'
4. rest參數 , 擴展運算符
rest : (. . .a) 作爲參數或者等號左邊變量 必須爲最後一個參數
擴展運算符: 相當於rest的逆運算, 展開一個數組或者對象
5.class 類,super方法:(阮一峯:https://m.imooc.com/article/20618)
注:react中一般寫法: super ( props );這樣寫的原因是 在constructor 中可以使用 this.props, props是實例化時傳入的參數。
(子類纔會有super方法,父類是沒有的);在子類的構造函數中,只有調用super之後,才能使用this關鍵字,否則會報錯,這是因爲子類沒有自己的this對象,而是繼承父類的this對象,然後對其進行加工,如果不調用super方法,子類就得不到this對象;
如果子類沒有定義constructor方法,這個方法會默認添加,也就是說,不管有沒有顯式定義,任何一個子類都有constructor方法。
通過super調用父類的方法時,super會綁定子類的this。
super當作函數調用時,代表父類的構造函數;super作爲對象時,在普通方法中,指向父類的原型對象,在靜態方法中,指向父類
26. http1.0 和 http2.0:
http2增加了:
- 多路複用
- 壓縮頭信息
- 請求劃分優先級
- 支持服務器端主動推送
- 只支持https
27. use strict 嚴格模式:(參考文章:https://blog.csdn.net/weixin_40387601/article/details/80514358)
js 以更嚴謹的方式運行。
28. 小程序實現vue類型的數據監聽:Object.defineProperty方法
/**
* 設置監聽器
*/
setWatcher(page) {
let data = page.data;
let watch = page.watch;
Object.keys(watch).forEach(v => {
let key = v.split('.'); // 將watch中的屬性以'.'切分成數組
let nowData = data; // 將data賦值給nowData
for (let i = 0; i < key.length - 1; i++) { // 遍歷key數組的元素,除了最後一個!
nowData = nowData[key[i]]; // 將nowData指向它的key屬性對象
}
let lastKey = key[key.length - 1];
// 假設key==='my.name',此時nowData===data['my']===data.my,lastKey==='name'
let watchFun = watch[v].handler || watch[v]; // 兼容帶handler和不帶handler的兩種寫法
let deep = watch[v].deep; // 若未設置deep,則爲undefine
this.observe(nowData, lastKey, watchFun, deep, page); // 監聽nowData對象的lastKey
})
},
/**
* 監聽屬性 並執行監聽函數
*/
observe(obj, key, watchFun, deep, page) {
var val = obj[key];
// 判斷deep是true 且 val不能爲空 且 typeof val==='object'(數組內數值變化也需要深度監聽)
if (deep && val != null && typeof val === 'object') {
Object.keys(val).forEach(childKey=>{ // 遍歷val對象下的每一個key
this.observe(val,childKey,watchFun,deep,page); // 遞歸調用監聽函數
})
}
var that = this;
Object.defineProperty(obj, key, {
configurable: true,
enumerable: true,
set: function(value) {
// 用page對象調用,改變函數內this指向,以便this.data訪問data內的屬性值
watchFun.call(page,value,val); // value是新值,val是舊值
val = value;
if(deep){ // 若是深度監聽,重新監聽該對象,以便監聽其屬性。
that.observe(obj, key, watchFun, deep, page);
}
},
get: function() {
return val;
}
})
}
page中使用:
//index.js
Page({
data: {
my: {
name: 'xuyang',
age: 21,
hobby: ['girls', 'games']
},
nameInfo:{}
},
onLoad() {
getApp().setWatcher(this);
this.data.my.hobby[0] = 'study';
this.setData({
nameInfo:{name:'haha',sex:'boy'}
})
console.log(this.data)
},
watch: {
my:{
handler(newValue) {
console.log(newValue);
},
deep:true
}
}
})
(轉載鏈接:https://blog.csdn.net/xuyangxinlei/article/details/81408200)
29. CSS 3 + HTML 5 (postcss-loader只是給 css 添加前綴,通gulp中的autoprefixer, 謹慎使用新屬性)
1.選擇器:
屬性:[att=val] 指定特定名字的元素
[att*=val] 匹配val*的元素,
[att^=val] 匹配val開頭的元素,比如id爲val1、val432432都可以。
[att$=val] 匹配val結尾的元素,比如id爲1213val、fdajlval等等。
順序:first-child:選擇第一個子元素
last-child:選擇最後一個子元素
nth-child:選擇第n個子元素,這個還可以根據奇偶來制定,
nth-last-child:選擇倒數第n個子元素
only-child:單個子元素時,指定樣式
狀態: hover , active ,checked , selection, focus , enabled , disabled , read-only
2. 效果: border-radius , box-shadow , box-sizing , background屬性 , linear-gradient , radial-gradient
3.動畫:
1.關鍵幀動畫:animation: name duration timing-function delay count; @keyframes
2.2D效果屬性: tranform : translate 、rotate、scale ; transition
4. html5 :
1.語義化標籤: nav ,head ,footer , aside,article,section;
2. 拖拽: drag , drop
3. vedio 、audio、canvas
4.input 新類型: time , date , email , url , search ,calendar , datetime, week , month , color , tel ,number ,
5. websocket , localstorage
28.閉包:定義 , 效果:可以獲去操作一個函數中的局部變量。缺點:消耗內存,一直保持父函數的引用。 優點: 對局部變量保護作用,利於函數的 封裝。
29. CMD,AMD比較:
AMD(異步模塊定義):requirejs : 提前下載,提前執行
CMD(通用模塊定義):seajs :提前下載,延遲執行
RequireJS 和 SeaJS 都是很不錯的模塊加載器,兩者區別如下:
1. 兩者定位有差異。RequireJS 想成爲瀏覽器端的模塊加載器,同時也想成爲 Rhino / Node 等環境的模塊加載器。SeaJS 則專注於 Web 瀏覽器端,同時通過 Node 擴展的方式可以很方便跑在 Node 服務器端
2. 兩者遵循的標準有差異。RequireJS 遵循的是 AMD(異步模塊定義)規範,SeaJS 遵循的是 CMD (通用模塊定義)規範。規範的不同,導致了兩者 API 的不同。SeaJS 更簡潔優雅,更貼近 CommonJS Modules/1.1 和 Node Modules 規範。
3. 兩者社區理念有差異。RequireJS 在嘗試讓第三方類庫修改自身來支持 RequireJS,目前只有少數社區採納。SeaJS 不強推,而採用自主封裝的方式來“海納百川”,目前已有較成熟的封裝策略。
4. 兩者代碼質量有差異。RequireJS 是沒有明顯的 bug,SeaJS 是明顯沒有 bug。
5. 兩者對調試等的支持有差異。SeaJS 通過插件,可以實現 Fiddler 中自動映射的功能,還可以實現自動 combo 等功能,非常方便便捷。RequireJS 無這方面的支持。
6. 兩者的插件機制有差異。RequireJS 採取的是在源碼中預留接口的形式,源碼中留有爲插件而寫的代碼。SeaJS 採取的插件機制則與 Node 的方式一致:開放自身,讓插件開發者可直接訪問或修改,從而非常靈活,可以實現各種類型的插件。.
(來源文章:http://www.cnblogs.com/dojo-lzz/p/4707725.html)
30. arguments對象:函數的參數對象
特點:1. 不是數組,但是有數組的一些屬性,length,索引,變成數組的方法:[].slice.call(arguments)或Array.prototype.slice.call(arguments);
typeof arguments // obeject ; {}.tostring.call(arguments) // [object Arguments]
2. 實參中的值和arguments中的值保持一致。
3. length的值不會自動改變,必須主動設置,但可以訪問
4. 屬性callee:arguments.callee指向函數本身,可以用於遞歸中,優點是即使函數名稱改變,也不會報錯 ; arguments.callee.caller指向調用此函數的函數,若無爲null,
5. 嚴格模式下,對arguments操作,只對arguments有效,對參數無效。
function test(a,b,c){
console.log(c);
arguments[2]=10;
console.log(c);
arguments[3]=10;
console.log(arguments[3]);
console.log(arguments.length);
arguments.length=4;
console.log(arguments.length);
}
test(1,2,3)
// 結果:
// 3
// 10 特點2
// 10 特點3
// 3
// 4
test(1,2)
// 結果:
// undefined 特點2
// 10 特點3
// 10
// 2
// 4
31. 隊列,宏任務,微任務:參考:https://juejin.im/post/59e85eebf265da430d571f89
32. SEO及優化:
1. TDK:title , description , keywords
2. 標題標籤,img的alt屬性,語義化標籤,
SPA的優化:單頁面應用對國內瀏覽器seo很不友好,國外瀏覽器不受影響。
a. 預渲染 b. ssr 服務端渲染,首屏採用服務端渲染。nuxt.js
vue : prerender-plugin + vue-meta-info
33. sort方法:瀏覽器的實現方式不同:V8:<=22使用InsertionSort ,>22使用QuickSort排序。ff:歸併排序
//自定義sort方法:
Array.prototype.mySort = function (fn) {
for (var i = this.length; i >0; i--) {
for (var j =0; j < i; j++) {
if (fn && typeof fn == 'function') {
if(fn(this[j] ,this[j+1])>0){
[this[j], this[j+1]] = [this[j+1], this[j]];
}
} else {
var a = String(this[j]),b=String(this[j+1]);
if(charcode(a,b)>0){
var temp=this[j];
this[j] = this[j+1];
this[j+1] = temp;
// [this[j+1], this[j]] = [this[j], this[j+1]];
}
}
}
}
function charcode(a,b){
if(a.charCodeAt(0)<b.charCodeAt(0)){
return -1
}else if(a.charCodeAt(0)>b.charCodeAt(0)){
return 1
}else{
if(a.slice(1)===''){
return -1
}else if(b.slice(1)===''){
return 1
}else{
return charcode(a.slice(1),b.slice(1))
}
}
}
return this;
}
34. 構造函數:
//js中沒有類的概念(es6中也只是中語法糖),所以通過原型鏈實現繼承這種機制。
//構造函數實際上就是普通函數,返回一個實例對象
function Test(name,age){
this.name=name;
this.age=age;
};
//每個函數都有prototype屬性,一個對象,是所以實例對象共有的屬性方法,因爲都引用這個對象,new 的過程中會自動添加constructor屬性,構造函數本身。
Test.prototype.constructor = Test;
Test.prototype.fn=function(){};
//一個實例的屬性分爲兩部分:自有屬性 + 公共屬性
var test = new Test(1,2); // name , age , fn
//通過 hasOwnProperty 判斷屬性是否是自有屬性
test.hasOwnProperty('fn') // false
//通過 isPrototypeOf 判斷 實例 是否是構造函數的實例
Test.prototype.isPrototypeOf(test) // true;
35原型鏈:
數據類型:undefined,null,Number,String,Boolean + Object 六大類型。
Number,String,Boolean, Object,Function等都是構造函數,typeof 值:‘function’
生成相應類型的數據可以直接定義,也可以通過構造函數生成(這種方式生成的返回值都是一個 object,function例外,返回的是function),
// 1.prototype:只有函數有此屬性,
// 2.__proto__:對象的此屬性指向構造函數的prototype, 函數的此屬性指向Function的prototype(所以的函數都是Function的實例),
Obeject.__proto__ === Function.prototype // true typeof 爲function,此function較特殊,沒有prototype屬性,
Object.__proto__.__proto__ ===Object.prototype // true 擁有object的屬性
//constructor:指向構造函數本身,在34中,是在prototype中的默認一個屬性。因此所以的實例中也會有此方法,
sd
36.運算符優先級及轉換
var a = (!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]] + ({}+[])[[~!+[]]*~+[]]; // sb (--的優先級大於*;~改變正負值再減一;[]是空=>0;{}是[object Object])
sd