摘要:前端筆記基本數據類型種數據類型基本類型復雜類型基本類型與引用類型的區別基本類型基本類型,是按值訪問,可以操作保存在變量中的實際值基本類型的值不可變輸出輸出其中的實際值并未變化,方法是返回了一個新的字符串也不能對基本類型添加屬性和方法表明了基
前端筆記/JavaScript 基本 數據類型 6種數據類型
基本類型: Undefined、Null、Boolean、String、Number
復雜類型: Object
基本類型與引用類型的區別 基本類型基本類型(String、Boolean、Number、null、undefined),是按值訪問,可以操作保存在變量中的實際值
基本類型的值不可變
var name = "jobs" console.log(name.toUpperCase()) // 輸出JOBS console.log(name) // 輸出jobs name.age = 20 name.say = function() {……} console.log(name.age) // undefined console.log(name.say) // undefined // 其中name的實際值并未變化,toUpperCase()方法是返回了一個新的字符串,也不能對基本類型添加屬性和方法,表明了基本類型的值不可變
基本類型的比較是值的比較,只有在值相等時才相等
基本類型的變量存放在棧區
var name = "jobs" var age = 20
棧區 | |
---|---|
name | age |
jobs | 20 |
棧區包含了變量的標識符和值
基本類型復制
var a = 10 var b = a a++ console.log(a, b) // 11 10 // 基本類型在復制操作后變量是相互獨立的互不影響引用類型
就是除了基本類型外的Object類型
引用類型值可以變,可以有屬性和方法
var person = {} // 創建個控對象 --引用類型 person.name = "jozo" person.age = 22 person.sayName = function(){console.log(person.name)} person.sayName() // "jozo" delete person.name // 刪除person對象的name屬性 person.sayName() // undefined // 引用類型的值是同時保存在棧內存和堆內存中的對象
棧區內存保存變量的標識符和指向堆內存中該對象的指針也就是該對象在堆內存中的地址
var person1 = {name:"jozo"} var person2 = {name:"xiaom"} var person3 = {name:"xiaoq"}
棧區 | 堆區 | ||
---|---|---|---|
person1 | 堆內存地址1 | ——> | Object1 |
person2 | 堆內存地址2 | ——> | Object2 |
person3 | 堆內存地址3 | ——> | Object3 |
引用類型比較是引用的比較
var p1 = {} var p2 = {} console.log(p1 == p2) // false // 引用類型是按引用訪問的,所以是比較它們的堆內存中地址是否相同
對象引用
var a = {} // 新建空對象 var b = a // 賦值后a和b指向同一個空對象 a.name = "jobs" b.age = 20 console.log(a.name, a.age, b.name, b.age) // jobs 20 jobs 20 // 引用類型的復制是對象保存在棧區的堆內存的地址的復制,兩個變量實際上指向同一個對象,因此任何操作都會互相影響傳遞參數
所有函數的參數都是按值傳遞
var p1 = { name: "Vian" } var setName = function(obj) { obj.name = "jobs" return obj } var res = setName(p1) console.log(p1.name) // jobs console.log(res.name) // jobs // 把p1傳入setName()中,obj和p1指向同一個對象,修改obj的name值其實是修改了它們共同指向的對象的name值
var p = { name: "alice" } var set = function(ot) { ot = {} ot.name = "tom" return ot } var re = set(p) console.log(p.name) // alice console.log(re.name) // tom // 在函數內部ot新定義了一個對象,obj引用了一個局部對象,外部p和內部ot指向了不同對象,所以不會影響引用類型詳解
new操作符跟隨Object構造函數
var person = new Object() person.name = "alice"
對象字面量表示法
var person = { name: "alice", "age": 20 }
屬性名也能使用字符串訪問對象屬性一般使用點語法,但js中也能使用方括號語法,并且可以使用變量訪問屬性
alert(person.name) // alice alert(person["name"]) // alice var personName = "name" alert(person[personName]) // alice
數組每一項都可以保存任何類型的數據,而且數組大小可以動態調整,跟隨數據的添加而自動增長
var arr = new Array() // 使用Array構造函數 var arr = [] // 使用數組字面量表示法
length總會返回大于0的整數,而且它不是只讀屬性
當設置length的值小于當前的數組長度時,會從末尾開始刪減元素
當設置length為大于當前數組長度時,則會從末尾新增項,新增每一項的值都為undefined
對只有一個全局作用域而言,使用instanceof操作符便可以
if (arr instanceof Array) { // 對數組的操作 } // instanceof操作符問題在于,它假定單一的全局執行環境。若網頁中包含不同框架,那么實際上會有兩個以上不同的全局執行環境,從而存在兩個以上不同的Array構造函數
Array.isArray()方法來判斷
if (Array.isArray(arr)) { // 對數組的操作 }
棧方法:
push(): 可接受任意個參數,逐個添加到數組末尾,并返回修改后數組長度
pop(): 從數組末尾移除最后一項,減少length的值,然后返回移除的項
隊列方法:
unshift(): 在數組前面添加任意個項,并返回新數組的長度
shift(): 移除數組第一個項,減少length的值,并返回移除的項
排序方法:
reverse(): 反轉數組項的順序
sort(): 默認升序排列,可接收一個比較函數作為參數,比較函數有兩個參數,若第一個參數要在第二個參數之前,則返回負數,相等則返回0,若第一個參數要在第二個參數之后,則返回正數
> sort()會調用每項的toString()轉型方法,比較字符串,即使是數值也會轉型后比較字符串,因此[0, 1, 5, 10, 15]使用這個方法會變成[0, 1, 10, 15, 5]
操作方法
concat(): 可接收數組、等作為參數,將數組合并
var color1 = ["pink", "yellow"] var color2 = color1.concat("skyblue", ["black", "orange"]) console.log(color1) // pink,yellow console.log(color2) // pink,yellow,skyblue,black,orange * `join()`: 可接受一個參數作為分隔符,將數組轉換為字符串 * `slice()`: 基于當前數組創建一個新數組,接受一個或者兩個參數,起始位置和結束位置,不會影響當前數組。 > 若只有一個參數,則返回從該參數位置開始到末尾所有的項 > 若兩個參數則返回起始位置到結束位置之間的項,但不包括結束位置
splice(): 主要作用向數組中插入項,始終返回一個數組,數組為原數組中刪除的項,若沒有則返回一個空數組,可以有三種用途
- 刪除:刪除任意數量的項,接受2個參數:要刪除的第一項的位置和要刪除的個數 - 插入:在指定位置插入任意數量的項,接受3個參數:起始位置、0(要刪除的項數、要插入的項),如果要插入多個項,可以再傳入第四個,五個,任意個項 - 替換: 可以在任意位置插入任意項,同時刪除任意項,接受3個參數:起始位置、要刪除的項數、要插入的項
位置方法
indexOf()和lastIndexOf()
都接受2個參數:要查找的項和(可選)表示查找起點位置的索引,indexOf()從頭開始找,lastIndexOf()從末尾開始找
都返回要查找的項在數組中的位置,沒找到則返回-1,并且查找時是使用全等操作符(===)
迭代方法
共有五個迭代方法,每個方法都接受兩個參數:要在每一項上運行的函數和(可選的)運行該函數的作用域對象——影響this的值。傳入這些方法中的函數接收三個參數:數組項的值、該項在數組中的位置和數組對象本身
every(): 對數組每一項運行給定函數,若該函數對每一項都返回true,則返回true
some(): 對數組每一項運行給定函數,若該函數對任意一項返回true,則返回true
filter(): 對數組每一項運行給定函數,返回該函數會返回true的項組成的數組
map(): 對數組每一項運行給定函數,返回每次函數調用結果組成的數組
forEach(): 對數組每一項運行給定函數,沒有返回值
以上方法都不會修改數組中的包含的值
var numbers = [1, 3, 5, 7, 9, 2, 4, 6, 8, 0] // every var a1 = numbers.every(function(item, index, array) { return item > 2 }) console.log(a1) // false // some var a2 = numbers.some(function(item, index, array) { return item > 8 }) console.log(a2) // true // filter var a3 = numbers.filter(function(item, index, array) { return item % 2 === 0 }) console.log(a3) // [2, 4, 6, 8, 0] // map var a4 = numbers.map(function(item, index, array) { return item * 2 }) console.log(a4) // [2, 6, 10, 14, 18, 4, 8, 12, 16, 0] // forEach /* 沒有返回值和for循環迭代數組一樣 */
reduce
reduce(function(total, currentValue [,currentIndex]) [,initialValue]): 是一種數組運算,通常用于將數組的所有成員"累積"為一個值。
- total:必選,初始值或者累積變量 - currentValue:必選,當前元素 - currentIndex:可選,當前元素的索引 - initialValue:可選,傳遞給函數的初始值 - 基本用法
/** * reduce(function(total, currentValue, currentIndex) [,initialValue]) 用于數組計算,通常用于將數組累積為一個值 */ /** * 參數tmp是累積變量,item為當前數組成員,index為數組下標;每次運行時item會累加到tmp,最后輸出tmp */ let arr = [1, 2, 3, 4, 5, 6]; let sum = arr.reduce((tmp, item, index) => tmp + item); console.log(sum); // 21
- map是reduce的特例
/* *map是reduce的特例 累積變量的初始值可以是一個數組,例子中初始值是一個空數組,結果返回一個新的數組,等同于map操作;map操作都可以用reduce,所以map是reduce的特例 */ let handler = (newArr, x) => { newArr.push(x + 1); return newArr; } let arr2 = arr.reduce(handler, []); console.log(arr2); // [ 2, 3, 4, 5, 6, 7 ]
var arr = [1, 10, 3, 8, 5, 9, 4, 6]; /*冒泡排序*/ function pops(arr) { for (var i = 0; i < arr.length; i++) { for (var j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j + 1]) { var temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } return arr; } console.log(pops(arr)); /*快速排序*/ function quick(arr) { if (arr.length <= 1) { return arr; } var len = Math.floor(arr.length / 2); var aj = arr.splice(len, 1); var left = []; var right = []; for (var i = 0; i < arr.length; i++) { if (arr[i] < aj) { left.push(arr[i]); } else { right.push(arr[i]); } } return quick(left).concat(aj, quick(right)); } console.log(quick(arr));
try/catch/finally
try { tryCode - 嘗試執行代碼塊 } catch(err) { catchCode - 捕獲錯誤的代碼塊 } finally { finallyCode - 無論 try / catch 結果如何都會執行的代碼塊 } // 如果使用了try那么catch和finally必須選一個
通過RegExp類型來支持正則表達式,使用類似Perl的語法來創建正則表達式
var expression = / pattern / flags;
其中模式(pattern)可以是任何簡單或復雜的正則表達式,每個正則表達式可以有一個或者多個標志(flags),用以標明正則表達式的行為,匹配模式有以下三個標志.
g:全局模式,模式將被用于整個字符串而非在發現第一個匹配項時立即停止
i:不區分大小寫模式,即在匹配時忽略大小寫
m:多行模式,即在到達一行文字末尾時還會繼續查找下一行中是否存在與模式匹配的項
exec(): 接受一個參數,即要使用模式的字符串
返回包含第一個匹配項的信息的數組,額外附帶2個屬性index和input,index表示匹配項在字符串中的位置,input表示應用正則表達式的字符串,若沒有匹配項返回null
對于exec()而言即使在模式匹配設置了全局標志(g),也只會返回第一個匹配項,在不設置時,在同一字符串上多次調用也只會始終返回第一個匹配項的信息;而設置了,則每次調用都會繼續匹配新的項
test():接受一個字符串參數,在模式與該參數匹配的情況下返回true否則返回false
函數其實是對象,每一個函數都是Function的實例,因此函數名實際上也是一個指向函數對象的指針,不會與函數綁定
解析器對函數聲明和函數表達式有差別對待
解析器會先讀取函數聲明,并使其在執行任何代碼前可用(可以訪問);至于函數表達式,則必須等到解析器執行到所在代碼行才會真正被解析
// 函數聲明 console.log(sum(10, 10)) // 20 function sum(a, b) { return a + b } // 函數表達式 console.log(add(10, 10)) // 報錯 var add = function(a, b) { return a + b }
函數聲明,在代碼開始執行前,解析器通過一個名為函數聲明提升的過程,讀取并將函數聲明添加到執行環境中,并放到源代碼樹的頂端,因此可以先調用再定義
函數表達式,函數位于一個初始化語句中,也就是在執行到函數代碼前,變量不會保存有對函數的引用
在函數內部有兩個特殊對象arguments和this
arguments是一個類數組對象,保存著函數的所有參數;它還有一個callee屬性,它是一個指針,指向擁有這個arguments對象的函數
callee
function factorial(num) { if (num <= 1) { return 1 } else { return num * arguments.callee(num - 1) /* arguments.callee即是factorial函數 */ } } console.log(factorial(10)) // 3628800
caller,es5中定義的函數對象屬性,返回一個調用當前函數的引用,如果是由頂層調用的話,則返回null
function a() { console.log(arguments.callee.caller) // 因為arguments.callee就是函數a,所以arguments.callee.caller等于a.caller } function b() { a() } a() // null 因為是頂層調用 b() // b函數的源代碼
this,this引用的是(this的值)函數據以執行的環境對象,在網頁全局作用域中調用函數時候this的引用對象就是window
每個函數都包含兩個屬性:length和prototype
length: 形參個數
prototype: 原型
每個函數包含兩個非繼承而來的方法: apply()和call();
作用都是在特定作用域中調用函數,實際上等于設置this的值
apply():接收2個參數,一個是在其中運行的函數的作用域,一個是Array實例或者arguments對象
call():接收2個參數,一個是在其中運行的函數的作用域,其余參數要直接傳遞給函數,也就是逐一列舉
function sum1(a, b) { return a + b } function sum2(a, b) { var s1 = sum1.apply(this, arguments) // arguments對象 var s2 = sum1.apply(this, [a, b]) // Array實例 console.log(s1, s2) } sum2(10, 10) //20 20 function sum3(a, b) { return sum1.call(this, a, b) // 參數逐一傳入 } console.log(sum3(10, 10)) // 20
apply()和call(),真正的用武之地并不在于傳遞參數,而是擴充函數賴以運行的作用域
var color = "blue" var o = { color: "pink" } function sayColor() { console.log(this.color) } /* this指向了全局作用域window */ sayColor() // blue sayColor(this) // blue sayColor(window) // blue /* this指向了o */ sayColor.apply(o) // pink sayColor.call(o) // pink
bind(): 它會創建一個函數的實例,其this的值會被綁定到傳給bind函數的值
var colors = "skyblue" var c = { colors: "orange" } function say() { console.log(this.colors) } var say2 = say.bind(c) say2() // orange
bind與apply、call不同,不會立刻執行
暫無
toFixed(): 接受一個參數,代表保留幾位小數,會四舍五入
var num = 10 console.log(num.toFixed(2)) // 10.00
string包含length屬性,返回字符串長度
字符方法
charAt()和charCodeAt():這兩個方法都接收一個參數,即基于0的字符的位置.其中charAt()以單字符字符串的形式返回給定位置的字符,而charCodeAt()則是返回編碼
var stringTXT = "hellow" console.log(stringTXT.charAt(3)) // l console.log(stringTXT.charCodeAt(3)) // 108
字符串操作方法
concat():用于將一個或多個字符串拼接起來
slice(),substr(),substring():這三個方法都返回被操作字符串的子字符串,也都接受一或兩個參數,第一個參數指定開始位置,第二個指定結束位置;slice和substring的第二個參數指定的是子字符串的最后一個字符后面的位置,substr的第二個參數則是指定返回字符的個數
var txt = "abcdefg" console.log(txt.slice(1, 3)) // bc console.log(txt.substring(1, 3)) // bc console.log(txt.substr(1, 3)) // bcd
位置方法
indexOf()和lastIndexOf():這兩個方法接受2個參數,第一個為要查找的字符串,(可選)第二個表示查找起點位置的索引,都是從字符串中尋找指定的字符串,然后返回該字符串的位置,若沒有則返回-1,一個從頭開始找,一個從末尾開始找
大小寫轉換
toLowerCase()和toUpperCase():全部轉換成小寫,大寫
toLocaleLowerCase()和toLocaleUpperCase():全部轉換成小寫,大寫,這是根據特定地區來轉換大小寫,在不知道代碼運行在哪個語言的情況下使用
字符串的模式匹配方法
match():接受一個參數,參數為正則表達式或者RegExp對象,返回一個數組,數組保存著每一個匹配的子字符串
var txt = "abcdefgabcdefgabcdefg" var reg = /ab/gi console.log(txt.match(reg)) // ["ab", "ab", "ab"]
search():接受一個參數,參數為正則表達式或者RegExp對象,從頭開始匹配,返回第一個匹配項的索引,沒有則返回-1
replace():接收2個參數,字符串或者正則表達式或者RegExp對象,第二個則是用于替換的字符串或者函數;若第一個參數為字符串則只會替換第一個子字符串,要想替換所有,則必須是正則表達式,并且指定全局標志(g);若第二個參數是函數,則給這個函數傳入的三個參數分別是匹配項第一個匹配項,第二個等等,最后兩個參數為匹配項的位置和原始字符串
split():將字符串以指定分隔符分割成字符串,分隔符可以是字符串也可以是正則表達式或者RegExp對象;也可以接受第二個參數,用于指定數組大小
內置單體對象encodeURI():主要用于整個uri,它不會對本身屬于uri的特殊字符進行編碼如冒號、正斜杠、問好、井號
encodeURIComponent():主要用于對其中一段進行編碼,它會對任何非標準字符進行編碼
var uri = "http://www.who.com/search?wd=123" console.log(encodeURI(uri)) // 結果: http://www.who%08.com/search?wd=123 console.log(encodeURIComponent(uri)) // 結果: http%3A%2F%2Fwww.who%08.com%2Fsearch%3Fwd%3D123
encodeURIComponent使用的比encodeURI多
decodeURI():解碼方法,只能對encodeURI()編碼的進行解碼
decodeURIComponent():解碼方法,可以解碼所有字符
eval():這個方法像是一個完整的ECMAScript解析器,它接受一個字符串參數,就是要執行的js代碼字符串
Math.PI: π的值
求極值
min(),max():求最小,最大值;可以接受任意個參數
舍入方法
ceil():向上求整
floor():向下求整
round():四舍五入
隨機值
random(): 返回一個0-1之間的隨機數,但不包含0和1,從區間內取一個值,可以用一下公式
(max - min) * Math.random() + min
絕對值
abs(): 絕對值
次方
pow(a, n): 第一個為底,第二個參數為次方值,a的n次方
原型和閉包 對象(undefined,number,string,boolean)屬于簡單的值類型,不是對象。函數、數組、對象、null、構造函數都是對象,都是引用類型判斷一個變量是不是對象,值類型用typeof,引用類型用instanceof
在js中數組、函數、對象都是對象,對象里面一切都是屬性,只有屬性,沒有方法; 方法也是一種屬性
對象都是通過函數創建的,函數是對象
function F() { this.name = "jobs" } var f1 = new F() // 對象可以通過函數創建 var arr = [1, 2, 3] // 語法糖,本質是下面的簡寫 var arr = new Array() // Array是構造函數 arr[0] = 1 arr[1] = 2 arr[2] = 3原型
prototype原型
函數默認有一個prototype屬性,prototype屬性的值是一個對象(屬性的集合),默認只有一個constructor屬性指向這個函數本身
[image:DF9C0DF3-83B1-4F0C-8F2B-39C112BA24F6-1188-00000B31D26AD3B2/prototype-1.png]
如圖所示,superType是一個函數,右邊是原型
原型作為對象,屬性的集合,可以自定義許多屬性,例如Object,里面包含了其他幾個屬性
[image:C2050E95-6407-4A59-9B93-D6F7081CD863-1188-00000B3DEE188E44/instanceof-2.png]
可以在自定義的方法的prototype中新增自己的屬性
function Fn() {
Fn.prototype.name = "王福鵬" Fn.prototype.getYear = function() { return 1988 }
}
[image:E2D062D3-B7D0-457C-97D2-6607E729A1C5-1188-00000B470B9F9F19/prototype-3.png]
function Fn() { Fn.prototype.name = "王福鵬" Fn.prototype.getYear = function() { return 1988 } } var f1 = new Fn() console.log(f1.name) // 王福鵬 console.log(f1.getYear()) // 1988 console.log(f1.__proto__ === Fn.prototype) // true
上述代碼,f1對象是從Fn中new出來的,這樣f1就可以調用Fn中的屬性,因為每個對象都有一個隱藏屬性"__proto__",這個屬性引用了創建這個對象的函數的prototype,所以f1.__proto__ === Fn.prototype,這里的"__proto__"成為隱式原型
隱式原型__proto__是瀏覽器提供的屬性,就是[[prototype]]這個隱藏屬性,__proto__因為不是規范屬性,所以要避免使用;
es5中用Object.getPrototypeOf(obj)函數獲得一個對象的[[prototype]]
es6中用Object.setPrototypeOf(obj, prototype)函數可以直接修改一個對象的[[prototype]]
參數obj將被設置原型的對象.
prototype該對象新的原型(可以是一個對象或者null).
每個對象都有一個__proto__,可稱為隱式原型
__proto__是一個隱藏屬性
var obj = {} console.log(obj.__proto__ === Object.prototype)
有上述代碼可知:每個對象都有一個__proto__`屬性指向創建該對象的函數的prototype屬性
有一個特例Object.prototype.__proto__ === null
instanceof 操作符console.log(Function instanceof Function) // true console.log(Function instanceof Object) // true console.log(Object instanceof Function) // true console.log(Object instanceof Object) // true
instanceof判斷規則是,沿著a的__proto__來找,沿著b的prototype來找,如果引用的同一個引用就返回true
[image:E4783050-568F-4369-A33E-192AE586FBE7-1188-00000B9545C250D1/instanceof-1.png]
即instanceof表示的就是一種繼承關系,或者原型鏈的結構
[image:8826A813-C433-43DB-9C3D-CF0964451DDA-1188-00000B97B94D72D0/instanceof-2.png]
繼承JavaScript的繼承是用原型鏈來體現的
function Foo() {} var f1 = new Foo() f1.a = 10 Foo.prototype.a = 100 Foo.prototype.b = 200 console.log(f1.a, f1.b) // 10 200
上述代碼,f1是Foo函數new出來的對象,f1.a是f1對象的基本屬性,而f1.b是從Foo.prototype得來的,因為f1.__proto__指向Foo.prototype
訪問一個對象的屬性時,現在基本屬性中查找,如果沒有,就沿著__proto__鏈向上查找,這就是原型鏈
如何區分一個屬性是基本的還是從原型中找到的,用hasOwnProperty
[image:802EAC7F-3F88-4EA9-A120-E988C06FB7B3-1188-00000B9C76399666/prototype-4.png]
f1中沒有hasOwnProperty方法,它是從Object.prototype而來的
[image:7231EB7A-F0A5-482E-9632-8C88F3FA7749-1188-00000BA5D0FE85B9/prototype-5.png]
對象的原型鏈都會找到Object.prototype,因此所有對象都有Object.prototype的方法,這就是繼承
執行上下文上下文環境
[image:B0C9A9CF-FB04-4776-A2E5-AA72796DC573-1188-00000BA936740391/this-1.png]
- 第一句報錯a未定義,二三句a為undefined,說明在js代碼一句句執行前,瀏覽器就已經開始一 些準備工作,其中就包括對變量的聲明,而不是賦值,賦值操作是在運行到語句時才執行;
[image:2185D116-A4C9-41BC-BF30-92F3E57EC3B3-1188-00000BAD8E05AD77/this-2.png]
- 這是第一種情況
[image:DCC314B3-40D8-4F45-8DC1-72AB6A089648-1188-00000BB1A9090280/this-3.png]
- 第一種情況是對變量只聲明,未賦值;第二種直接賦值給了this;這也是‘準備工作’之一
[image:88C73D7D-40A0-470F-81BE-B2651D40A767-1188-00000BB70805B00A/this-4.png]
- 在這里對函數表達式和普通變量賦值一樣,而函數聲明則立刻賦值了
準備工作完成的事
變量、函數表達式 —— 變量聲明,默認賦值為undefined
this —— 賦值
函數聲明 —— 賦值
這三種數據準備情況就是‘執行上下文’或者‘執行上下文環境’
js在執行代碼片段前都會進行準備工作來生成‘執行上下文’,代碼片段分三種情況:全局代碼、函數體、eval代碼
在函數中,arguments和函數參數會直接賦值;函數每調用一次,都會產生一個新的執行上下文環境;而且函數在定義的時候(不是調用的時候),就已經確定函數體內部自由變量的作用域
在執行代碼之前,把將要用到的所有的變量都事先拿出來,有的直接賦值了,有的先用undefined占個空
全局代碼的上下文環境為
普通變量(包含函數表達式) | 聲明(默認賦值為undefined) |
函數聲明 | 賦值 |
this | 賦值 |
如果代碼片段是函數體,則在此基礎上附加
參數 | 賦值 |
arguments | 賦值 |
自由變量的取值作用域 | 賦值 |
函數中this到底是什么值,是在函數真正被調用時確定的,函數定義時確定不了;this永遠指向的是最后調用它的對象,也就是看它執行的時候是誰調用的;因為this取值是執行上下文環境的一部分,每次調用都會產生一個新的執行環境上下文
分四種狀況
構造函數
function F(num) { this.num = num this.log = "txt" console.log(this) }
- 把函數作為構造函數,那么this就是new出來的對象 - 函數作為對象的一個屬性 - 如果函數作為對象的一個屬性,并且作為對象的屬性被調用時,this指向該對象
var obj = { x: 10, fn: function() { console.log(this) // {x:10, fn: function} console.log(this.x) // 10 } } obj.fn()
- 函數調用call和apply,bind時調用 - 當一個函數被call和apply調用時,this的值就取傳入的對象的值
var obj = { x: 10 } function fn() { console.log(this) console.log(this.x) } fn.call(obj) // {x: 10} 10 fn.apply(obj) // {x: 10} 10 var fns = fn.bind(obj) fns() // {x: 10} 10
全局和調用普通函數
this指向window
作用域作用域
[image:C6407A7F-8B78-4A86-8C15-6697981F687C-1188-00000BFD4FA9B6C0/this-5.png]
[image:08320C13-AE3E-4C60-A615-25442AD209CA-1188-00000BFECEDB8EC1/this-6.png]
作用域中變量的值是在執行過程中產生的確定的
如果要查找一個作用域下某個變量的值,就需要找到這個作用域對應的執行上下文環境,再在其中尋找變量的值
自由變量和作用域鏈要到創建這個函數的那個作用域中取值——是“創建”,而不是“調用”,切記切記——其實這就是所謂的“靜態作用域”
作用域鏈
[image:12DFA8C1-973E-4680-A97D-C57F33ABEBCB-1188-00000C050C4391C4/this-7.png]
面向對象的程序設計 屬性類型包含兩種數據屬性和訪問器屬性數據屬性
數據屬性包含一個數據值的位置,在這個位置可以讀取和寫入值,數據屬性有4個描述其行為的特性
[[Configurable]]:表示能否通過delete刪除屬性,從而重新定義屬性,能否修改屬性特性,能否把屬性修改為訪問器屬性
[[Enumerable]]:能否通過for-in循環返回屬性
[[Writable]]:能否修改屬性值
[[Value]]:包含這個屬性的數據值,默認undefined
直接在對象上定義的屬性,它們的[[Configurable]]、[[Enumerable]]、[[Writable]]的值默認為true,[[Value]]為指定值
var p = { name: "nico" } // [[Value]]的值為 nico
要修改屬性默認特性,必須使用es5的Object.defineProperty()方法,接收三個參數,屬性所在對象,屬性名字和一個描述符對象。其中描述符對象屬性必須是:configurable、enumerable、writable、value.設置其中一個或多個值(小寫)可以多次調用Object.defineProperty(),但是Configurable一旦設置為false(不可配置),就不能再將其設置為true(可配置),而且為false時其他屬性也受到限制了
在調用Object.defineProperty()時,若不設置,configurable、enumerable、writable的值都為false
var Person = {} Object.defineProperty(Person, "name", { configurable: false, wirtable: false, value: "alice" }) console.log(Person.name) // alice delete Person.name console.log(Person.name) // alice Person.name = "Nico" console.log(Person.name) // alice Object.defineProperty(Person, "name", { configurable: true, value: "Nico" }) console.log(Person.name) // 報錯訪問器屬性
訪問器屬性不包含數據值,包含一對getter和setter函數(不過它們不是必須的),在讀取訪問器屬性時,會調用getter函數,它負責返回有效的值;在寫入訪問器屬性時會調用setter函數,它負責處理數據;訪問器有如下4個特性
* [[Configurable]]:表示能否通過delete刪除屬性,從而重新定義屬性,能否修改屬性特性,能否把屬性修改為訪問器屬性
[[Enumerable]]:能否通過for-in循環返回屬性
[[Get]]:在讀取時調用的函數,默認值為undefined
[[Set]]:在寫入屬性時調用的函數,默認值為undefined
訪問器屬性不能直接定義,必須使用Object.defineProperty()來定義
var book = { _year: 2014, // _ 是一種常用標記,用于表示只能通過對象方法訪問的屬性 edition: 1 } Object.defineProperty(book, "year", { get: function() { return this._year }, set: function(val) { if (val > 2014) { this._year = val this.edition = val - 2014 } } }) book.year = 2016 console.log(book.edition) // 2
這是使用訪問器屬性的常見方式,即設置一個屬性的值會導致其他屬性發生變化定義多個屬性不一定要同時使用getter和setter,只指定getter表示屬性不能寫,嘗試寫入屬性會被忽略;只指定setter表示不能讀,否則會返回undefined;在嚴格模式下都會拋出錯誤
Object.defineProperties(),es5中定義的,可以通過描述符一次定義多個屬性,接收2個對象參數,第一個是要添加和修改其屬性的對象,第二個對象的屬性與第一個對象中要添加或修改的屬性要一一對應
var book = {} Object.defineProperties(book, { _year: { value: 2000 }, edition: { writable: true, value: 1 }, year: { get: function() { return this._year }, set: function(val) { if (val > 2000) { this._year = val this.edition += val - 2000 } } } }) console.log(book.year) // 2000 book.year = 2017 console.log(book.edition) // 18讀取屬性的特性
Object.getOwnPropertyDescriptor(),可以取得給定屬性的描述符;接收2個參數:屬性所在對象和要讀取的其描述符的屬性名,返回值為一個對象;如果是數據屬性,這個對象的屬性有configurable、enumerable、writable、value;如果是訪問器屬性,這個對象的屬性有configurable、enumerbale、get、set創建對象 工廠模式
function createperson(name, age) { var o = {} o.name = name o.age = age o.say = function() { console.log(this.name, this.age) } return o } var p1 = createperson("alice", 18) var p2 = createperson("lulu", 20) console.log(p1 instanceof Object) // true console.log(p1 instanceof createperson) // false
工廠模式解決了創建多個相似對象的問題,但沒有解決對象識別問題(怎么知道一個對象的類型)構造函數模式
function Person(name, age) { this.name = name this.age = age this.say = function() { console.log(this.name, this.age) } } var p1 = new Person("alice", 18) var p2 = new Person("lulu", 20) console.log(p1 instanceof Object) // true console.log(p1 instanceof Person) // true
與工廠模式對比,沒有顯示的創建對象,直接將屬性和方法賦給了this對象,沒有return語句在這個模式下創建的所有對象既是Object的實例又是Person的實例
創建自定義構造函數意味著可以將它的實例標識為一種特定類型,這正是構造函數模式勝過工廠模式的地方
使用構造函數會使得每個方法都要在每個實例上創建一遍,在上述例子中p1和p2都有say方法,但那不是同一個Fuction的實例,因為在js中函數是對象,會導致不同的作用域鏈和標識符解析
console.log(p1.say == p2.say) // false原型模式
創建的函數都有一個prototype(原型)屬性,它是一個指針,指向一個對象,這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法,也就是prototype就是通過調用構造函數而創建的那個對象實例的原型對象
function Person() {} Person.prototype.name = "nico" Person.prototype.say = function() { console.log(this.name) } var p1 = new Person() p1.say() // nico console.log(p1 instanceof Person) // true
理解原型對象
只要創建了新函數,就會為該函數創建一個prototype屬性,這個屬性指向函數的原型對象
默認情況下,所有原型對象都會自動獲得一個constructor(構造函數)屬性,這個屬性包含一個指向prototype屬性所在函數的指針,例如前面的代碼中Person.prototype.constructor指向Person;通過這個構造函數可以繼續為原型對象添加其它屬性和方法
創建了自定義構造函數后,其原型對象默認只會取得constructor屬性;至于其他方法,則從Object繼承而來
當調用一個構造函數創建一個新的實例后,該實例內部包含一個指針(內部屬性),指向構造函數的原型對象;es5中這個指針叫[[Prototype]],在腳本中沒有標準的方式訪問[[Prototype]],但Firefox,Safari,Chrome在每個對象上都支持一個屬性__proto__;這個鏈接存在于實例與構造函數的原型對象之間,而不是實例與構造函數之間
可以通過對象實例訪問保存在原型中的值,但卻不能重寫原型中的值
原型模式最大問題是由其共享的本性所導致的,改變一個實例的屬性,所有實例都會變
更簡單的原型語法
function Person() {} Person.prototype = { name: "nico", say: function() { console.log(this.name) } } var p1 = new Person() p1.say() // nico console.log(p1 instanceof Person) // true console.log(p1.constructor == Person) // false
以對象字面量形式創建,會導致constructor屬性不再指向Person
可以設置constructor為適當值
function Person() {} Person.prototype = { constructor: Person, name: "nico", say: function() { console.log(this.name) } } var p1 = new Person() p1.say() // nico console.log(p1 instanceof Person) // true console.log(p1.constructor == Person) // true
但這樣會導致constructor的[[Enumerable]]為true,原生的constructor為不可枚舉屬性,這時候要用es5的Object.defineProperty()重寫constructor屬性
function Person() {} Person.prototype = { constructor: Person, name: "nico", say: function() { console.log(this.name) } } Object.defineProperty(Person.prototype, "constructor", { enumerable: false, value: Person }) var p1 = new Person() p1.say() // nico console.log(p1 instanceof Person) // true console.log(p1.constructor == Person) // true組合模式 - 最常用方式
概述
組合使用構造函數模式和原型模式
這是創建自定義類型最常見的模式
構造函數模式用于定義實例屬性,而原型模式用于定義方法和共享的屬性
這樣,每個實例都有一份自己的實例屬性的副本,同時又共享著對方法的引用,還支持向構造函數傳參
這種模式是目前使用最廣泛的一種創建自定義類型的方法,可以說是用來定義引用類型的一種默認模式
function Person(name, age) { this.name = name this.age = age } Person.prototype = { constructor: Person, say: function() { console.log(this.name, this.age) } } var p1 = new Person("alice", 20) var p2 = new Person("nico", 30) p1.say() console.info(p1.name == p2.name) // false console.info(p1.say == p2.say) // true動態原型模式
為了解決獨立的構造函數和原型,動態原型模式將所有信息封裝到構造函數中,而通過在構造函數中初始化原型,又保持了同時使用構造函數和原型的優點;也就是通過檢測某個應該存在的方法是否有效來決定是否初始化原型
function Person(name, age) { this.name = name this.age = age if (typeof this.say != "function") { Person.prototype.say = function() { console.log(this.name, this.age) } } } var p1 = new Person("alice", 20) var p2 = new Person("nico", 30) console.info(p1.name == p2.name) // false console.info(p1.say == p2.say) // true
這里只有在say方法不存在時,才會將它添加到原型中,這段代碼只有在初次調用構造函數時才會執行
if語句檢查可以使初始化之后應該存在的任何屬性或方法,不必一堆if語句來檢測每個屬性和每個方法,只要檢查其中一個即可,還可以使用instanceof來確定類型
寄生構造函數模式與工廠模式一樣,instanceof操作符不能用來確定對象類型,在能使用其他模式的情況下不推薦使用穩妥構造函數模式
function Person(name, age) { var o = {} o.say = function() { console.log(name) } return o } var p1 = Person("alice", 20) p1.say() // alice
這樣變量Person中保存的是一個穩妥對象,除了調用say()外,無法訪問其數據成員,這種模式instanceof也沒什么意義繼承 借用構造函數
使用call或者apply,將父對象的構造函數綁定在子對象上
function Animal() { this.species = "貓科動物" } function Cat(name, color) { Animal.apply(this, arguments) this.name = name this.color = color } var cat1 = new Cat("kit", "white") console.log(cat1.species) // 貓科動物
方法都在構造函數中定義,函數無法復用,借用構造函數很少多帶帶使用
原型鏈使用prototype屬性,如果子構造函數的prototype對象指向一個父構造函數的實例,那么所有子構造函數的實例都可以繼承父構造函數了
function Animal() { this.species = "貓科動物" } function Cat(name, color) { this.name = name this.color = color } Cat.prototype = new Animal() Cat.prototype.constructor = Cat var cat1 = new Cat("ly", "blue") console.log(cat1.species) // 貓科動物
解析上述代碼
Cat.prototype = new Animal()
將Cat的prototype對象指向一個Animal的實例,它相當于刪除了prototype原先的值,然后賦予一個新值
- `Cat.prototype.constructor = Cat`任何一個prototype都有一個constructor屬性,由于上述代碼,會導致Cat.prototype.constructor指向Animal,需要重新將構造函數定義回Cat - 如果替換了prototype對象那么下一步必定是將constructor指向原來的構造函數 * 由于不能在不影響所有對象實例的情況下傳參和由于原型中包含的引用類型值得問題,很少會多帶帶使用原型鏈原型式繼承(用空對象做中介)
function Animal() { this.species = "貓科動物" } function Cat(name, color) { this.name = name this.color = color } function F() {} F.prototype = new Animal() Cat.prototype = new F() var cat1 = new Cat("ly", "blue") console.log(cat1.species) // 貓科動物 console.log(Animal.prototype.constructor) // Animal的源代碼
function Animal() { this.species = "貓科動物" } function Cat(name, color) { this.name = name this.color = color } function extend(child, parent) { var F = function() {} F.prototype = new parent() child.prototype = new F() child.prototype.constructor = child child.uber = parent.prototype } extend(Cat, Animal) var cat1 = new Cat("jack", "orange") console.log(cat1.species) // 貓科動物
這個extend函數,就是YUI庫如何實現繼承的方法寄生繼承最后一行只是為了實現繼承的完備性,純屬備用性質
創建一個僅用于封裝繼承過程的函數
無法實現函數復用
function creatAnother(obj) { var clone = Object(obj) clone.say = function() { console.log("hi") } return clone } var Person = { name: "nico" } var an = creatAnother(Person) an.say() // hi組合繼承 - 最常用方式
也叫偽經典繼承,將原型鏈和借用構造函數的技術整合一起,從而發揮二者之長
通過原型鏈實現對原型屬性和方法的繼承,通過借用構造函數來實現對實例屬性的繼承
最常用方式
函數可復用,可傳參,不存在引用屬性共享問題
function Person(name, age) { this.name = name this.age = age } Person.prototype.sayName = function() { console.log(this.name) } Person.prototype.sayAge = function() { console.log(this.age) } function Girls(name, age) { Person.apply(this, arguments) } Girls.prototype = new Person() Girls.prototype.constructor = Girls; var alice = new Girls("alice", 16) alice.sayName() // alice alice.sayAge() // 16寄生組合式繼承
最好的繼承方式
function inter(Super, Sub) { var clone = Object(Super.prototype) // 創建對象 clone.constructor = Sub // 增強對象 Sub.prototype = clone // 指定對象 } function Person(name, age) { this.name = name this.age = age } Person.prototype.say = function() { console.log(this.name, this.age) } function Girls(name, age, play) { Person.apply(this, arguments) this.play = play } inter(Person, Girls) Girls.prototype.plays = function() { console.log(this.play) } var alice = new Girls("alice", 16, "game") alice.say() // alice 16 alice.plays() // game
inter函數實現了寄生組合的最簡單形式,在函數內部先創建超類原型副本,為創建的副本添加constructor屬性,最后將副本賦給子類型的原型
瀏覽器環境 DOM和BOM BOM瀏覽器對象模型,提供了獨立于瀏覽器顯示內容而與瀏覽器窗口進行交互的對象location
用于存儲當前頁面URL信息的對象
location的屬性如下:
//假設url為 http://search.phpied.com:8080/search?p=javascript#results location.; location.hash = ""; location.host = "search.phpied.com:8080"; location.hostname = "search.phpied.com"; location.pathname = "/search"; location.port = "8080"; location.protocol = "http:"; location.search = "?p=javascript";
location的三個方法:
reload(): 無參數,重新載入當前頁面; location = location也能用于重新載入當前頁面
assign(newURL): 載入新頁面會留下歷史記錄
replace(newURL): 載入新頁面不會留下歷史記錄
histroy存儲了頁面的訪問記錄
window.history.lenght: 存儲的記錄數
history.forward(): 前進
history.back(): 后退
history.go(): 0重新載入當前頁面; 正值前進幾個頁面; 負值后退幾個頁面
screen提供了桌面信息
screen.width,screen.height: 桌面分辨率,總大小
screen.availWidth,screen.availHeight: 除去操作系統菜單欄(例如windows的任務欄)以外的區域大小
alert,prompt,confirm這幾個并不屬于ECMAScript,而是BOM方法定時器
定時器也是BOM方法DOM
文檔對象模型,將xml或html文檔解析成樹形節點的方法DOM節點
nodeName : 節點的名稱
nodeValue :節點的值
nodeType :節點的類型
getElementsByTagName、getElementsByName、getElementById
可以用屬性形式訪問attribute,因為class為保留字,所以class要用className訪問
屬性:nextSibling與previousSibling,得到下一個兄弟節點、上一個兄弟節點;空行也算
屬性:nextElementSibling 與previousElementSibling,得到下一個上一個兄弟元素節點
innerHtml,可用于修改節點內容
style屬性用于修改樣式
document.createElement(): 創建元素節點
document.createTextNode: 創建文本節點
cloneNode(): 該方法有一個參數,true深拷貝,包括所有子節點, false淺拷貝,只針對當前節點
var odv = document.getElementsByTagName("div")[0]; var p2 = document.getElementsByTagName("p")[1]; odv.appendChild(p2.cloneNode(false)); odv.appendChild(p2.cloneNode(true)); // 淺拷貝,文本節點不會拷貝
appendChild(newChild): 將節點插入到 節點的子節點列表的末尾
insertBefore(newChild, refChild): 將節點插入節點指定子節點的前面
var odv = document.getElementsByTagName("div")[0]; var p2 = document.getElementsByTagName("p")[1]; odv.appendChild(p2.cloneNode(true)); odv.insertBefore(p2.cloneNode(true), document.getElementsByTagName("p")[0]);
removeChild(child): 從子節點列表中移除指定節點
replaceChild(newChild, oldChild): 將指定子節點替換成新節點
var odv = document.getElementsByTagName("div")[0]; var p2 = document.getElementsByTagName("p")[1]; odv.replaceChild(document.createElement("li"), p2);只適用于HTML的DOM方法
document.body
document.images, 相當于Core DOM組件的document.getElementsByTagName("img")的調用
document.forms, 獲取所form,包含子元素;然后可以通過elements來訪問子元素,如果form或者子元素有名字,也可用過名字訪問
var forms = document.forms[0]; // var user = forms.elements[0]; 和下行一樣 var user = forms.user; console.log(user); user.value = "admin"; // 標簽里有了admin
addEventListener(even, function, boolean) : 第一個參數為事件名不加on,第二個參數為函數,第三個為布爾值默認為false在冒泡階段執行,true在捕獲階段執行
removeEventListener(): 該方法與上一個參數相同,它是移除監聽器;但若是第二個參數為匿名函數則移除不了
捕捉和冒泡捕捉:事件先發生在document上,依次傳遞給body等,最終達到該元素上
冒泡:事件先發生在該元素上,再依次向上,然后到body,直至document對象上
阻斷事件傳播stopPropagation(): 這樣就使得事件無法傳播了,只發生在自己身上
var op = document.getElementsByTagName("p"); op[0].addEventListener("click", function(e) { console.log(e.target); e.stopPropagation(); }, false);阻止默認事件
pereventDefault(): 不是所有默認事件都能阻止
var alink = document.getElementsByTagName("a"); alink[0].addEventListener("click", function(e) { e.preventDefault(); console.log(123); }, false);跨瀏覽器事件監聽(兼容IE)
DOM2屬性 | IE對應屬性 | 說明 |
---|---|---|
addEventListener | attachEvent | 事件監聽 |
event | window.event | IE中的全局事件對象 |
target | srcElement | 事件元素的target屬性 |
stopPropagation | cancelBubble | only-IE屬性,設置為true |
preventDefault | returnValue | only-IE屬性,設置為false |
removeEventListener | detachEvent | 移除事件監聽 |
就是HTML、CSS和JS分開命名空間
為了減少命名沖突,通常減少全局變量的使用;更好的方法是將不同變量和方法定義在不同命名空間中;本質是只定義一個全局變量,并將其它變量和方法定義為該變量的屬性將對象用作命名空間
// 新建全局變量MYAPP var MYAPP = MYAPP || {}; // 添加屬性 MYAPP.event = {}; // 添加方法 MYAPP.event = { getEvent: function(e) { // ...... }, // ......other methods }命名空間中構造器應用
我們可以在命名空間中使用構造器函數
// 本例中,我們用Element構造器創建一個dom元素 var MYAPP = MYAPP || {}; MYAPP.dom = {}; MYAPP.dom.Element = function(type, props) { var tmp = document.createElement(type); for (var i in props) { tmp.setAttribute(i, props[i]); console.log(i, props[i]); } return tmp; } var a = new MYAPP.dom.Element("a", { href: "javascript.void(0);" }); document.body.appendChild(a);namespace方法
var MYAPP = {}; MYAPP.namespace = function(str){ var parts = str.split("."), parent = MYAPP, i=0, l=0; if(parts[0]==="MYAPP"){ parts = parts.slice(1); } for(i=0,l=parts.length; i設計模式 設計模式有23種甚至更多,下面為4種常用模式單例模式 工廠模式 裝飾器模式 觀察者模式var sub = { callbacker: [], // 發布 add: function(fn) { this.callbacker.push(fn); }, // 訂閱 fire: function(fn) { this.callbacker.forEach(function(element) { element(); }); } } sub.add(function() { console.log(1) }); sub.add(function() { console.log(2) }); sub.fire(); // 1 2ES6 let和const letlet用于申明變量,并且只在該代碼塊內有效
let不存在變量提升,只能先聲明再使用
暫時性死區,在代碼塊內未使用let申明變量前,變量都是不可用的
不允許重復聲明變量
let和const實際上為js提供了塊級作用域
constconst就是常量
一旦聲明,必須就賦值,且不可變更
無法重復聲明
全局對象的屬性全局對象是最頂層的對象,在瀏覽器環境中是window對象,在nodeJS中是global對象
es5中全局對象屬性與全局變量等價
es6中var,function命令聲明的全局變量依然是全局對象的屬性;而let、const、class命令聲明的全局變量則不再是全局對象的屬性
變量的解構賦值 數組的結構賦值 基本用法let [a, b, c] = [1, "a", ["c"]]; console.log(a, b, c); // 1, "a", ["c"]即匹配模式,等號兩邊格式一樣,即可進行變量的賦值
若右邊表達式不是數組,則會報錯;只要有Iterator接口的數據結構都可以使用數組形式的解構賦值
適用于var、let、const命令
若解構失敗變量值為undefined
默認值解構賦值允許有默認值
ES6內部使用嚴格相等運算符(===),所以一個數組成員不嚴格等于undefined是不會使用默認值的
var [a = 1, b = 2, c = 3, d = 4] = [undefined, null, "c", d]; console.log(a, b, c, d); //1 null "c" 4對象的解構賦值var {x, y} = {x: 1, y: "a" }; console.log(x, y); //1 "a" var { bar: baz } = { bar: "hello" }; console.log(baz); //hello /*下面例子中js會將{}當成代碼塊,此時需要用小括號括起來*/ var k; // {k} = {k: 123};會報錯,js會將{}當成代碼塊,此時需要用小括號括起來 ({ k } = { k: 123 }); console.log(k); // 123 /*在這個例子中,loc是模式不是變量不會賦值*/ var local = { loc: { ui: "ui", txt: "txt" }, title: "標題" } var { loc: { ui, txt }, title } = local; // console.log(loc); loc is not defined console.log(ui, txt, title); // ui txt 標題 /*對象的解構賦值也能設置默認值,同樣只有在值嚴格為undefined時,默認值才會有用*/ var {bat = 123, bas = 456, bad} = {bat: undefined, bas: null, bad: "bad"}; console.log(bat, bas, bad); // 123 null "bad" /*若解構失敗變量值為undefined*/ /*對象的解構賦值,可以方便的將對象方法賦值到某個變量中*/ var {pow, random} = Math; // 將Math對象的次方和隨機數方法賦值給了pow和random console.log(pow(2, 3)); // 8 console.log(random()); // 隨機數 /*因為數組也是特殊對象,因此數組也能進行對象的解構賦值*/ var arr = [1, 2, 3]; var {0: first, [arr.length - 1]: last} = arr; console.log(first, last); // 1 3字符串的解構賦值// 將字符串轉成了類似數組的對象 const [a, b] = "hi"; console.log(a, b); // h i // 字符串有length屬性,因此可以對這個對象進行解構賦值 var { length: len } = "hello"; console.log(len); // 5函數參數的解構賦值function add([x, y]) { return x + y; } console.log(add([1, 2])) // 3 function move({ x = 0, y = 0 } = {}) { return [x, y]; } console.log(move({ x: 3 })) // [3, 0] console.log(move({ y: 8 })) // [0, 8] console.log(move({ x: 3, y: 8 })) // [3, 8]解構賦值的應用交換變量值
[x, y] = [y, x];從函數返回多個值
函數參數定義和設置默認值
遍歷Map結構
輸入模塊的指定方法
提取JSON
var data = { id: 1, name: "admin", type: 0, data: { goods: [9001, 9002], goods_type: [0, 1] } } var { id, name, type, data: { goods, goods_type } } = data; console.log(id, name, type, goods, goods_type); // 1 "admin" 0 (2) [9001, 9002] (2) [0, 1]數組的擴展 新增方法 Array.fromArray.from方法用于將類似數組的對象和可遍歷對象(包含set、map)轉換成數組實際應用中可以將DOM操作返回的NodeList和函數內arguments轉為數組
還能接受第二個參數,作用類似于數組的map方法,對每個元素進行處理,將處理后的值放入返回的數組
Array.of用于將一組值轉換為數組
var arr1 = Array(); var arr2 = Array(3); var arr3 = Array(1, 2); console.log(arr1); // [] console.log(arr2); // [ , , ] console.log(arr3); // [1, 2] var arr4 = Array.of(1); console.log(arr4); // [1] /*因為數組的構造函數,只有在參數不小于2時才會作為數組值,一個參數時作為數組長度;Array.of則是保持一致,無論參數多少都作為數組元素*/copyWithincopyWithin(target, start, end): 將指定位置的成員復制到其他位置(會覆蓋原有成員),然后返回當前數組,也就是會修改當前數組
參數:
target(必須): 從該位置開始替換
start(可選):從該位置讀取,默認為0,若為負值則為倒數
end(可選):讀取到該位置結束,默認為數組長度,若為負值則為倒數
find和findIndex參數為一個函數,將數組內元素依次執行該回調函數,找出第一個返回值為true的成員,find是返回這個成員,若沒有符合條件的成員則返回undefined;findIndex是返回該成員位置,若沒有符合條件的成員則返回-1
回調函數,接收三個參數:當前值、當前位置、原數組
fill用給定值,填充一個數組,會覆蓋原有全部值
可以接受第二、三個參數,用于指定填充的起始和結束位置
數組實例的keys、values、entries都用于遍歷數組,返回一個遍歷器,可用for...of來遍歷
keys()是對鍵名,values()是對鍵值,entries()是對鍵值對
數組實例的includesincludes返回一個布爾值,表示數組是否包含給定的值
該方法可選第二個參數,代表起始搜索位置,默認為0,若為負值則倒數
[1, 2, 3].includes(2) // true函數擴展 函數的默認值可以設置函數默認值,有默認值的參數最好作為尾參
可使用rest參數, 即...參數
function add(...val) { let sum = 0; for (let i of val) { sum += i } console.log(sum); } add(1, 2, 3, 4, 5, 6, 7, 8, 9); //45rest參數是一個數組,可以使用任意數組方法
rest參數后面不能再跟任何參數
rest參數可以替代Array.prototype.slice.call(arguments)
擴展運算符 基本含義擴展運算符就是三個點...,用于將數組轉為用逗號分隔的參數序列
function add(...val) { let sum = 0; for (l
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/107742.html
摘要:具體內容請參考。感謝大家閱讀,另外,在這邊幫朋友推一個愛心眾籌,希望大家能夠奉獻點愛心,朋友母親,身患直腸癌,目前在北京武警總醫院接收治療,可留言留下您的聯系方式,日后感激大家 判斷數組是否包含某一特定元素是很常見的需求,javascript中有很多實現方法,今天有空匯總了一下,按兼容性由強到弱排序,返回類型一律為boolean: 假設數組為arr,目標元素為target 循環遍歷: ...
摘要:返回字符串中指定位置的字符返回指定位置的字符的編碼輸出用于連接多個字符串。輸出方法用于把一個字符串分割成字符串數組。返回布爾值,表示參數字符串是否在原字符串的頭部。 1、charAt(index):返回字符串中指定位置的字符; charCodeAt(index):返回指定位置的字符的Unicode編碼 var str = abcdefghi; console.log(str.cha...
摘要:特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 特意對前端學習資源做一個匯總,方便自己學習查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入匯總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應和斧正,會及時更新,平時業務工作時也會不定期更...
摘要:最后代碼執行代碼執行,,調用優先順序成員訪問帶參數列表函數調用無參數列表查找一個字符串中指定字符出現的位置經典問題 1、 JavaScript中如何檢測一個變量類型是String?請寫出函數實現 //分析:String的兩種創建方法: //第一種方法: var str = str //str只是一個以String為數據類型的值,但并不屬于String對象的實例 //第二種方法: var...
摘要:收集的一些前端面試題從面試題發現不足,進而查漏補缺,比通過面試更難得及各大互聯網公司前端筆試面試題篇及各大互聯網公司前端筆試面試題篇面試題個和個經典面試題前端開發面試題如何面試前端工程師很重要個變態題解析如何通過餓了么面試輕 收集的一些前端面試題 從面試題發現不足,進而查漏補缺,比通過面試更難得 1 BAT及各大互聯網公司2014前端筆試面試題--Html,Css篇 2 BAT...
閱讀 754·2021-07-25 21:37
閱讀 3667·2019-08-30 15:55
閱讀 2582·2019-08-30 15:54
閱讀 1739·2019-08-30 15:44
閱讀 3134·2019-08-30 15:44
閱讀 873·2019-08-30 15:43
閱讀 1037·2019-08-29 15:36
閱讀 3050·2019-08-29 10:58