變量提高的概念 :深刻理解 js 變量提高html
閉包 :閉包,是真的美前端
談到閉包拉扯到垃圾回收機制 阮一峯JavaScript 內存泄漏教程java
函數式高級編程==》柯里化函數與組合函數node
柯里化函數:「前端進階」完全弄懂函數柯里化git
組合函數:「前端進階」完全弄懂函數組合es6
JS引擎會在正式執行以前先進行一次預編譯,在這個過程當中,首先將變量聲明及函數聲明提高至當前做用域的頂端,而後進行接下來的處理。github
變量提高面試
function hoistVariable() {
var foo = foo || 5;
console.log(foo); // 5
}
---》預編譯以後
function hoistVariable() {
var foo;
foo = foo || 5;
console.log(foo); // 5
}
複製代碼
函數提高算法
function hoistFunction() {
foo(); // output: I am hoisted
function foo() {
console.log('I am hoisted');
}
}
複製代碼
------》編譯以後編程
function hoistFunction() {
function foo() {
console.log('I am hoisted');
}
foo(); // output: I am hoisted
}
複製代碼
閉包就是可以讀取其餘函數內部變量的函數,【在本質上,閉包是將函數內部和函數外部鏈接起來的橋樑】
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result(); // 999
複製代碼
閉包的用途 什麼是閉包?閉包的做用,用法及優缺點
能夠讀取函數內部的變量
讓這些變量的值始終保持在內存中
function f1(){
    nAdd=function(){n+=1} //nAdd是全局函數
  }
