說起JavaScript,大家都知道是一門腳本語言。那么ES是什么鬼呢?ES全稱ECMAScript ,是JavaScript語言的國際標准。
最近總結了條js的基礎特性相關的知識點,大家一起看一下吧

1.嚴格模式
- 使用嚴格模式,可以在函數內部進行較為嚴格的全局和局部的錯誤條件檢查
- 嚴格模式的編譯指示,"use strict"
- 創建全局變量,未聲明變量,非嚴格模式下為創建全局變量;嚴格模式下為拋出ReferenceError
- 對變量調用delete操作符,刪除變量,非嚴格模式下為靜默失敗;嚴格模式下為拋出ReferenceError
- 操作對象情況下:a,只讀屬性賦值會拋出TypeError;b,對不可配置的屬性使用delete操作符會拋出TypeError;c,為不可擴展的對象添加屬性會拋出TypeError。
- 重名屬性情況:a,非嚴格模式下沒有錯誤,以第二個屬性為准;b,嚴格模式下會拋出語法錯誤。
- 函數參數必須唯一,重名參數,在非嚴格模式下沒有錯誤,只能訪問第二個參數;嚴格模式下,會拋出錯誤。
function funValue(value) { value="dada"; alert(value); // dada alert(argument[0]); // 非嚴格模式:dada // 嚴格模式模式 dadaqianduan } funValue('dadaqianduan'); 復制代碼
- 訪問arguments.callee和arguments.caller,在非嚴格模式下沒有問題,嚴格模式下拋出TypeError。
2.Class基礎語法
在JavaScript當中如何聲明一個類?如何定義類中的方法?如何實例化對象?
我們來看看下面的代碼示例:
// es5 let dada = function(type) { this.type = type } dada.prototype.study = function() { console.log('魔王哪吒'); } let da1 = new dada('程序員') let da2 = new dada('It') da1.constructor.prototype.study = function() { console.log('dadaqianduan'); } da1.study() 復制代碼
JavaScript constructor
屬性
定義和用法
constructor
屬性返回對創建此對象的數組函數的引用。
語法
object.constructor
constructor
是一種用於創建和初始化class
創建的對象的特殊方法。
// es6 class Da { constructor(name) { // 構造函數內寫屬性 this.name = name; } eat() { // 構造函數外寫方法 console.log('i eat') } } const da1 = new Da('da1'); console.log(da1.name); // da1 console.log(da1); 復制代碼
- 一個類中只能有一個名為“constructor"的方法,出現多次構造函數constructor方法會拋出一個SyntaxError錯誤
- 在一個構造方法中可以使用super來調用一個父類的構造方法
- 如果沒有指定一個構造函數方法constructor方法,就會使用一個默認的構造函數
3.類的屬性Setter和Getter
var daObj = {
get val() {
return ;
},
set val(value) {
}
}
復制代碼
get:
var da = { a: 1, get val(){ return this.a + 1; } } console.log(da.val);//2 da.val = 100; console.log(da.val);//2 class Da { constructor(type) { this.type = type } get age() { return 1 } set age(val) { this.realAge = val } eat() { console.log('i am eat') } } let da1 = new Da('da1') console.log(da1.age) da1.age = 1 console.log(da1.realAge) 復制代碼
class Da {
constructor(type, age) {
this.type = type
this.age1 = age
}
get age() {
return this._age
}
set age(val) {
this._age = val
}
}
復制代碼
利用set/get實現對element.innerHTML封裝
class myHTMLElement {
constructor(element) {
this.element = element
}
get html() {
return this.element.innerHTML
}
set html(value) {
this.element.innerHTML = value
}
}
復制代碼
設置一個閉包,通過一定的規則來限制對它的修改:
let myName = 'dada'
class Da {
constructor(type) {
this.type = type
}
get name() {
return myName
}
set name(val) {
myName = val
}
}
復制代碼
4.靜態方法
在es5中實現的靜態方法:
let Da = function (type) { this.type = type this.eat = function() { console.log('i eat') } } Da.study = function(book) { console.log('i book'); } 復制代碼
let Da = function(type) { this.type = type } Da.prototype.eat = function() { Da.walk() console.log('i am') } Da.walk = function(){ console.log('walk') } let da1 = new Da('da1') da1.eat() // walk // i am 復制代碼
靜態方法在你的實例化對象是找不到的
在es6中的靜態方法,標記static
class Da {
constructor(type) {
this.type = type
}
eat() {
console.log('i eat')
}
static study() {
console.log('i study')
}
}
復制代碼
5.如何繼承一個類
在es5中的繼承:
// 定義一個父類
let Da = function(type) {
this.type = type
}
// 定義方法
Da.prototype.eat = function() {
console.log('i am')
}
// 定義靜態方法
Da.study = function(book) {
console.log('i study')
}
// 定義子類
let Da1 = function() {
// 初始化父類
Da.call(this, 'da1');
this.run = function() {
console.log('i run')
}
}
// 繼承
Da1.prototype = Da.prototype
復制代碼
在es6中的繼承
class Da { constructor(type) { this.type = type } eat() { // Da.walk(); console.log('i eat') } static walk(){ console.log('i walk') } } class da extends Da { // 構造函數 //constructor (type) { //super(type) //} run() { console.log('i run') } } let da1 = new da('da1') 復制代碼
6.面向對象編程Class
類的聲明,屬性,方法,靜態方法,繼承,多態,私有屬性
// 類的聲明
let Da = function(type) {
this.type = type
this.eat = function() {
console.log('i eat');
}
}
let da = new Da('da');
復制代碼
// prototype
let Da = function(type) {
this.type = type
}
Da.prototype.eat = function() {
console.log('i eat')
}
let da1 = new Da('da1')
復制代碼
es6中的Class
class Da {
// 構造函數
constructor(type) {
this.type = type
}
// 方法
walk() {
console.log('i walk')
}
}
let da = new Da('da');
// console.log(typeof Da); function
復制代碼
7.函數參數的默認值
函數參數是從左到右解析,如果沒有默認值會被解析成
undefined
// 參數默認值
function da (x,y,z) {
}
function sum() {
let num = 0
Array.prototype.forEach.call(arguments, function(item){
num += item * 1
})
Array.from(arguments).forEach(function(item){
num += item * 1
})
return num
}
復制代碼
// 不確定
function sum(...nums) {
let num = 0
nums.forEach(function(item){
num += item * 1
})
return num
}
console.log(sum(1,2,3,4,5))
復制代碼
function sum () {
let num = 0
Array.prototype.forEach.call(arguments, function (item) {
num += item * 1
})
return num
}
function sum (...nums) {
let num = 0
nums.forEach(function (item) {
num += item * 1
})
return num
}
復制代碼
8.es6箭頭函數
箭頭函數表達式的語法比函數表達式更簡潔,並且沒有自己的this,arguments,super或new.target。箭頭函數表達式更適用於那些本來需要匿名函數的地方,並且它不能用作構造函數。
() => {}
// function Da() {}
// let da = function() {}
let da = () => {
console.log('hello')
}
da()
let da = name => {}
復制代碼
const materials = [ 'Hydrogen', 'Helium', 'Lithium', 'Beryllium' ]; console.log(materials.map(material => material.length)); // expected output: Array [8, 6, 7, 9] 復制代碼
拓展
判斷函數有幾個參數
- 在 ES5 中可以在函數體內使用 arguments 來判斷。
- 在 ES6 中可以借助 Function.length 來判斷。(統計第一個默認參數前面的變量數)
console.log(sum(...[4]))
console.log(sum.apply(null, [4]))
復制代碼
9.JavaScript中的三個點(…)
JavaScript當中,函數的參數前面有三個點,代表什么呢?我們看下代碼示例:
function myFunc(a, b, ...args) {
console.log(a); // 22
console.log(b); // 98
console.log(args); // [43, 3, 26]
};
myFunc(22, 98, 43, 3, 26);
復制代碼
function myFunc(x, y, ...params) { // used rest operator here console.log(x); console.log(y); console.log(params); } var inputs = ["a", "b", "c", "d", "e", "f"]; myFunc(...inputs); // used spread operator here // "a" // "b" // ["c", "d", "e", "f"] 復制代碼
var obj1 = { foo: 'bar', x: 42 }; var obj2 = { foo: 'baz', y: 13 }; var clonedObj = { ...obj1 }; // Object { foo: "bar", x: 42 } var mergedObj = { ...obj1, ...obj2 }; // Object { foo: "baz", x: 42, y: 13 } 復制代碼
10.Object Property
JS中對象的屬性定義,代碼示例如下:
let x = 'da1';
let y = 'da2';
let obj = {
x,
y
}
console.log(obj);
// 結果
{x:'da1',y:'da2'}
復制代碼
let x=1; let y=2; let z=3
let obj = {
'x': x,
y,
[z+y]: 4,
* hello() { // 異步
console.log('dada')
}
}
// function* functionName() {}
obj.hello()
復制代碼
11.Set數據結構
Set存儲的成員不允許的重復的(它類似於數組)
Set 本身是一個構造函數,用來生成 Set 數據結構。
const s = new Set();
[2, 3, 5].forEach(x => s.add(x));
Set 函數可以接受一個數組(或類似數組的對象)作為參數,用來初始化
const set = new Set([1, 2, 3, 4, 4]);
復制代碼
實現數組去重
var arr = [1,1,2,2,3,3]; // step1:數組轉集合
var s = new Set(arr); // 已經去掉重復值,當前不是數組,而集合
s.size; // 3
// step2:集合轉數組
console.log([...s]); // 1,2,3;
// Array.form 方法可以將 Set 結構轉為數組
const items = new Set([1, 2, 3]);
const arr = Array.from(items);
function dada(array) {
return Array.from(new Set(array));
}
dada([1, 1, 2])
復制代碼
Set的遍歷
keys()
:返回鍵名
的遍歷器values()
:返回鍵值
的遍歷器entries()
:返回鍵值對
的遍歷器forEach()
:使用回調函數遍歷每個成員
操作方法
add(value)
:添加某個值
,返回Set結構本身。delete(value)
:刪除某個值
,返回一個布爾值,表示刪除是否成功。has(value)
:返回一個布爾值
,表示該值是否為Set的成員。clear()
:清除所有成員
,沒有返回值。
let set = new Set([1, 2, 3, 4, 4]);
// 添加數據
let addSet = set.add(5);
console.log(addSet); // Set(5) {1, 2, 3, 4, 5}
// 刪除數據
let delSet = set.delete(4);
console.log(delSet); // true
// 查看是否存在數據 4
let hasSet = set.has(4);
console.log(hasSet); // false
// 清除所有數據
set.clear();
console.log(set); // Set(0) {}
復制代碼
實現並集(Union)、交集(Intersect)和差集(Difference)
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2, 1]);
// 並集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {1, 2, 3}
// 差集
let difference = new Set([...b].filter(x => !a.has(x)));
// Set {4}
復制代碼
12.Map數據結構
JS當中的哈希表,使用方法如下:
let map = new Map()
map.set(1, 2)
map.set(3, 4)
map.set(1, 3)
console.log(map)
創建
var da = new Map();
var jeskson = {};
遍歷
da.forEach(function(value,key,map){}
長度
da.size
刪除
//da.delete() 刪除key,全部清楚da.clear()
新增
da.set(key,value)
da.has(查索引值)
da.forEach((value,key) =>{
})
for( let [key, value] of map){}
// let map = new Map( [[1,2], [3,4]] )
map的key任意都可以
let o = function() {
console.log('o')
}
map.set(o, 3)
console.log(map.get(o)); // 3
復制代碼
// map.js
var Dictionary = function() {
var items = {};
// 檢查鍵
this.has = function(key) {
return key in items;
}
// 添加鍵值對
this.set = function(key, value){
items[key] = value;
}
// 通過鍵移除元素
this.delete = function(key) {
if(this.has(key)){
delete items[key]
return true
}
return false
}
// 鍵獲取值
this.get = function(key){
return this.has(key) ? items[key] : undefined;
}
// 列表返回字典值
this.values = function() {
var values = [];
for(var k in items) {
if(this.has(k)) {
values.push(items[k])
}
}
return values;
}
// 獲取全部鍵名
this.keys = function() {
return Object.keys(items);
}
// 獲取私有變量items
this.getItems = function() {
return items;
}
}
復制代碼
Map數據結構,它類似於對象,也是鍵值對的集合,但是“鍵”的范圍不限於字符串,各種類型的值(包括對象)都可以當作鍵。
13.Object.assign(對象的拷貝)
Object.assign() 方法用於將所有可枚舉屬性的值從一個或多個源對象復制到目標對象。它將返回目標對象。
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }
console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }
> Object { a: 1, b: 4, c: 5 }
> Object { a: 1, b: 4, c: 5 }
復制代碼
語法
Object.assign(target, ...sources)
復制代碼
參數
target
復制代碼
目標對象
sources
復制代碼
源對象
返回值
目標對象。
const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
復制代碼
- Object.assign()拷貝的是(可枚舉)屬性值
- Object.assign方法的第一個參數是目標對象,后面的參數都是源對象
- 如果目標對象與源對象有同名屬性,或多個源對象有同名屬性,則后面的屬性會覆蓋前面的屬性
- 由於undefined和null無法轉成對象,所以如果它們作為參數,就會報錯
- 如果undefined和null不在首參數,就不會報錯
- 如果源對象某個屬性的值是對象,那么目標對象拷貝得到的是這個對象的引用(這個對象的任何變化,都會反映到目標對象上面。)
Object.assign(undefined) // 報錯
Object.assign(null) // 報錯
let obj = {a: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
const target = { a: { b: 'c', d: 'e' } }
const source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }
const source = {
get foo() { return 1 }
};
const target = {};
Object.assign(target, source)
// { foo: 1 }
復制代碼
Object.assign復制的是屬性值value,如果屬性值是一個引用類型,那么復制的其實是引用地址,就會存在引用共享的問題(Object.assign(target,source1,...,sourceN)淺拷貝的過程)
要點:

function ObjectAssign(target, ...sources) {
// 對第一個參數的判斷,不能為undefined和null
if(target === undefined || target === null) {
throw my TypeError('error');
}
// 將第一個參數轉為對象(不是對象轉換為對象)
const targetObj = Object(target);
// 將源對象自身的所有可枚舉屬性復制到目標對象
for(let i = 0; i<sources.length; i++){
let source = sources[i];
// 對於undefined和null在源中不會報錯,會直接跳過
if(source !== undefined && source !== null) {
// 將源象轉換成對象
// 需要將源自身的可枚舉數據進行復制
// Reflect.ownKeys(obj)
const keysArray = Reflect.ownKeys(Object(source));
for (let nextIndex = 0; nextIndex < keysArray.length; nextIndex++) {
const nextKey = keysArray[nextIndex];
// 去除不可枚舉屬性
const desc = Object.getOwnPropertyDescriptor(source,nextKey);
if(desc!==undefined&&desc.enumerable){
targetObj[nextKey] = source[nextKey];
}
}
}
}
return targetObj;
}
if(typeof Object.myAssign !== 'function'){
Object.defineProperty(Object, 'myAssign', {
value: ObjectAssign,
writable: true,
enumerable: false,
configurable: true
});
}
復制代碼
淺拷貝 Object.assign 的實現原理
拷貝第一層的基本類似值和第一層的引用類型地址:
let da1 = { name: 'da1', age: 1 } let da2 = { name: 'da2', study: { title: 'web' } } let da3 = Object.assign(da1,da2); console.log(da3); // { // name: 'da2', // age: 1, // study: { title: 'web' } // } console.log( da1 === da3); // true da2.name = 'da22'; da2.study.title = 'web2'; console.log(da2); // { // name: 'da22', // study: { title: 'web2' } // } console.log(da1); // { // age: 1, // name: 'da2', // study: { title: 'web2' } // } 復制代碼
如果源對象的屬性值是一個指向對象的引用,它也只拷貝這個引用地址哦!
let da1 = { name: 'da1', age: 1 } let da2 = { a: Symbol('dadaqianduan'), b: null, c: undefined } let da3 = Object.assign(da1, da2); console.log(da3); // { // name: 'da1', // age: 1, // a: Symbol('dadaqianduan'), // b: null, // c: undefined // } console.log(da1 === da3); // true 復制代碼





let map = new Map([iterable])
// Map是用來實現字典的功能-Object鍵值對
復制代碼

動態屬性鍵
// ES5 code
var
key1 = 'one',
obj = {
two: 2,
three: 3
};
obj[key1] = 1;
// obj.one = 1, obj.two = 2, obj.three = 3
// ES6 code
const
key1 = 'one',
obj = {
[key1]: 1,
two: 2,
three: 3
};
// obj.one = 1, obj.two = 2, obj.three = 3
// ES6 code
const
i = 1,
obj = {
['i' + i]: i
};
console.log(obj.i1); // 1
復制代碼
補充:前端面試考點,HTML和CSS,性能優化,原型,作用域,異步,各種手寫代碼,DOM事件和Ajax,HTTP協議。
- css(布局,定位,移動端響應式)
- es(原型,原型鏈,作用域,閉包,異步,單線程)
- webapi(DOM BOM,Ajax跨域,事件存儲)
- 開發環境(版本管理,調試抓包,打包構建)
- 運行環境(頁面渲染,性能優化,web安全)
- 網絡通訊
- 布局(盒模型,BFC,float,flex)
- 定位,圖文樣式,移動端響應式(rem,media query,vw/vh),動畫、漸變
- 變量類型和計算(值類型和引用類型,類型判斷,邏輯運算)
- 原型和原型鏈(class,繼承,原型,原型鏈,instanceof)
- 作用域和閉包(作用域,自由變量,閉包,this)
- 異步(單線程,callback,應用場景,Promise,event-loop,async/await,微任務/宏任務)
- 模塊化(ES6 Module)
- DOM(樹形結構,節點操作,屬性,樹結構操作,性能)
- BOM(navigator,screen,location,history)
- 事件(綁定,冒泡,代理)
- ajax(XMLHttpRequest,狀態碼,跨域)
- 存儲(cookie,localStorage,sessionStorage)
- 開發環境(git,調試,webpack和babel,linux命令)
- 運行環境(頁面加載:加載,渲染。性能優化:加載資源優化,渲染優化。安全:xss,CSRF)
- HTTP協議:狀態碼,Method,Restful API,headers,緩存策略
14.模板文字
模板文字是es2015/es6的新功能,與es5及以下版本相比,可以通過新穎的方式使用字符串,先只需要反引號代替單引號或雙引號即可:
const module_string = `dadaqianduan` 復制代碼
它們之所以獨特是因為它們提供了很多用引號構建的普通字符串不具備的功能:
- 提供了定義多行字符串的語法;
- 提供了一種簡單的方法來插值字符串中的變量和表達式
- 允許您使用模板標簽創建DSL(領域特定的語言)
使用多行字符串
在es6之前的版本:
// 要創建跨越兩行的字符串,必須\在行尾使用字符 const dada = 'dada \ dadaqianduan' // 呈現效果:在兩行上創建一個字符串,但是僅在一行上呈現 復制代碼
要在多行上呈現,則需要使用\n
在每行的末尾添加
const string =
'dada 魔王哪吒\n \
dadaqianduan'
復制代碼
使用反引號打開模板文字后,只需要按enter鍵就行:
const dada = `dadaqianduan 魔王哪吒` 復制代碼
在這里請記住空間是有意義的:
const da = `First Second` 復制代碼

使用trim()方法,可以消除第一個字符之前的任何空格
插補:模板文字提供了一種將變量和表達式插入字符串的簡便的方法
const da = `dadaqianduan ${mydada}`
${}里面可以添加任何東西
const da1 = `dada ${1+2+3}`
const da2 = `dada ${dafun() ? 'x' : 'y'}`
復制代碼
15.什么是解構賦值
let da = ['hello', 'world']
let [firstName, surName] = da
cosole.log(firstName, surName);
復制代碼
解構賦值在於賦值,拷貝出來賦值給變量,而賦值的元素本身不會發生改變
默認值
let [da1, da2] = []; console.log(da1); // undefined console.log(da2); // undefined 復制代碼
給變量賦值(默認值),防止出現undefined的情況:
let [da1= 'da1', da2 = 'da2']=['dadaqianduan] console.log(da1); // dadaqianduan console.log(da2); // da2 復制代碼
解構分配
ES5中的索引提取這些值:
var myArray = ['a', 'b', 'c']; var one = myArray[0], two = myArray[1], three = myArray[2]; // one = 'a', two = 'b', three = 'c' 復制代碼
ES6解構允許使用更簡單方法:
const [one, , three] = myArray; // one = 'a', three = 'c' 復制代碼
使用rest運算符(...)
提取剩余元素:
const [one, ...two] = myArray; // one = 'a', two = ['b, 'c'] 復制代碼
const myObject = { one: 'a', two: 'b', three: 'c' }; // ES6 destructuring example const {one: first, two: second, three: third} = myObject; // first = 'a', second = 'b', third = 'c' 復制代碼
可變值交換
var a = 1, b = 2; // ES5 swap var temp = a; a = b; b = temp; // a = 2, b = 1 // ES6 swap back [a, b] = [b, a]; // a = 1, b = 2 [b, c, d, e, a] = [a, b, c, d, e]; 復制代碼
在ES6中,我們可以為任何參數分配默認值
function dada(param = {}) {
復制代碼
函數返回多個值(函數只能返回一個值,但可以是一個復雜的對象或多維數組)
function f() { return [1, 2, 3]; } const [a, b, c] = f(); // a = 1, b = 2, c = 3 復制代碼
ES6 JavaScript深度解構
默認情況下,找不到的屬性為undefined
var {da} = {bar: 'dada'} console.log(da) // undefined 復制代碼
如果訪問不存在的父級的深層嵌套屬性,則將獲得異常。
var {da:{bar}} = {dada: 'dadaqianduan'} // Exception 復制代碼
var key = 'dadaqianduan' var { [key]: foo } = { dadaqianduan: 'bar' } console.log(foo) // 'bar' 復制代碼
var {da=3} = { da: 2 } console.log(da) // 2 var {da=3} = { da: undefined } console.log(da) // 3 var {da=3} = { bar: 2 } console.log(da) // 3 var [a] = [] console.log(a) // undefined var [b=10] = [undefined] console.log(b) // 10 var [c=10] = [] console.log(c) // 10 function da () { return { x: 1, y: 2 } } var {x, y} = da() console.log(x) // 1 console.log(y) // 2 復制代碼
16.異步操作
Callback
Promise
function loadScript(src) { return new Promise((resolve, reject) => { let script = document.createElement('script') script.src = src script.onload = () => resolve(src) script.onerror = (err) => reject(err) document.head.append(script) }) } 復制代碼
function loadScript(src) { let script = document.createElement('script'); script.src = src; document.head.append(script) } 復制代碼
var promise = new Promise(function(resolve, reject){
resolve('傳遞給then的值')
})
promise.then(function(value){
console.log(value)
},function(error){
console.error(error)
})
復制代碼
Promise對象是用於表示一個異步操作的最終完成(或失敗),以及其結果值。
示例:
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('da');
}, 200);
});
promise.then((value) => {
console.log(value);
});
console.log(promise);
復制代碼
語法:
new Promise(function (resolve,reject){...});
復制代碼
描述:Promise對象是一個代理對象,被代理的值在Promise對象創建時可能是未知的,它允許你為異步操作的成功和失敗分別綁定相應的處理方法,這讓異步方法可以像同步方法那樣返回值,但並不是立即返回最終執行結果,而是一個能代表未來出現的結果的promise對象。
一個Promise有以下幾種狀態:
- pending,初始狀態,既不是成功,也不是失敗狀態。
- fulfilled,意味着操作成功完成。
- rejected,意味着操作失敗。
pending狀態的Promise對象可能會變為fulfilled狀態並傳遞一個值給相應的狀態處理方法。

