0.es6新特性
1.不一樣的變量聲明:const和let
2.模板字符串,字符串拼接
3.箭頭函數(Arrow Functions)
4.函數的參數默認值
// ES6之前,當未傳入參數時,text = 'default';
function printText(text) {
text = text || 'default';
console.log(text);
}
// ES6;
function printText(text = 'default') {
console.log(text);
}
printText('hello'); // hello
printText();// default
5.Spread / Rest 操作符
Spread / Rest 操作符指的是 ... ,具體是 Spread 還是 Rest 需要看上下文語境。
當被用於迭代器中時,它是一個 Spread 操作符:
function foo(x,y,z) {
console.log(x,y,z);
}
let arr = [1,2,3];
foo(...arr); // 1 2 3
當被用於函數傳參時,是一個 Rest 操作符:當被用於函數傳參時,是一個 Rest 操作符:
function foo(...args) {
console.log(args);
}
foo( 1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
6.ES6中的類
class Student {
constructor() {
console.log("I'm a student.");
}
study() {
console.log('study!');
}
static read() {
console.log("Reading Now.");
}
}
console.log(typeof Student); // function
let stu = new Student(); // "I'm a student."
stu.study(); // "study!"
stu.read(); // "Reading Now."
類相當於實例的原型, 所有在類中定義的方法, 都會被實例繼承。 如果在一個方法前, 加上static關鍵字, 就表示該方法不會被實例繼承, 而是直接通過類來調用, 這就稱爲“ 靜態方法”。
class Foo {
static classMethod() {
return 'hello';
}
}
Foo.classMethod() // 'hello'
var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function
類中的繼承和超集:
class Phone {
constructor() {
console.log("I'm a phone.");
}
}
class MI extends Phone {
constructor() {
super();
console.log("I'm a phone designed by xiaomi");
}
}
let mi8 = new MI();
extends 允許一個子類繼承父類,需要注意的是,子類的constructor 函數中需要執行 super() 函數。
當然,你也可以在子類方法中調用父類的方法,如super.parentMethodName()。
在 這裏 閱讀更多關於類的介紹。
有幾點值得注意的是:
- 類的聲明不會提升(hoisting),如果你要使用某個 Class,那你必須在使用之前定義它,否則會拋出一個 ReferenceError 的錯誤
- 在類中定義函數不需要使用 function 關鍵詞
1.原型,和原型鏈
javascript語言是一種面向對象的語言,它沒有"子類"和"父類"的概念,裏面所有的數據類型都是對象
每一個對象都有原型,原型也是一個對象,這個對象也有自己的原型,一層套一層,就是原型鏈。
2.主流瀏覽器5個及其內核
IE Trident 微軟
Chrome Blink Google
FireFox Gecko
Opera presto
Safari webkit Apple
3.var和let的區別
1.使用var聲明的變量,其作用域爲該語句所在的函數內,且存在變量提升現象;
2.使用let聲明的變量,其作用域爲該語句所在的代碼塊內,不存在變量提升;
3.let不允許在相同作用域內,重複聲明同一個變量。
4.數組Array的方法
- concat:合併數組
- constructor:數組的 的構造函數
- copyWithin:ƒ複製數組的一部分到同一數組中的另一個位置
- entries:返回一個新的Array Iterator對象,該對象包含數組中每個索引的鍵/值對。
- every:方法用於檢測數組所有元素是否都符合指定條件(通過函數提供)。[1,2,3].every(i=>i>2;)
- fill:使用固定值填充數組:
- filter:方法創建一個新的數組,新數組中的元素是通過檢查指定數組中符合條件的所有元素。
- find:方法返回通過測試(函數內判斷)的數組的第一個元素的值。
- findIndex:函數也是查找目標元素,找到就返回元素的位置,找不到就返回-1。
- forEach:方法用於調用數組的每個元素,並將元素傳遞給回調函數。
- includes:方法用來判斷一個數組是否包含一個指定的值,如果是返回 true,否則false。
- indexOf:方法可返回數組中某個指定值的元素位置。
- join:方法用於把數組中的所有元素放入一個字符串。元素是通過指定的分隔符進行分隔的。
- keys:ƒ keys()
- lastIndexOf:方法可返回一個指定的元素在數組中最後出現的位置,從該字符串的後面向前查找。
- length:數組長度
- map:方法返回一個新數組,數組中的元素爲原始數組元素調用函數處理後的值
- pop:最後一個元素出列
- push:對未加入一個元素
- reduce:
-
var arr = [1, 2, 3, 4]; var sum = arr.reduce((x,y)=>x+y) var mul = arr.reduce((x,y)=>x*y) console.log( sum ); //求和,10 console.log( mul ); //求乘積,24
- reduceRight:同reduce,從數組末未開始
- reverse:反轉數組排列
- shift:數組第一個元素出列
- slice:方法可從已有的數組中返回選定的元素。
- some:方法用於檢測數組中的元素是否滿足指定條件(函數提供)。
- sort:排序
- splice:方法可刪除從 index 處開始的零個或多個元素,並且用參數列表中聲明的一個或多個值來替換那些被刪除的元素。
- toLocaleString:把數組轉換爲本地字符串。
- toString:
- unshift:方法可向數組的開頭添加一個或更多元素,並返回新的長度。
- values:ƒ values()
5.promise
使用promise是爲了解決回調地獄的問題,
firstAsync(function(data){
//處理得到的 data 數據
//....
secondAsync(function(data2){
//處理得到的 data2 數據
//....
thirdAsync(function(data3){
//處理得到的 data3 數據
//....
});
});
});
回調層層嵌套不易閱讀。
Promise,他是一個對象,是用來處理異步操作的,可以讓我們寫異步調用的時候寫起來更加優雅,更加美觀便於閱讀。顧名思義爲承諾、許諾的意思,意思是使用了Promise之後他肯定會給我們答覆,無論成功或者失敗都會給我們一個答覆,所以我們就不用擔心他跑了哈哈。所以,Promise有三種狀態:pending(進行中),resolved(完成),rejected(失敗)。只有異步返回的結構可以改變其狀態。所以,promise的過程一般只有兩種:pending->resolved或者pending->rejected。
function cook(){
console.log('開始做飯。');
var p = new Promise(function(resolve, reject){ //做一些異步操作
setTimeout(function(){
console.log('做飯完畢!');
reject('飯做糊了')
// resolve('雞蛋炒飯');
//一前一後遇到reject,resolve,後面不在執行resolve()
}, 1000);
});
return p;
}
//喫飯
function eat(data){
console.log('開始喫飯:' + data);
}
function notEat(data) {
console.log(data)
}
cook()
.then(eat,notEat)
promise對象的構造函數的參數是一個函數function(resolve, reject) ,這個函數有兩個參數resolve,reject,都是函數,他們負責把promise對象的狀態從pending變成resolved,或者rejected。promise對象p的then方法接受兩個函數,第一個在promise狀態爲resolved時執行,第二個在promise狀態爲rejected時執行。resolve的參數會傳遞給對應的函數,rejected同理。eat,notEat,函數可以繼續返回promise對象,然後繼續鏈式調用。
參考資料:https://www.cnblogs.com/sweeeper/p/8442613.html
6.call , apply,arguments
var person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates",
}
var person2 = {
firstName:"Steve",
lastName: "Jobs",
}
person.fullName.call(person1); // 將返回 "Bill Gates"
person.fullName.call(person1);
相當於
var person1=new Person({firstName:"Bill",lastName: "Gates",});
person1.fullName();
var person = {
fullName: function(city, country) {
return this.firstName + " " + this.lastName + "," + city + "," + country;
}
}
var person1 = {
firstName:"Bill",
lastName: "Gates"
}
var str=person.fullName.call(person1, "Seattle", "USA");
console.log(str) //Bill Gates,Seatle,USA
apply
/*定義一個人類*/
function Person(name,age)
{
this.name=name;
this.age=age;
}
/*定義一個學生類*/
functionStudent(name,age,grade)
{
Person.apply(this,arguments);
this.grade=grade;
}
//創建一個學生類
var student=new Student("zhangsan",21,"一年級");
//測試
alert("name:"+student.name+"\n"+"age:"+student.age+"\n"+"grade:"+student.grade);
//大家可以看到測試結果name:zhangsan age:21 grade:一年級
//學生類裏面我沒有給name和age屬性賦值啊,爲什麼又存在這兩個屬性的值呢,這個就是apply的神奇之處.
分析: Person.apply(this,arguments);
this:在創建對象在這個時候代表的是student
arguments:是一個數組,也就是[“zhangsan”,”21”,”一年級”];
也就是通俗一點講就是:用student去執行Person這個類裏面的內容,在Person這個類裏面存在this.name等之類的語句,這樣就將屬性創建到了student對象裏面.
相當於python的裝飾器函數,有裝飾器的函數調用之前,先把該函數和其參數放入裝飾器做一定的處理。
@decorateFunc
def func():
……
Arguments
function a() {
console.log(arguments)
for(let i=0;i<arguments.length;i++){
console.log(arguments[i])
}
console.log(arguments.callee)
}
a(1,2,3,4,5,6)
callee,打印自己函數的代碼……
function b(q,w,e) {
e=2
console.log(arguments[2])
}
b(1,1,1) //打印2
function b(q,w,e) {
arguments[2]=3
console.log(e)
}
b(1,1,1) //打印3
函數的參數列表,與arguments列表相互影響,相當於是引用關係。
7.淺拷貝和深拷貝的理解,實現深拷貝
參開資料:https://blog.csdn.net/weixin_37719279/article/details/81240658
淺拷貝只拷貝一層,深拷貝,拷貝每一層
深拷貝,遞歸拷貝,只要array,object,往裏找。
但是當遇到兩個互相引用的對象,會出現死循環的情況。
爲了避免相互引用的對象導致死循環的情況,則應該在遍歷的時候判斷是否相互引用對象,如果是則退出循環。
8.dom事件流
參考資料:https://blog.csdn.net/qr457535344/article/details/79711469
流
流的概念,在現今的JavaScript中隨處可見。比如說React中的單向數據流,Node中的流,又或是今天本文所講的DOM事件流。都是流的一種生動體現。
至於流的具體概念,我們採用下文的解釋:
用術語說流是對輸入輸出設備的抽象。以程序的角度說,流是具有方向的數據。
通通連起來——無處不在的流 淘寶FED--愈之
事件流之事件冒泡與事件捕獲
在瀏覽器發展的過程中,開發團隊遇到了一個問題。那就是頁面中的哪一部分擁有特定的事件?
可以想象畫在一張紙上的一組同心圓,如果你把手指放在圓心上,那麼你的手指指向的其實不是一個圓,而是紙上所有的圓。放到實際頁面中就是,你點擊一個按鈕,事實上你還同時點擊了按鈕所有的父元素。
開發團隊的問題就在於,當點擊按鈕時,是按鈕最外層的父元素先收到事件並執行,還是具體元素先收到事件並執行?所以這兒引入了事件流的概念。
事件流所描述的就是從頁面中接受事件的順序。
因爲有兩種觀點,所以事件流也有兩種,分別是事件冒泡和事件捕獲。現行的主流是事件冒泡。
事件冒泡
事件冒泡即事件開始時,由最具體的元素接收(也就是事件發生所在的節點),然後逐級傳播到較爲不具體的節點。
舉個栗子,就很容易明白了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Event Bubbling</title>
</head>
<body>
<button id="clickMe">Click Me</button>
</body>
</html>
然後,我們給button
和它的父元素,加入點擊事件。
var button = document.getElementById('clickMe');
button.onclick = function() {
console.log('1. You click Button');
};
document.body.onclick = function() {
console.log('2. You click body');
};
document.onclick = function() {
console.log('3. You click document');
};
window.onclick = function() {
console.log('4. You click window');
};
在代碼所示的頁面中,如果點擊了button,那麼這個點擊事件會按如下的順序傳播(Chrome瀏覽器):
-
button
-
body
-
document
-
window
也就是說,click事件首先在<button>
元素上發生,然後逐級向上傳播。這就是事件冒泡。
事件捕獲
事件捕獲的概念,與事件冒泡正好相反。它認爲當某個事件發生時,父元素應該更早接收到事件,具體元素則最後接收到事件。比如說剛纔的demo,如果是事件捕獲的話,事件發生順序會是這樣的:
-
window
-
document
-
body
-
button
當然,由於時代更迭,事件冒泡方式更勝一籌。所以放心的使用事件冒泡,有特殊需要再使用事件捕獲即可。
(1)捕獲階段:當我們在 DOM 樹的某個節點發生了一些操作(例如單擊、鼠標移動上去),就會有一個事件發射過去。這個事件從 Window 發出,不斷經過下級節點直到觸發的目標節點。在到達目標節點之前的過程,就是捕獲階段(Capture Phase)。(所有經過的節點,都會觸發這個事件。捕獲階段的任務就是建立這個事件傳遞路線,以便後面冒泡階段順着這條路線返回 Window。)在目標元素對象本身上註冊的捕獲事件處理程序不會被調用。
(2)目標階段:當事件不斷的傳遞直到目標節點的時候,最終在目標節點上觸發這個事件,就是目標階段。
(3)冒泡階段:事件冒泡即事件開始時,由最具體的元素接收(也就是事件發生所在的節點),然後逐級傳播到較爲不具體的節點(我們平時用的事件綁定就是利用的事件冒泡的原理)
事件冒泡過程,是可以被阻止的。防止事件冒泡而帶來不必要的錯誤和困擾。
這個方法就是:stopPropagation()
stopPropagation() 方法:終止事件在傳播過程的捕獲、目標處理或起泡階段進一步傳播。調用該方法後,該節點上處理該事件的處理程序將被調用,事件不再被分派到其他節點。
9.前端項目管理
- src/
- main/ # main 目錄
- alpha/ # alpha 頁面
- index.css # css 入口文件
- index.js # js 入口文件
- index.html # html 入口文件
- ...
- beta/ # beta 頁面
- index.css
- index.js
- index.html
- ...
- ...
目錄結構按頁面分,不要按文件類型分
- 可擴展性:能夠很方便、清晰的擴展一個頁面、組件、模塊
- 組件化:多個頁面之間共用的大塊代碼可以獨立成組件,多個頁面、組件之間共用的小塊代碼可以獨立成公共模塊
- 可閱讀性:閱讀性良好(包括目錄文件結構、代碼結構),能夠很快捷的找到某個頁面、組件的文件,也能快捷的看出項目有哪些頁面、組件
- 可移植性:能夠輕鬆的對項目架構進行升級,或移植某些頁面、組件、模塊到其他項目
- 可重構性:對某個頁面、組件、模塊進行重構時,能夠保證在重構之後功能不會改變、不會產生新 bug
- 開發友好:開發者在開發某一個功能時,能夠有比較好的體驗(不好的體驗比如:多個文件相隔很遠)
- 協作性:多人協作時,很少產生代碼衝突、文件覆蓋等問題
- 可交接性:當有人要離開項目時,交接給其他人是很方便的
更多內容:https://blog.csdn.net/cc9200/article/details/101839894
10.跨域的理解和解決
首先,我們得先理解一下何爲跨域?所謂跨域,即網站的協議名 protocol(例如 http ://) 、域名 host (例如:www.example.com)、端口號 port (例如 80 ,默認端口可以省略) 這三個中的任意一個不同,網站之間的數據傳輸或者請求就屬於跨域請求了。
這是由於瀏覽器的同源策略,爲了防範跨站腳本的攻擊,禁止客戶端腳本對不同域的服務進行跨站調用,但是跨域並非瀏覽器限制了發起跨站請求,而是跨站請求可以正常發起,但返回結果被瀏覽器攔截了。有些瀏覽器不允許從HTTPS協議的域 跨域訪問 HTTP協議,比如Chrome和Firefox,這些瀏覽器在請求還未發出的時候就會攔截請求,這是一個特例。如果是非同源,共有三種行爲受到限制:(1)cookie、LocalStorage 和 IndexDB 無法讀取;(2)DOM 無法獲得;(3)AJAX請求不能發送。
1、利用 JSONP 實現跨域
$.getJSON('http://jjjjjjjj.com/data?callback=?,function(data)'){
//處理獲得的json數據
});
2、利用 CORS 實現跨域
CORS (Cross-Origin Resource Sharing)跨域資源共享,定義了必須在訪問跨域資源時,瀏覽器與服務器應該如何溝通。CORS 背後的思想是使用自定義的 HTTP 頭部,讓服務器能聲明哪些來源可以通過瀏覽器訪問該服務器上的資源,從而決定請求或響應是應該成功還是失敗,CORS 本身並非絕對的安全,可利用 OAuth2 加強保障。(更多關於 CORS 的詳解可以查看 阮一峯老師的一篇文章:跨域資源共享 CORS 詳解)
header("Access-Control-Allow-Origin: *") //“*”號表示允許任何域向我們的服務端提交請求
header("Access-Control-Allow-Origin: http://jjjjj.jd.com") //也可以設置指定的域名
11.js數據類型:
undefined、null、boolean、number、string、object、function、array
12.jquery鏈式調用實現原理
jq的方法都是掛在原型的,那麼如果我們每次在內部方法返回this,也就是返回實例對象,那麼我們就可以繼續調用原型上的方法了,這樣的就節省代碼量,提高代碼的效率,代碼看起來更優雅。
var MyJQ = function(){
}
MyJQ.prototype = {
css:function(){
console.log("設置css樣式");
return this;
},
show:function(){
console.log("將元素顯示");
return this;
},
hide:function(){
console.log("將元素隱藏");
}
};
var myjq = new MyJQ();
myjq.css().css().show().hide();
12.防抖節流
1、什麼是函數防抖
函數防抖(debounce):就是讓某個函數在上一次執行之後,滿足等待某個時間內不再觸發此函數後再執行,而在這個等待時間內再次觸發函數,等待時間可以重新計算,知道該函數在一定間隔內沒有被調用時,纔開始執行被調用方法(所謂防抖,就是指觸發事件後在 n 秒內函數只能執行一次,如果在 n 秒內又觸發了事件,則會重新計算函數執行時間。)
應用場景:假設我們網站有個所搜框,用戶輸入文本我們會自動聯想匹配出一些結果供用戶選擇。
我們可能首先想到到的做法就是監聽keypress事件,然後異步去查詢結果
這個方法本事是沒有錯的,但是如果用戶快速的輸入一連串字符,假設是10個字符,就會在瞬間觸發了10次請求,這無疑不是我們想要的。
什麼是函數節流
函數節流(throttle):是讓一個函數無法在很短的時間間隔內連續調用,當上一次執行完之後過了規定的時間間隔,才能進行下一次的函數調用。(所謂節流,就是指連續觸發事件但是在N秒中只執行一次函數)節流會稀釋函數的執行頻率。
13.如何判斷一個變量是數組類型還是對象類型
instanceof
14.for in for of forEach map的區別
可遍歷對象不同,index或key的值類型不同,只有for in可以遍歷自定義屬性和原型鏈的自定義屬性。
15.模塊機制,amd和commonjs
先回答我:爲什麼模塊很重要?
答:因爲有了模塊,我們就可以更方便地使用別人的代碼,想要什麼功能,就加載什麼模塊。
但是,這樣做有一個前提,那就是大家必須以同樣的方式編寫模塊,否則你有你的寫法,我有我的寫法,豈不是亂了套!
於是下面三個模塊規範出來了,這篇文章也出來了
16.this對象和bind,call函數使用
func.bind(obj)
obj.func()
var User = {
count: 1,
getCount: function() {
return this.count;
}
};
console.log(User.getCount());
var func = User.getCount;
console.log(func());
// 1和undefined。
var func = User.getCount.bind(User);
console.log(func());
17.proptype原型對象的理解,實現一個方法,傳入一個string類型的參數,然後將string的每個字符間加個空格返回
spacify('hello world') // => 'h e l l o w o r l d'
'hello world'.spacify();
String.prototype.spacify = function(){
return this.split('').join(' ');
};
18.函數申明與函數表達式的區別
// 函數聲明
function funDeclaration(type){
return type==="Declaration";
}
// 函數表達式
var funExpression = function(type){
return type==="Expression";
}
用函數聲明創建的函數funDeclaration可以在funDeclaration定義之前就進行調用;而用函數表達式創建的funExpression函數不能在funExpression被賦值之前進行調用。
19.函數式編程,實現函數multi(2)(3)(4)=24
function multi(num) {
var func=function (x){
return multi(x*num)
}
func.valueOf=function(){
return num;
}
return func
}
console.log(cmulti(1)) // 1
console.log(cmulti(1)(2)(3)(4)) // 24
console.log(cmulti(1)(2)(3)(4)(5)(6))// 720
valueOf()方法和toString()方法是一樣的,都會在後臺進行隱式的調用,在 o = +o時,等號右邊就已經調用了valueOf(),相當於 o = +(-1);所以,最終結果o爲-1.