複製代碼
使用閉包的注意點
(1)因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露。解決方法是,在退出函數以前,將不使用的局部變量所有刪除
function foo() {
let a = 2;
function bar() {
console.log( a );
}
return bar;
}
let baz = foo();
baz(); //baz指向的對象會永遠存在堆內存中
baz = null; //若是baz再也不使用,將其指向的對象釋放
複製代碼
垃圾回收機制怎麼知道,哪些內存再也不須要呢?:
最常使用的方法叫作"引用計數"(reference counting):語言引擎有一張"引用表",保存了內存裏面全部的資源(一般是各類值)的引用次數。若是一個值的引用次數是0,就表示這個值再也不用到了,所以能夠將這塊內存釋放
const arr = [1, 2, 3, 4];
console.log('hello world');
複製代碼
上面代碼中,數組[1, 2, 3, 4]是一個值,會佔用內存。變量arr是僅有的對這個值的引用,所以引用次數爲1。儘管後面的代碼沒有用到arr,它仍是會持續佔用內存。
若是增長一行代碼,解除arr對[1, 2, 3, 4]引用,這塊內存就能夠被垃圾回收機制釋放了
let arr = [1, 2, 3, 4];
console.log('hello world');
arr = null;
複製代碼
柯里化,能夠理解爲提早接收部分參數,延遲執行,不當即輸出結果,而是返回一個接受剩餘參數的函數。由於這樣的特性,也被稱爲部分計算函數。柯里化,是一個逐步接收參數的過程。在接下來的剖析中,你會深入體會到這一點。
一道經典面試題multi(2)(3)(4)=24?
實現 multi 函數去計算出結果值呢?腦海中首先浮現的解決方案是,閉包
function multi(a) {
return function(b) {
return function(c) {
return a * b * c;
}
}
}
複製代碼
實現方案存在的缺陷
使用函數柯里化 解決
//實現乘積功能,返回得是函數
function multi() {
var args = Array.prototype.slice.call(arguments);//獲取到實參借用數組的slice方法
var fn = function() { //解決多個括號的問題//multi(2,3,4,5)(1,2,7,5)
var newArgs = args.concat(Array.prototype.slice.call(arguments));//獲取數組
return multi.apply(this, newArgs);//調用下面的方法
}
//返回的結果轉字符串,每一次會先執行這個核心方法
fn.toString = function() { //multi(2,3,4,5)
//數組reduce方法相稱
return args.reduce(function(a, b) {
return a * b;
})
}
return fn;//多個括號調用第一個方法fn,否者直接返回
}
複製代碼
柯里化使用場景 簡述幾個很是有用的柯里化函數使用場景 /// JS專題之函數柯里化
----》先不顧忌反柯里化,講到柯里化,能夠在牽扯到另外一個高級編程函數compose組合函數 JavaScript高級編程
compose組合函數 JavaScript專題之函數組合 /// 組合 (compose) /// JS 函數式編程指南
最多見的繼承方法就是使用原型鏈實現繼承
//父類
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
}
//子類
function SubType() {
ths.subproperty = true;
}
//繼承
SubType.prototype = new SuperType();// 實現繼承
SubType.prototype.getSubValue = function() {
return this.subprototype;
}
//實例化
var instance = new SubType();
console.log(instance.getSuperValue());// true
複製代碼
繼承原理 子類SubType默認提供的原型===》它換了一個新原型(即父類SuperType的實例)===》子類SubType具備父類SuperType實例所擁有的所有實現和方法(指向父類SuperType的原型)=======》instance實例具備父類SuperType的subproperty屬性
經過原型鏈尋找原理 調用實例以後的instance的getSuperValue() ===》instance實例上找不到該方法(即子類SubType)====》 順着原型鏈先找到SubType.prototype===》順着原型鏈找到SuperType.prototype。
若是該屬性爲引用類型時,全部的實例都會共享該屬性,一個實例修改了該屬性,其它實例也會發生變化,同時,在建立子類型時,咱們也不能向超類型的構造函數中傳遞參數
(由原型繼承延申至此)爲了解決原型中包含引用類型值所帶來的問題,開發人員開始使用借用構造函數的技術實現繼承,該方法主要是經過apply()和call()方法,在子類型構造函數的內部調用超類型構造函數,從而解決該問題。
function SuperType(name,colors) {
this.name=name;
this.colors = ["red","blue","green"]
}
function SubType(name,colors) {
SuperType.call(this,name,colors);// 實現繼承
this.age = 29;
this.name = "Nasx";
}
var instance1 = new SubType();
var instance2 = new SubType();
instance2.colors.push("black");
console.log(instance1.colors);// red,blue,green
console.log(instance2.colors);// red,blue,green,black
console.log(instance2.name);//
複製代碼
經過使用call()方法,咱們其實是在新建立的SubType實例的環境下調用了SuperType的構造函數,所以,colors屬性是分別存在instance1和instance2實例中的,修改其中一個不會影響另外一個。
call和apply的區別:用來改變this的指向的
傳參列表:第一位傳的都是改變this指向的那個,第二位call能夠一位一位的傳實參列表進去,可是,apply只能傳一位,並且必須是數組形式的實參。
call須要把實參按照形參的個數傳進去,
apply須要傳一個arguments
bind() //返回的是方法,bind的時候傳的參數會預先傳給返回的方法,調用方法時就不用再傳參數了。
function Car(wheelSize,style,c,sitColor,height,width,len){
Wheel.apply(this,[wheelSize,style]);
Sit.apply(this,[c,sitColor]);
Model.apply(this,[height,width,len]);
}
複製代碼
優勢:解決了原型鏈繼承中引用類型的共享問題,同時能夠在子類型構造函數中向超類型構造函數傳遞參數。
缺點:定義方法時,將會在每一個實例上都會從新定義,不能實現函數的複用。
組合繼承主要是將原型鏈和借用構造函數的技術組合到一塊
原型鏈--->實現對原型屬性和方法的基礎
借用構造函數--->實現對實例屬性的基礎
//先經過借用構造函數call實現實例屬性的基礎
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"]
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name,age) {
SuperType.call(this,name);
this.age = age;
}
//借用原型鏈實現對原型的屬性和方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
console.log(this.age);
}
複製代碼
這邊先解決原型鏈/原型
var person = {
name: "Nicholas",
friends: ["Shelby","Court","Van"]
}
var anotherPerson = Object.create(person, {
name: {
value: "Greg"
}
});
console.log(anotherPerson.name); // Greg
複製代碼
讓anotherPerson繼承了person,其中,friends做爲引用類型,將會被全部繼承該對象的對象所共享,而經過傳入第二個參數,咱們能夠定義額外的屬性,修改person中的原有信息。
建立一個僅用於封裝繼承過程的函數,該函數在內部以某種方法來加強對象,最後再返回該對象。
function createAnother(original) {
var clone = Object(original);
// 經過調用函數建立一個新對象
clone.sayHi = function() {
console.log("hi");
}
return clone;
}
複製代碼
看作是傳進去一個對象,而後對該對象進行必定的加工,也就是增長一些方法來加強該對象,而後再返回一個包含新方法的對象的一個過程
var person = {
name: "Nicholas",
friends:["Shelby","Court","Van"]
}
var anotherPerson = createAnother(person);
anotherPerson.sayHi(); // hi
複製代碼
person是沒有包含任何方法的,而經過將person傳進去createAnother方法中進行加工,返回的新對象就包含了一個新的方法
組合繼承是js中最常常用到的一種繼承方法,而咱們前面也已經說了組合繼承的缺點,組合繼承須要調用兩次超類型構造函數,一次是在建立子類型原型的時候,另外一次是在子類型構造函數內部,子類型最終會包含超類型對象的所有實例屬性,可是咱們不得不在調用子類型構造函數時重寫這些屬性。
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"]
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name,age) {
SuperType.call(this,name); // 第二次調用超類型構造函數
this.age = age;
}
SubType.prototype = new SuperType(); // 第一次調用超類型構造函數
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
console.log(this.age);
}
複製代碼
結果就是在SubType.prototype和SubType的實例上都會建立name和colors屬性,最後SubType的實例上的name和colors屬性會屏蔽掉SubType.prototype上的name和colors屬性
寄生組合式繼承主要經過借用構造函數來繼承屬性,經過原型鏈的混成形式來繼承方法,其實就是沒必要爲了指定子類型的原型而調用超類型的構造函數,只須要超類型原型的一個副本就能夠了。
function inheritPrototype(subType,SuperType) {
var prototype = Object(SuperType); // 建立對象
prototype.constructor = subType; // 加強對象
subType.prototype = prototype; // 指定對象
}
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"]
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name,age) {
SuperType.call(this,name);
this.age = age;
}
//避免了在SubType.prototype上面建立的沒必要要的,多餘的屬性
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function() {
console.log(this.age);
}
複製代碼
es6中可使用Class來建立對象,而一樣的道理,在es6中,也新增長了extends實現Class的繼承,Class 能夠經過extends關鍵字實現繼承,這比 ES5 的經過修改原型鏈實現繼承,要清晰和方便不少
class Point {}
class ColorPoint extends Point {}
複製代碼
上面這個例子中能夠實現ColorPoint類繼承Point類,這種簡潔的語法確實比咱們上面介紹的那些方法要簡潔的好多呀。
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
this.color = color; // ReferenceError
super(x, y);
this.color = color; // 正確
}
}
複製代碼
後面還會講到類比繼承
解決全部異步的方式
異步 擼js基礎之異步
加深執行順序的理解 從一道Promise執行順序的題目看Promise實現
手寫題(能夠不會,可是須要大概理解思路以及大意)「中高級前端面試」JavaScript手寫代碼無敵祕籍
看這個就行了 RESTful 架構風格概述
let arr=[1,2,3,4,5];
//forEach s數組遍歷 可傳值
arr.forEach(function(value,index){
console.log(value);
console.log(index)
})
複製代碼
let arr1=arr.map(function(value){
return value*2+1
} )
複製代碼
let arr2=arr.filter(function(value){
return value>2
})
console.log(arr2)
複製代碼
let arr3=arr.some(function(value){
return value>5
})
複製代碼
let arr4=arr.every(function(value){
return value>0
})
console.log(arr4)//true
複製代碼
console.log(arr.indexOf(5));
if(arr.indexOf(5)>1){
console.log("正確")
}
複製代碼
let arr=[1,2,3,4,5];
let result=arr.reduce(function(last,now){
return last+now;
},0)//後邊跟開始跟那個計算
console.log(result)//15
複製代碼
(Number的屬性不用強調)=》檢測有窮數/檢測整數/轉化浮點數/轉化整數/轉化字符串/返回對象原始值
方法用來檢測傳入的參數是不是一個有窮數
ps:返回布爾類型:
Number.isFinite(NaN) //false
Number.isFinite(Infinity); // false
複製代碼
(全局的 isFinite(),會強制轉化類型)不會強制將一個非數值的參數轉換成數值,這就意味着,只有數值類型的值,且是有窮的(finite),才返回 true
方法用來判斷給定的參數是否爲整數
ps:返回布爾類型
Number.isInteger("10"); // false
Number.isInteger(-100000); // true
複製代碼
注意 NaN 和正負 Infinity 不是整數。
Number.isSafeInteger():表示給定的值是不是一個安全整數(safe integer)。很少用
Number.parseFloat(string):被解析的字符串
ps:一個字符串解析成浮點數。該方法與全局的 parseFloat() 函數相同,對(**首字符不可爲非數值**)字母**會進行隱式轉化刪除**
Number.parseFloat("sss") //NaN
Number.parseFloat(true) //NaN
複製代碼
給定值被解析成浮點數,若是沒法被解析成浮點數,則返回NaN
方法依據指定基數 [ 參數 radix 的值],把字符串 [ 參數 string 的值] 解析成整數。(指定轉化什麼進制的)
ps:一個字符串能夠解析指定的多少進制,對(首字符不可爲非數值)字母會進行隱式轉化刪除
Number.parseInt('0110', 2) //6
Number.parseInt('0110', 10) //110
Number.parseInt('1000s') //1000
Number.parseInt('d1d0d00s') //NaN
複製代碼
reaix無關緊要,radix爲指定基數(即字符串以多少進制的數字表示),默認十進制
返回指定 Number 對象的字符串表示形式
ps:---radix指定返回多少進制
(18).toString() //"18"
18.toString() //Invalid or unexpected token
(6).toString(2) // '110'
複製代碼
Number 對象覆蓋了 Object 對象上的 toString() 方法,它不是繼承的 Object.prototype.toString()。對於 Number 對象,toString() 方法以指定的基數返回該對象的字符串表示。
進行數字到字符串的轉換時,建議用小括號將要轉換的目標括起來,防止出錯。
返回一個被 Number 對象包裝的原始值。
ps:該方法一般是由 JavaScript 引擎在內部隱式調用的,而不是由用戶在代碼中顯式調用的。
var numObj = new Number(10);
console.log(typeof numObj); // object
var num = numObj.valueOf();
console.log(num); // 10
console.log(typeof num); // number
複製代碼
細講重要的屬性和方法 ---------- 獲取函數名稱/長度/調用函數caller/apply數組/call 列表/bind 函數
返回調用指定函數的函數(函數A使用Function.caller,函數B調用函數A【Function.caller返回函數B】) 掘金
ps : arguments.callee.caller替代了被廢棄的 arguments.caller 【callee返回正在執行的函數對象】
function myFunc() {
if (myFunc.caller == null) {
return ("該函數在全局做用域內被調用!");
} else
return ("調用個人是函數是" + myFunc.caller);
}
function ss(){
console.log(myFunc())
}
ss() // 調用個人是函數是function ss(){console.log(myFunc())}
複製代碼
若是一個函數f是在全局做用域內被調用的,則f.caller爲null,相反,若是一個函數是在另一個函數做用域內被調用的,則f.caller指向調用它的那個函數
屬性指明函數的形參個數
ps:length 是函數對象的一個屬性值,指該函數有多少個必需要傳入的參數,即形參的個數
console.log((function(a, b) {}).length); /* 2 etc. */
console.log((function(...args) {}).length) // 0, 其餘參數不計算在內
console.log((function(a, b = 1, c) {}).length);
// 1, b=1是計算,阻斷了計算
// 只有一個a
複製代碼
【arguments.length 是函數被調用時實際傳參的個數】,Function.prototype 對象的 length 屬性值爲 0
函數聲明的名稱:(直接返回名稱)
function doSomething() { }
doSomething.name; // "doSomething"
複製代碼
構造函數的名稱 :變量和方法能夠從句法位置推斷匿名函數的名稱
ps:不能經過此方法賦值更改函數的名稱,此屬性是隻讀的,要更改它,可使用Object.defineProperty()
var f = function() {};
var object = {
someMethod: function() {}
someMethods: function object_someMethod() {}
};
console.log(f.name); // "f"
console.log(object.someMethod.name); // "someMethod"
console.log(object.someMethods.name); // "object_someMethod"
複製代碼
簡寫方法的名稱
var o = {
foo(){}
};
o.foo.name; // "foo";
複製代碼
綁定函數的名稱 : Function.bind() 所建立的函數將會在函數的名稱前加上"bound " 。
function foo() {};
foo.bind({}).name; // "bound foo"
複製代碼
【數組】調用一個具備給定this值的函數,以及做爲一個數組(或相似數組對象)提供的參數。
ps:call()方法的做用和 apply() 方法相似,區別就是call()方法接受的是參數列表,而apply()方法接受的是一個參數數組。
var numbers = [5, 6, 2, 3, 7];
var max = Math.max.apply(null, numbers);
console.log(max);
// expected output: 7
複製代碼
語法:function.apply( thisArg , [ argsArray ] )
thisArg: 可選的。在 func 函數運行時使用的** this** 值來改變this指向
argsArray:可選的。一個數組或者類數組對象,其中的數組元素將做爲單獨的參數傳給 func 函數。若是該參數的值爲null 或 undefined,則表示不須要傳入任何參數
調用有指定this值和參數的函數的結果。
用 apply 將數組添加到另外一個數組(concat確實具備咱們想要的行爲,但它實際上並不附加到現有數組,而是建立並返回一個新數組)
var array = ['a', 'b'];
var elements = [0, 1, 2];
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]
複製代碼
方法使用一個指定的 this 值和單獨給出的一個或多個參數來調用一個函數
-------------------------------------------------使用 call 方法調用父構造函數
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
//調用父構造函數
Product.call(this, name, price);
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
// expected output: "cheese"
複製代碼
-------------------------------------------------使用 call 方法調用匿名函數
var animals = [
{ species: 'Lion', name: 'King' },
{ species: 'Whale', name: 'Fail' }
];
for (var i = 0; i < animals.length; i++) {
(function(i) {
this.print = function() {
console.log('#' + i + ' ' + this.species
+ ': ' + this.name);
}
this.print();
}).call(animals[i], i);
}
複製代碼
-------------------------------------------------使用 call 方法調用函數而且指定上下文的 'this'
function greet() {
var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
console.log(reply);
}
var obj = {
animal: 'cats', sleepDuration: '12 and 16 hours'
};
greet.call(obj); // cats typically sleep between 12 and 16 hours
複製代碼
建立一個新的函數,在bind()被調用時,這個新函數的this被bind的第一個參數指定,其他的參數將做爲新函數的參數供調用時使用
-----------------------------------------------------例子
var module = {
x: 42,
getX: function() {
return this.x;
}
}
var unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// expected output: undefined
var boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// expected output: 42
複製代碼
---------------------------------------------------實現bind
//判斷瀏覽器是否function內置bind方法
if(!Function.prototype.bind){
Function.prototype.bind = function(oThis) {
if(typeof this !== 'function'){
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable')
}
//獲取參數,從1開始(爲啥呢,由於bind方法有個this指向問題)
var args=Array.prototype.slice.call(arguments,1),
fToBind = this, //指向的是綁定的函數
fNOP=function(){},//定義空函數(由於返回的是一個函數)
fBound=function(){
// this instanceof fBound === true時,說明返回的fBound被當作new的構造函數調用
return fToBind.apply(this instanceof fBound?this:oThis,Args.concat(Array.prototype.slice.call(arguments))) //借用方法
}
// 維護原型關係(this指向不是window)
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
// 下行的代碼使fBound.prototype是fNOP的實例,所以
// 返回的fBound若做爲new的構造函數,new生成的新對象做爲this傳入fBound,新對象的__proto__就是fNOP的實例
fBound.prototype = new fNOP();
return fBound;
}
}
複製代碼
方法返回一個表示當前函數源代碼的字符串。
幾乎全部的 JavaScript 對象都是 Object 的實例;一個典型的對象繼承了Object.prototype的屬性(包括方法)
返回建立實例對象的 Object 構造函數的引用。注意,此屬性的值是對函數自己的引用,而不是一個包含函數名稱的字符串
//實例對象是Object
var o = {};
o.constructor === Object; // true
var o = new Object;
o.constructor === Object; // true
複製代碼
方法用於將全部可枚舉屬性的值從一個或多個源對象複製到目標對象。它將返回目標對象。
用法
複製一個對象
const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }
複製代碼
深拷貝問題:深拷貝屬性值(對象裏的屬性),淺拷貝對象(對象裏的對象)
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}}
obj2.b.c = 3;
console.log(JSON.stringify(obj1)); // { a: 1, b: { c: 3}}
console.log(JSON.stringify(obj2)); // { a: 2, b: { c: 3}}
複製代碼
合併對象
const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };
const obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目標對象自身也會改變。
複製代碼
合併具備相同屬性的對象
const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };
const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
複製代碼
原始類型會被包裝爲對象
const v1 = "abc";
const v2 = true;
const v3 = 10;
const v4 = Symbol("foo")
const obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// 原始類型會被包裝,null 和 undefined 會被忽略。
// 注意,只有字符串的包裝對象纔可能有自身可枚舉屬性。
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
複製代碼
異常會打斷後續拷貝任務
建立一個新對象,使用現有的對象來提供新建立的對象的__proto__((指定_proto_)可用來指定原型)
語法:Object.create(proto[, propertiesObject])
------------繼承之原型式繼承
var person={
name:"Nicho",
friends:["Shelby","Count","Van"]
}
var anthor=Object.create(person,{
name:{
value:"Geral"
}
})
console.log(anthor.name) //Geral
複製代碼
----------------繼承之類比繼承
// Shape - 父類(superclass)
function Shape() {
this.x = 0;
this.y = 0;
}
// 父類的方法
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - 子類(subclass)
function Rectangle() {
Shape.call(this); // call super constructor.
}
// 子類續承父類
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?',
rect instanceof Rectangle); // true
複製代碼
方法直接在一個對象上定義一個或多個新的屬性或修改現有屬性,並返回該對象 學習
語法: Object.defineProperties(obj, props)
obj: 將要被添加屬性或修改屬性的對象
props: 該對象的一個或多個鍵值對定義了將要爲對象添加或修改的屬性的具體配置
var obj = {};
Object.defineProperties(obj, {//數據描述符
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
});
複製代碼
數據(數據述符)屬性
configurable:爲false,則不可以使用delete操做符(在嚴格模式下拋出錯誤), 修改全部內部屬性值會拋出錯誤,在《javaScript高級教程中》說只能夠改變writable的值,如今改變writable的值也會拋出錯誤,默認爲 false。
Enumerable:該屬性是否可枚舉,便是否經過for-in或Object.keys()返回屬性,若是直接使用字面量定義對象,默認爲 false
value:與屬性關聯的值。能夠是任何有效的JavaScript值(數字,對象,函數等),默認爲 undefined.
writable:當且僅當該屬性的writable爲true時,value才能被賦值運算符改變。默認爲 false。
方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象。
若是不指定configurable, writable, enumerable ,則這些屬性默認值爲false,若是不指定value, get, set,則這些屬性默認值爲undefined
語法:Object.defineProperty(obj, prop, descriptor)
obj: 須要被操做的目標對象
prop: 目標對象須要定義或修改的屬性的名稱
descriptor: 將被定義或修改的屬性的述符
var o = {}; // 建立一個新對象
// 在對象中添加一個屬性與數據描述符的示例(數據描述符)
Object.defineProperty(o, "a", {
value : 37,
writable : true,
enumerable : true,
configurable : true
});
// 對象o擁有了屬性a,值爲37
// 在對象中添加一個屬性與存取描述符的示例(存取數據夫)
var bValue;
Object.defineProperty(o, "b", {
get : function(){ //獲取操做
return bValue;
},
set : function(newValue){ //攔截操做
bValue = newValue;
},
enumerable : true,
configurable : true
});
o.b = 38; // newValue爲38 o.b也是38
複製代碼
存取描述符屬性
configurable:爲false,則不可以使用delete操做符(在嚴格模式下拋出錯誤), 修改全部內部屬性值會拋出錯誤,在《javaScript高級教程中》說只能夠改變writable的值,如今改變writable的值也會拋出錯誤,默認爲 false。
Enumerable:該屬性是否可枚舉,便是否經過for-in或Object.keys()返回屬性,若是直接使用字面量定義對象,默認爲 false
get:一個給屬性提供 getter 的方法,若是沒有 getter 則爲 undefined。當訪問該屬性時,該方法會被執行,方法執行時沒有參數傳入,可是會傳入this對象(因爲繼承關係,這裏的this並不必定是定義該屬性的對象)。
Set:一個給屬性提供 setter 的方法(給對象屬性設置值時調用的函數),若是沒有 setter 則爲 undefined。該方法將接受惟一參數,並將該參數的新值分配給該屬性。默認爲 undefined
configurable | enumerable | value | writable | get | set | |
---|---|---|---|---|---|---|
數據描述符 | Yes | Yes | Yes | Yes | No | No |
存取描述符 | Yes | Yes | No | No | Yes | Yes |
若是一個描述符不具備value,writable,get 和 set 任意一個關鍵字,那麼它將被認爲是一個數據描述符。若是一個描述符同時有(value或writable)和(get或set)關鍵字,將會產生一個異常。
返回一個給定對象自身可枚舉屬性的鍵值對數組,其排列與使用 for...in 循環遍歷該對象時返回的順序一致(區別在於 for-in 循環也枚舉原型鏈中的屬性)。
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
// array like object
const obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(obj)); // [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ]
// array like object with random key ordering
const anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.entries(anObj)); // [ ['2', 'b'], ['7', 'c'], ['100', 'a'] ]
複製代碼
凍結一個對象。一個被凍結的對象不再能被修改;凍結了一個對象則不能向這個對象添加新的屬性,不能刪除已有屬性,不能修改該對象已有屬性的可枚舉性、可配置性、可寫性,以及不能修改已有屬性的值。此外,凍結一個對象後該對象的原型也不能被修改。freeze() 返回和傳入的參數相同的對象。
方法接收一個鍵值對的列表參數,並返回一個帶有這些鍵值對的新對象
Map 轉化爲 Object
const map = new Map([ ['foo', 'bar'], ['baz', 42] ]);
const obj = Object.fromEntries(map);
console.log(obj); // { foo: "bar", baz: 42 }
複製代碼
Array 轉化爲 Object
const arr = [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ];
const obj = Object.fromEntries(arr);
console.log(obj); // { 0: "a", 1: "b", 2: "c" }
複製代碼
返回指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不須要從原型鏈上進行查找的屬性)
var person = {
name: '張三',
age: 18
}
var desc = Object.getOwnPropertyDescriptor(person, 'name');
console.log(desc) 結果以下
// {
// configurable: true,
// enumerable: true,
// writable: true,
// value: "張三"
// }
複製代碼
所指定對象的全部自身屬性的描述符,若是沒有任何自身屬性,則返回空對象
var person = {
name: '張三',
age: 18
}
var desc = Object.getOwnPropertyDescriptors(person);
console.log(desc)
複製代碼
返回一個由指定對象的全部自身屬性的屬性名(包括不可枚舉屬性但不包括Symbol值做爲名稱的屬性)組成的數組。
ps:返回一個數組,該數組對元素是 obj自身擁有的枚舉或不可枚舉屬性名稱字符串。 數組中枚舉屬性的順序與經過 for...in 循環(或 Object.keys)迭代該對象屬性時一致。數組中不可枚舉屬性的順序未定義。
var arr = ["a", "b", "c"];
console.log(Object.getOwnPropertyNames(arr).sort()); // ["0", "1", "2", "length"]
// 類數組對象
var obj = { 0: "a", 1: "b", 2: "c"};
console.log(Object.getOwnPropertyNames(obj).sort()); // ["0", "1", "2"]
複製代碼
var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true
複製代碼
方法會返回一個由一個給定對象的自身可枚舉屬性組成的數組,數組中屬性名的排列順序和使用 for...in 循環遍歷該對象時返回的順序一致 。若是對象的鍵-值都不可枚舉,那麼將返回由鍵組成的數組。
obj:要返回其枚舉自身屬性的對象。
// simple array
var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']
// array like object
var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj)); // console: ['0', '1', '2']
// array like object with random key ordering
var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj)); // console: ['2', '7', '100']
複製代碼
使用 hasOwnProperty 方法判斷屬性是否存在
o = new Object();
o.prop = 'exists';
function changeO() {
o.newprop = o.prop;
delete o.prop;
}
o.hasOwnProperty('prop'); // 返回 true
changeO();
o.hasOwnProperty('prop'); // 返回 false
複製代碼
自身屬性與繼承屬性
o = new Object();
o.prop = 'exists';
o.hasOwnProperty('prop'); // 返回 true
o.hasOwnProperty('toString'); // 返回 false 繼承屬性
o.hasOwnProperty('hasOwnProperty'); // 返回 false 繼承屬性
複製代碼
toString() 返回 "[object type]"
> 能夠經過 toString() 來獲取每一個對象的類型。爲了每一個對象都能經過 Object.prototype.toString() 來檢測,須要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式來調用,傳遞要檢查的對象做爲第一個參數,稱爲 thisArg。
var toString = Object.prototype.toString;
toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]
//Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]
複製代碼
URIError 對象用來表示以一種錯誤的方式使用全局URI處理函數而產生的錯誤。
TypeError(類型錯誤) 對象用來表示值的類型非預期類型時發生的錯誤。
SyntaxError 對象表明嘗試解析語法上不合法的代碼的錯誤
ReferenceError(引用錯誤) 對象表明當一個不存在的變量被引用時發生的錯誤。
RangeError對象標明一個錯誤,當一個值不在其所容許的範圍或者集合中。
InternalError 對象表示出如今JavaScript引擎內部的錯誤。 例如: "InternalError: too much recursion"(內部錯誤:遞歸過深
EvalError eval 函數的錯誤.此異常再也不會被JavaScript拋出,可是EvalError對象仍然保持兼容性.
函數解碼一個由encodeURI 先前建立的統一資源標識符(URI)或相似的例程。
decodeURI("https://developer.mozilla.org/ru/docs/JavaScript_%D1%88%D0%B5%D0%BB%D0%BB%D1%8B");
// "https://developer.mozilla.org/ru/docs/JavaScript_шеллы"
複製代碼
方法用於解碼由 encodeURIComponent 方法或者其它相似方法編碼的部分統一資源標識符(URI)
decodeURIComponent("JavaScript_%D1%88%D0%B5%D0%BB%D0%BB%D1%8B");
// "JavaScript_шеллы"
複製代碼
函數經過將特定字符的每一個實例替換爲一個、兩個、三或四轉義序列來對統一資源標識符 (URI) 進行編碼
是對統一資源標識符(URI)的組成部分進行編碼的方法
使用var聲明變量嚴格模式中將不經過
何使用'eval'的操做都會被禁止
eval做用域
with被禁用
caller/callee 被禁用
禁止擴展的對象添加新屬性會報錯
除系統內置的屬性會報錯
delete使用var聲明的變量或掛在window上的變量報錯
delete不可刪除屬性(isSealed或isFrozen)的對象時報錯
對一個對象的只讀屬性進行賦值將報錯
對象有重名的屬性將報錯
函數有重名的參數將報錯
八進制表示法被禁用
arguments嚴格定義爲參數,再也不與形參綁定
函數必須聲明在頂層
ES5裏新增的關鍵字不能當作變量標示符使用,如implements, interface, let, package, private, protected, pulic, static, yield
call/apply的第一個參數直接傳入不包裝爲對象
call/apply的第一個參數爲null/undefined時,this爲null/undefined
bind的第一個參數爲null/undefined時,this爲null/undefined
前言:只寫以爲有用的
repeat方法返回一個新字符串,表示將原字符串重複n次。
'x'.repeat(3) // "xxx"
'na'.repeat(2.9) // "nana"
複製代碼
若是某個字符串不夠指定長度,會在頭部或尾部補全。padStart()用於頭部補全,padEnd()用於尾部補全。
'x'.padStart(4, 'ab') // 'abax' 在x前面的
'x'.padEnd(5, 'ab') // 'xabab'
複製代碼
--(若是原字符串的長度,等於或大於最大長度,則字符串補全不生效,返回原字符串。)
'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'
複製代碼
消除字符串的空格--trim()[ES2019 對字符串實例新增了trimStart()和trimEnd()]
前言:只寫以爲有用的
實例方法:isFinite()--數值是否爲有限 實例方法:.isInteger()--數值是否爲整數
Number.isFinite()用來檢查一個數值是否爲有限的(finite),即不是Infinity。【Number.isNaN()用來檢查一個值是否爲NaN。】
ES6 將全局方法parseInt()和parseFloat(),移植到Number對象上面,行爲徹底保持不變。【是逐步減小全局性方法,使得語言逐步模塊化。】
// ES5的寫法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45
// ES6的寫法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
複製代碼
Number.isInteger()用來判斷一個數值是否爲整數。
Number.isInteger(25) // true
Number.isInteger(25.1) // false
複製代碼
前言:只寫以爲有用的
實例方法:Math.trunc--去除一個數的小數部分,返回整數部分 實例方法:Math.sign--判斷一個數究竟是正數、負數、仍是零 實例方法:Math.cbrt:計算一個數的立方根
Math.trunc方法用於去除一個數的小數部分,返回整數部分。
Math.trunc(4.1) // 4
Math.trunc(4.9) // 4
複製代碼
Math.sign方法用來判斷一個數究竟是正數、負數、仍是零。對於非數值,會先將其轉換爲數值。
參數爲正數,返回+1;
參數爲負數,返回-1;
參數爲 0,返回0;
參數爲-0,返回-0;
其餘值,返回NaN。
複製代碼
Math.cbrt方法用於計算一個數的立方根。 Math.cbrt('8') // 2
前言:擴展運算符...,將一個數組轉爲用逗號分隔的參數序列,有點for的意思。
1.數組疊加
//items變成序列加到array數組裏
function push(array, ...items) {
array.push(...items);
}
複製代碼
2.擴展運算符與正常的函數參數能夠結合使用,很是靈活。
//「...」,數組變成參數
function add(x, y) {
return x + y;
}
const numbers = [4, 38];
add(...numbers) // 42-----add(4,38)
複製代碼
3.擴展運算符後面還能夠放置表達式
const arr = [
...(x > 0 ? ['a'] : []),
'b',
];
複製代碼
4.擴展運算符後面是一個空數組,則不產生任何效果
[...[], 1]
// [1]
複製代碼
5.函數調用時,擴展運算符才能夠放在圓括號中,不然會報錯
(...[1, 2]) // Uncaught SyntaxError: Unexpected number
console.log((...[1, 2])) // Uncaught SyntaxError: Unexpected number
-----擴展運算符取代apply方法
// ES6 的寫法 Math.max(...[14, 3, 77])
// 等同於 Math.max(14, 3, 77);
-------經過push函數,將一個數組添加到另外一個數組的尾部。
// ES6 的寫法 let arr1 = [0, 1, 2]; let arr2 = [3, 4, 5]; arr1.push(...arr2);
擴展運算符的應用
(1) 複製數組
//a2並非a1的克隆,而是指向同一份數據的另外一個指針。修改a2,會直接致使a1的變化
[
const a1 = [1, 2];
const a2 = a1;
]
//擴展運算符提供了複製數組的簡便寫法【修改a2,不會直接致使a1的變化】
const a1 = [1, 2];
// 寫法一
const a2 = [...a1];
// 寫法二
const [...a2] = a1;
複製代碼
(2)合併數組
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];
// ES5 的合併數組
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6 的合併數組
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
複製代碼
(3)解構賦值 tip:將擴展運算符用於數組賦值,只能放在參數的最後一位,不然會報錯
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
const [...butLast, last] = [1, 2, 3, 4, 5];
// 報錯
複製代碼
(4)字符串 tip:擴展運算符還能夠將字符串轉爲真正的數組。
[...'hello']
// [ "h", "e", "l", "l", "o" ]
複製代碼
(5)實現了 Iterator 接口的對象 tip:querySelectorAll方法返回的是一個NodeList對象。 它不是數組,而是一個相似數組的對象。 這時,擴展運算符能夠將其轉爲真正的數組。
let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
複製代碼
tip:方法用於將兩類對象轉爲真正的數組: 相似數組的對象(array-like object)和可遍歷(iterable)的對象【(包括 ES6 新增的數據結構 Set 和 Map).】
所謂相似數組的對象,本質特徵只有一點,即必須有length屬性。
所以,任何有length屬性的對象,均可以經過Array.from方法轉爲數組.
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
複製代碼
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
複製代碼
tips:將指定位置的成員複製到其餘位置(會覆蓋原有成員),而後返回當前數組
target(必需):從該位置開始替換數據。若是爲負值,表示倒數。
start(可選):從該位置開始讀取數據,默認爲 0。若是爲負值,表示倒數。
end(可選):到該位置前中止讀取數據,默認等於數組長度。若是爲負值,表示倒數。
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5] 三個參數都是數組裏讀取
複製代碼
find() 找出第一個符合條件的數組成員。【只找一個】
findIndex() 方法的用法與find方法很是相似,返回第一個符合條件的數組成員的位置,
能夠接受三個參數,依次爲當前的值、當前的位置和原數組。
fill方法使用給定值,填充一個數組
['a', 'b', 'c'].fill(7, 1, 2)
// ['a', 7, 'c']
複製代碼
方法返回一個布爾值,表示某個數組是否包含給定的值,與字符串的includes方法相似
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
該方法的第二個參數表示搜索的起始位置
[1, 2, 3].includes(3, 3); // false
複製代碼
flat()嵌套的數組「拉平」,變成一維的數組。該方法返回一個新數組
[1, 2, [3, 4]].flat()
// [1, 2, 3, 4]
複製代碼
無論有多少層嵌套,都要轉成一維數組,能夠用Infinity關鍵字做爲參數,有空位,flat()方法會跳過空位。
[1, [2, [3]]].flat(Infinity)
// [1, 2, 3]
複製代碼
flatMap()方法對原數組的每一個成員執行一個函數(至關於執行Array.prototype.map()), 而後對返回值組成的數組執行flat()方法。該方法返回一個新數組,不改變原數組。
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]
複製代碼
前言:ES6 對它進行了重大升級,本章介紹數據結構自己的改變;
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同於
const baz = {foo: foo};
複製代碼
const person = {
sayName() {
console.log('hello!');
},
};
person.sayName.name // "sayName"
複製代碼
this關鍵字老是指向函數所在的當前對象,ES6 又新增了另外一個相似的關鍵字super,指向當前對象的原型對象
const proto = {
foo: 'hello'
};
const obj = {
foo: 'world',
find() {
return super.foo;
}
};
Object.setPrototypeOf(obj, proto);
obj.find() // "hello"
複製代碼
比較兩個值是否嚴格相等Object.is()
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
複製代碼
用於對象的合併Object.assign()
(1)目標對象與源對象有同名屬性,或多個源對象有同名屬性,則後面的屬性會覆蓋前面的屬性。
(2)若是該參數不是對象,則會先轉成對象,而後返回。
(3)因爲undefined和null沒法轉成對象,因此若是它們做爲參數,就會報錯。-----不在首參數,就不會報錯
(4)除了字符串會以數組形式,拷貝入目標對象,其餘值都不會產生效果
(5)Object.assign方法實行的是淺拷貝-----對象的任何變化,都會反映到目標對象上面
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
const obj = {a: 1};
Object.assign(obj) === obj // true
複製代碼
Object.assign方法用處不少
(1)爲對象添加屬性
class Point { constructor(x, y) { Object.assign(this, {x, y});//等同於 this.x=x;this.y=y } }
(2)爲對象添加方法
Object.assign(SomeClass.prototype, {
someMethod(arg1, arg2) {
···
},
anotherMethod() {
···
}
});
複製代碼
(3)克隆對象--克隆它繼承的值。若是想要保持繼承鏈
function clone(origin) {
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto), origin);
}
複製代碼
(4)合併多個對象
const merge =
(...sources) => Object.assign({}, ...sources);
複製代碼
(5)爲屬性指定默認值
返回某個對象屬性的描述對象(descriptor)------Object.getOwnPropertyDescriptors()----引入目的:Object.assign()沒法正確拷貝get屬性和set屬性的問題。
Object.setPrototypeOf(),Object.getPrototypeOf()獲取設置原型對象
{constructor: ƒ, defineGetter: ƒ, defineSetter: ƒ, hasOwnProperty: ƒ, lookupGetter: ƒ, …}
Object.keys方法,返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷(enumerable)屬性的鍵名
var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
複製代碼
Object.values方法返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷(enumerable)屬性的鍵值。
const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]
複製代碼
Object.entries()方法返回一個數組,成員是參數對象自身的(不含繼承的)全部可遍歷(enumerable)屬性的鍵值對數組
const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
複製代碼
Object.fromEntries()---方法是Object.entries()的逆操做,用於將一個鍵值對數組轉爲對象。
Object.fromEntries([
['foo', 'bar'],
['baz', 42]
])
// { foo: "bar", baz: 42 }
複製代碼
<script>
const modle = "一切皆對象";
let alerts = ["請你回答Yes Or No", { "selset": "Yes", "Yes": "在弱類型語言JavaScript面前的確有時候一切皆對象" }, { "selset": "No", "No": "同志你還沒學透徹啊!" }];
let sheet=["Object.assign",{"info":"目標對象與源對象有同名屬性,或多個源對象有同名屬性,則後面的屬性會覆蓋前面的屬性"},{"info":"若是該參數不是對象,則會先轉成對象,而後返回"},{"info":"因爲undefined和null沒法轉成對象,因此若是它們做爲參數,就會報錯。-----不在首參數,就不會報錯"},{"info":"除了字符串會以數組形式,拷貝入目標對象,其餘值都不會產生效果"},{"info":"Object.assign方法實行的是淺拷貝-----對象的任何變化,都會反映到目標對象上面"}]
var name = prompt(modle);
for (let i = 0; i < alerts.length; i++) {
if (Object.is(i, 0)) {
if (Object.is(name, alerts[i + 1]["selset"]) || Object.is(name, alerts[i + 2]["selset"])) {
Object.is(name, alerts[i + 1]["selset"]) ? alert(alerts[i + 1][alerts[i + 1]["selset"]]) : alert(alerts[i + 1][alerts[i + 2]["selset"]]);
} else {
name = window.confirm(alerts[i]);
if (name) {
alert("你很棒幫哦")
}else{
alert("你個菜雞");
}
}
}else{
Object.assign(alerts,sheet);
alert(alerts[i]["info"]);
}
}
</script>
複製代碼
前言: ES6 引入了一種新的原始數據類型Symbol,表示獨一無二的值。它是 JavaScript 語言的第七種數據類型
注意:Symbol函數前不能使用new命令,不然會報錯。 let s = Symbol();
這是由於生成的 Symbol 是一個原始類型的值,不是對象。 也就是說,因爲 Symbol 值不是對象,因此不能添加屬性 。 typeof s 基本上,它是一種相似於字符串的數據類型。 // "symbol"
// 沒有參數的狀況
let s1 = Symbol();
let s2 = Symbol();
s1 === s2 // false
// 有參數的狀況
let s1 = Symbol('foo');
let s2 = Symbol('foo');
s1 === s2 // false
複製代碼
let sym = Symbol('My symbol');
"your symbol is " + sym
// TypeError: can't convert symbol to string
複製代碼
String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'
複製代碼
symbol.description // "My symbol"
複製代碼
寫法
let mySymbol = Symbol();
// 第一種寫法
let a = {};
a[mySymbol] = 'Hello!';
// 第二種寫法
let a = {
[mySymbol]: 'Hello!'
};
// 第三種寫法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上寫法都獲得一樣結果
a[mySymbol] // "Hello!"
複製代碼
2.風格良好的代碼,應該儘可能消除魔術字符串,改由含義清晰的變量代替。
const shapeType = {
triangle: 'Triangle'
};//變量
function getArea(shape, options) {
let area = 0;
switch (shape) {
case shapeType.triangle:
area = .5 * options.width * options.height;
break;
}
return area;
}
getArea(shapeType.triangle, { width: 100, height: 100 });
複製代碼
Set前言:新的數據結構 Set,它相似於數組,可是成員的值都是惟一的,沒有重複的值。
Set自己是一個構造函數,用來生成 Set 數據結構。
例1:const s = new Set();
[2, 3, 5, 4, 5, 2, 2].forEach(x=>s.add(x));
例2:const set = new Set([1, 2, 3, 4, 4]);
[...set]
例3:[...new Set('ababbc')].join('')//abc
複製代碼
const s = new Set();
1.--- s.add(1);s.add(2);s.add(2);
// 注意2被加入了兩次
s.size // 2
2.--- s.has(1) // true
s.has(2) // true
s.has(3) // false
3.--- s.delete(2);
s.has(2) // false
複製代碼
1.keys方法和values方法的行爲徹底一致
let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) {
console.log(item);
}
// red
// green
// blue
for (let item of set.values()) {
console.log(item);
}
// red
// green
// blue
複製代碼
2.entries方法返回的遍歷器,同時包括鍵名和鍵值,因此每次輸出一個數組,它的兩個成員徹底相等。
for (let item of set.entries()) {
console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]
複製代碼
3.省略values方法,直接用for...of循環遍歷 Set。
let set = new Set(['red', 'green', 'blue']);
for (let x of set) {
console.log(x);
}
// red
// green
// blue
複製代碼
4.forEach方法的參數就是一個處理函數。該函數的參數與數組的forEach一致,依次爲鍵值、鍵名、集合自己
let set = new Set([1, 4, 9]);
set.forEach((value, key) => console.log(key + ' : ' + value))
// 1 : 1
// 4 : 4
// 9 : 9
複製代碼
+ 1. 擴展運算符(...)內部使用for...of循環
let set = new Set(['red', 'green', 'blue']);
let arr = [...set];
// ['red', 'green', 'blue']
+ 2. 擴展運算符和 Set 結構相結合,就能夠去除數組的重複成員
let arr = [3, 5, 2, 2, 5, 5];
let unique = [...new Set(arr)];// [3, 5, 2]
複製代碼
相似於對象,也是鍵值對的集合,可是「鍵」的範圍不限於字符串,各類類型的值(包括對象)均可以看成鍵
tips:Map 結構提供了「值—值」的對應,是一種更完善的 Hash 結構實現。若是你須要「鍵值對」的數據結構,Map 比 Object 更合適。
const map = new Map([
['name', '張三'],
['title', 'Author']
]);
map.size // 2
map.has('name') // true
map.get('name') // "張三"
map.has('title') // true
map.get('title') // "Author"
複製代碼
解釋:執行的算法是
const items = [
['name', '張三'],
['title', 'Author']
];
const map = new Map();
items.forEach(
([key, value]) => map.set(key, value)
);
複製代碼
實例的屬性和操做方法
(1)size 屬性
size屬性返回 Map 結構的成員總數。
const map = new Map();
map.set('foo', true);
map.set('bar', false);
map.size // 2
複製代碼
(2)set(key, value)
set方法設置鍵名key對應的鍵值爲value,而後返回整個 Map 結構。若是key已經有值,則鍵值會被更新,不然就新生成該鍵。
const m = new Map();
m.set('edition', 6) // 鍵是字符串 m.set(262, 'standard') // 鍵是數值 m.set(undefined, 'nah') // 鍵是 undefined
(3)get()
方法讀取key對應的鍵值,若是找不到key,返回undefined。
const m = new Map();
const hello = function() {console.log('hello');};
m.set(hello, 'Hello ES6!') // 鍵是函數
m.get(hello) // Hello ES6!
複製代碼
(4)has\delete\clear
ES6 系列之 defineProperty 與 proxy