Promise.prototype.then
和Promise.prototype.catch
方法返回promise
對象,所以它們可以被鏈式調用。
方法:
Promise.all(iterable)
- 返回一個新的promise對象
- 在iterable參數對象里所有的promise對象都成功時,才會觸發成功
- 當任何一個iterable里面的promise對象失敗,才會觸發promise對象的失敗
- 成功狀態會把一個包含iterable里所有promise返回值的數組作為成功回調的返回值,順序和iterable的順序一樣
- 如果這個新的promise對象觸發了失敗,會把iterable里的第一個觸發失敗的promise對象的錯誤信息作為它的失敗信息
- 場景,多用於處理多個promise對象的狀態集合
Promise.any(iterable)
- 接收一個Promise對象的集合,當其中的一個promise成功,就返回那個成功的promise的值
Promise.reject(reason)
- 返回一個狀態為失敗的Promise對象,然后將失敗信息傳遞給對應的處理方法
Promise.resolve(value)
- 返回一個狀態由給定value決定的Promise對象
Promise原型
屬性:Promise.prototype.constructor
返回被創建的實例函數,默認為Promise函數。
方法:
- Promise.prototype.catch(onRejected)
- Promise.prototype.then(onFulfilled,onRejected)
- Promise.prototype.finally(onFinally)
function myAsyncFunction(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open('GET',url); xhr.onload = () => resolve(xhr.responseText); xhr.onerror = () => reject(xhr.statusText); xhr.send(); }); } 復制代碼
17.ES6代理
- 默認情況下,代理不執行任何操作
示例:
var target = {} var handler = {} var proxy = new Proxy(target, handler) proxy.a = 'b' console.log(target.a) // 'b' console.log(proxy.c === undefined) // true 復制代碼
為了更好地了解代理的有用性,讓我們做一些小練習。
示例:
想象一下,您已經17歲了,即將滿18歲。並且您希望您的程序在打開時自動向您祝賀。為此,您可以使用代理。
var person = { name: "dada", age: 17 }; person = new Proxy(person, { set(target, property, value) { if (value === 18) { console.log("Congratulations! You are of legal age"); Reflect.set(target, property, value); return true; } } }); person.age = 18; if (value < 13 && value > 99) { throw new Error('The age should be between 13 and 99') } else { Reflect.set(target, property, value) } 復制代碼
語法:
let p = new Proxy(target, handler) 復制代碼
- target 用Proxy包裝的目標對象
- handler 一個對象,其屬性是當執行一個操作時定義代理的行為的函數
如果不想再調用key的時候,返回undefined:
console.log(o.dada || '')
復制代碼
使用Proxy
let o = { name: 'dada', age: 1 } let handler = { get(obj, key) { return Reflect.has(obj, key)?obj[key]:'' } } let p = new Proxy(o, handler) console.log(p.from) 復制代碼
希望從服務器獲取的數據只讀,不允許修改:
for (let [key] of Object.entries(response.data)) {
Object.defineProperty(response.data, key, {
writable: false
})
}
復制代碼
使用Proxy:
let data = new Proxy(response.data, { set(obj, key, value) { return false } }) 復制代碼
檢驗邏輯代碼:
// Validator.js export default(obj, key, vlaue) => { if(Reflect.has(key) && value > 20) { obj[key] = value } } import Validator from './Validator' let data = new Proxy(response.data, { set: Validator }) 復制代碼
使用Proxy,對讀寫進行監控:
let validator = { set(target, key, value) { if(key === 'age') { if(typeof value !== 'number' || Number.isNaN(value)) { throw new TypeError('Age must be a number') } if(value<=0){ throw new TypeError('Age must be a positive number') } } return true } } const person = { age: 12 } const proxy = new Proxy(person,validator) proxy.age = 'dada' // TypeError number proxy.age = NaN proxy.age = 0 // positive number proxy.age = 3 復制代碼
示例:每個對象都有一個自己的id
class Component { constructor() { this.proxy = new Proxy({ id: Math.random().toString(36).slice(-8) }) } get id() { return this.proxy.id } } 復制代碼

18.Generator
function * dada() {
for(let i=0; i<2; i++ {
yield console.log(i);
}
}
const da = dada()
da.next()
da.next()
復制代碼
Generator函數與普通函數的區別在於定義的時候有一個*
,執行下面函數:
function* dada() {
console.log('dadaqianduan');
}
dada(); // 沒有執行函數
如需要輸出,改為:
var da = dada();
da.next();
復制代碼
要生成一個自增的id:
var count_id = 0;
function dada_id() {
count_id ++;
return count_id;
}
復制代碼
方法
Generator.prototype.next()
返回一個由 yield表達式生成的值。
Generator.prototype.return()
返回給定的值並結束生成器。
Generator.prototype.throw()
向生成器拋出一個錯誤。
復制代碼
書寫風格:
function *da() {
}
function* da(){
}
復制代碼
方法
Generator對象方法:next,return,throw
通過Next方法來獲取每一次遍歷的結果,這個方法返回一個對象,這個對象包含兩個value和done。
value:當前程序的運行結果 done:遍歷是否結束
next是可以接收參數的,這個參數可以讓你在generator外部給內部傳遞數據,這個參數就是作為yield的返回值。
return()方法可以讓generator遍歷終止
function * da() {
yield 1
yield 2
yield 3
}
var d = da()
console.log(d.next()) // {value:1,done:false}
console.log(d.return()) // {value:undefined,done:true}
console.log(d.next()) // {value:undefined,done:true}
復制代碼
return可以傳入參數,作為返回的value的值
function * da() {
yield 1
yield 2
yield 3
}
var d = da()
console.log(d.nex()) // {value:1,done:false}
console.log(d.return(100)) // {value:100,done:true}
console.log(d.next()) // {value:undefined,done:true}
復制代碼
throw()方法在generator外部控制內部執行的“終斷”
generator函數聲明:
function* genFunc(){...}
const genObj = genFunc();
復制代碼
generator表達式:
const genFunc = function* () {...}
const genObj = genFunc();
復制代碼
對象中定義:
const obj = {
* generatorMethod(){
...
}
}
const genObj = obj.generatorMethod();
復制代碼
類定義(類聲明或類表達式):
class MyClass{
* generatorMethod(){
...
}
}
const myInst = new MyClass();
const genObj = myInst.generatorMethod();
復制代碼
最簡單的iterator遍歷規范:
authors[Symbol.iterator] = function(){
// this
return {
next(){
return{
done:false,
value:1
}
}
}
}
復制代碼
19.module
在es6前,js文件之間的導入,導出是借助require.js,sea.js,如現在使用import,export,來實現原生javascript的導入,導出。
export:
導出變量或者常量
export const da = 'dadaqianduan'
export let da1 = 'da1'
export var da2 = 'da1'
const name = 'dada'
let name1 = 'dada1'
export {
name,
name1
}
導出函數
export function da(value){
console.log(value)
}
const da = (value) => {
console.log(value);
}
export {
da
}
導出Object
export({
name: 'da1',
message: 'dadaqianduan'
})
let da = {
name: 'name1'
}
export {
da
}
導出Class
class Da {
constructor(){
this.id = 1
}
}
export {
Da
}
export class Da {
constructor() {
this.id = 1
}
}
修改導出名稱
const name = 'da1'
export {
name as cname
}
export default name
復制代碼
import
// 直接導入
const name = 'dada'
let name1 = 'dada1'
var name2 = 'dada2'
export {
name as cname
}
export default name2
import name2, {name1, name} from A
復制代碼
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function dada(x,y) {
return sqrt(square(x) + square(y));
}
import {square,da} from 'da';
console.log(square(11)); // 121
console.log();
復制代碼
export default function() {...}
import myFunc from 'myFunc';
export default class{...}
import MyClass from 'MyClass';
const inst = new MyClass();
復制代碼
20.import, export
require
--lib.js--
function add(x,y){
return x + y
}
module.exports = {
add: add,
};
--main.js--
var add = require('lib').addd;
console.log(add(1,2));
復制代碼
import
--lib.js--
export function add(x,y) {
return x + y
}
--main.js--
import {add} from 'lib';
console.log(add(1,2));
復制代碼
--lib.js--
export const sqrt = Math.sqrt;
export function square(x) {
return x * x;
}
export function da(x,y) {
return sqrt(square(x)+square(y));
}
--main.js--
import {square, da} from 'lib'
--myFunc.js--
export default function() {...};
--main.js--
import myFunc from 'myFunc';
myFunc();
復制代碼
21.Array.prototype.includes,Promise
該方法判斷一個數組是否包含一個指定的值,返回布爾值
let da1 = [1,2,3];
console.log(da1.includes(2));
復制代碼
arr.find(function(item){
return item === 1;
})
arr.filter(function(item){
return item === 2;
})
Math.pow(2,3)->2**3
復制代碼
async function firstAsync(){
let promise = new Promise ((resolve,reject) => {
setTimeout(function(){
resolve('dadaqianduan')
},1000)
})
console.log(await promise)
console.log(await Promise.resolve(1))
console.log(2)
return Promise.resolve(3)
}
firstAsync().then(val => {
console.log(val)
})
復制代碼
await后面是Promise對象
Object.values()返回一個數組,其元素是再對象上找到的可枚舉屬性值。
let da = {
'da': 1,
'da2': 2
}
console.log(Object.value(da)) // [1,2]
Object.values是在對象上找到可枚舉的屬性的值,所以只要這個對象是可枚舉的就可以
復制代碼
Object.entries()方法返回一個給定對象自身可枚舉屬性的鍵值對數組
22.JS異步進階
題目一:
Promise.resolve().then(()=>{
console.log(1)
}).catch(()=>{
console.log(2)
}).then(()=>{
console.log(3)
})
復制代碼
題目二:
Promise.resolve().then(()=>{
console.log(1)
throw new Error('da')
}).catch(()=>{
console.log(2)
}).then(()=>{
console.log(3)
})
復制代碼
題目三:
Promise.resolve().then(()=>{
console.log(1)
throw new Error('da')
}).catch(()=>{
console.log(2)
}).catch(()=>{
console.log(3)
})
復制代碼
題目四:
async function fn() {
return 1
}
(async function() {
const a = fn() // ??
const b = await fn() // ??
})()
復制代碼
題目五:
console.log(100)
setTimeout( () => {
console.log(200)
})
Promise.resolve().then( ()=> {
console.log(300)
})
console.log(400)
復制代碼
題目六:
async function async1() {
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2 () {
console.log('async2')
}
console.log('script start')
setTimeout(function(){
console.log('setTimeout')
},0)
async1()
new Promise(function (resolve){
console.log('promise1')
resolve()
}).then(function(){
console.log('promise2')
})
console.log('script end')
復制代碼
加載圖片:
// 加載
function loadImg(src) {
const p = new Promise(
(resolve,reject) => {
const img = document.createElement('img')
img.onload = () =>{
resolve(img)
}
img.onerror = () =>{
const err = new Error('圖片加載失敗')
reject(err)
}
img.src = src
}
)
return p
}
const url = 'https'
const p = loadImg(url)
p.then(img =>{
console.log(img.width)
return img
}).then(img =>{
console.log(img.height)
}).catch(ex => {
console.error(ex)
})
復制代碼
async function async1() {
console.log('async1 start') // 2
await async2() // undefined
console.log('async1 end') // 5
}
async function async2() {
console.log('async2') // 3
}
console.log('script start') // 1
async1()
console.log('script end') // 4
復制代碼
for...of常用於異步的遍歷
function add(num) {
return new Promise(resolve => {
setTimeout(()=>{
resolve(num*num)
},1000)
})
}
const nums = [1,2,3]
nums.forEach(async(i)=>{
const res = await add(i)
})
復制代碼
23.宏任務和微任務
宏任務:setTimeout,setInterval,ajax等 微任務:Promise async/await
微任務執行時比宏任務要早:
宏任務:DOM渲染后觸發,如setTimeout
微任務:DOM渲染前觸發,如Promise
24.For await of 異步操作集合
function da(time) {
return new Promise(function(resolve,reject){
setTimeout(function(){
resolve(time)
},time)
})
}
async function test() {
let arr = [da(2000),da(1000),da(3000)]
for await (let item of arr) {
console.log(Date.now(), item)
}
}
復制代碼
const input = {
a: 1,
b: 2
}
const output = {
...input,
c: 3
}
console.log(output)
const input = {
a: 1,
b: 2,
c: 3
}
let {a, ...rest } = input
復制代碼
25Array.prototype.flat()
該方法會按照一個可指定的深度遞歸遍歷數組,並將所有元素與遍歷到的子數組中的元素合為一個新數組。
Array.prototype.flat()建議將數組遞歸展平至指定范圍depth並返回新數組。
depth(指定要提取嵌套數組的結構深度)
語法:Array.prototype.flat(depth)
depth —默認值1,Infinity用於展平所有嵌套數組。
const numbers = [1, 2, [3, 4, [5, 6]]];
// Considers default depth of 1
numbers.flat();
> [1, 2, 3, 4, [5, 6]]
// With depth of 2
numbers.flat(2);
> [1, 2, 3, 4, 5, 6]
// Executes two flat operations
numbers.flat().flat();
> [1, 2, 3, 4, 5, 6]
// Flattens recursively until the array contains no nested arrays
numbers.flat(Infinity)
> [1, 2, 3, 4, 5, 6]
復制代碼
語法:Array.prototype.flatMap(callback)
callback:function
產生新Array的元素。
const numbers = [1, 2, 3];
numbers.map(x => [x * 2]);
> [[2], [4], [6]]
numbers.flatMap(x => [x * 2]);
> [2, 4, 6]
復制代碼
Object.fromEntries
Object.fromEntries
執行與的相反操作Object.entries
。它將一組鍵值對轉換為一個對象。
const records = [['name','da'], ['age', 32]];
const obj = Object.fromEntries(records);
> { name: 'da', age: 32}
Object.entries(obj);
> [['name','Mathew'], ['age', 32]];
復制代碼
Symbol.prototype.description
只讀屬性,返回Symbol
對象的可選描述:
Symbol('desc').toString();
> "Symbol(desc)"
Symbol('desc').description;
> "desc"
Symbol('').description;
> ""
Symbol().description;
> undefined