摘要:前端筆記基本數(shù)據(jù)類型種數(shù)據(jù)類型基本類型復(fù)雜類型基本類型與引用類型的區(qū)別基本類型基本類型,是按值訪問,可以操作保存在變量中的實際值基本類型的值不可變輸出輸出其中的實際值并未變化,方法是返回了一個新的字符串也不能對基本類型添加屬性和方法表明了基
前端筆記/JavaScript 基本 數(shù)據(jù)類型 6種數(shù)據(jù)類型
基本類型: Undefined、Null、Boolean、String、Number
復(fù)雜類型: Object
基本類型與引用類型的區(qū)別 基本類型基本類型(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()方法是返回了一個新的字符串,也不能對基本類型添加屬性和方法,表明了基本類型的值不可變
基本類型的比較是值的比較,只有在值相等時才相等
基本類型的變量存放在棧區(qū)
var name = "jobs" var age = 20
棧區(qū) | |
---|---|
name | age |
jobs | 20 |
棧區(qū)包含了變量的標識符和值
基本類型復(fù)制
var a = 10 var b = a a++ console.log(a, b) // 11 10 // 基本類型在復(fù)制操作后變量是相互獨立的互不影響引用類型
就是除了基本類型外的Object類型
引用類型值可以變,可以有屬性和方法
var person = {} // 創(chuàng)建個控對象 --引用類型 person.name = "jozo" person.age = 22 person.sayName = function(){console.log(person.name)} person.sayName() // "jozo" delete person.name // 刪除person對象的name屬性 person.sayName() // undefined // 引用類型的值是同時保存在棧內(nèi)存和堆內(nèi)存中的對象
棧區(qū)內(nèi)存保存變量的標識符和指向堆內(nèi)存中該對象的指針也就是該對象在堆內(nèi)存中的地址
var person1 = {name:"jozo"} var person2 = {name:"xiaom"} var person3 = {name:"xiaoq"}
棧區(qū) | 堆區(qū) | ||
---|---|---|---|
person1 | 堆內(nèi)存地址1 | ——> | Object1 |
person2 | 堆內(nèi)存地址2 | ——> | Object2 |
person3 | 堆內(nèi)存地址3 | ——> | Object3 |
引用類型比較是引用的比較
var p1 = {} var p2 = {} console.log(p1 == p2) // false // 引用類型是按引用訪問的,所以是比較它們的堆內(nèi)存中地址是否相同
對象引用
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 // 引用類型的復(fù)制是對象保存在棧區(qū)的堆內(nèi)存的地址的復(fù)制,兩個變量實際上指向同一個對象,因此任何操作都會互相影響傳遞參數(shù)
所有函數(shù)的參數(shù)都是按值傳遞
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 // 在函數(shù)內(nèi)部ot新定義了一個對象,obj引用了一個局部對象,外部p和內(nèi)部ot指向了不同對象,所以不會影響引用類型詳解
new操作符跟隨Object構(gòu)造函數(shù)
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
數(shù)組每一項都可以保存任何類型的數(shù)據(jù),而且數(shù)組大小可以動態(tài)調(diào)整,跟隨數(shù)據(jù)的添加而自動增長
var arr = new Array() // 使用Array構(gòu)造函數(shù) var arr = [] // 使用數(shù)組字面量表示法
length總會返回大于0的整數(shù),而且它不是只讀屬性
當設(shè)置length的值小于當前的數(shù)組長度時,會從末尾開始刪減元素
當設(shè)置length為大于當前數(shù)組長度時,則會從末尾新增項,新增每一項的值都為undefined
對只有一個全局作用域而言,使用instanceof操作符便可以
if (arr instanceof Array) { // 對數(shù)組的操作 } // instanceof操作符問題在于,它假定單一的全局執(zhí)行環(huán)境。若網(wǎng)頁中包含不同框架,那么實際上會有兩個以上不同的全局執(zhí)行環(huán)境,從而存在兩個以上不同的Array構(gòu)造函數(shù)
Array.isArray()方法來判斷
if (Array.isArray(arr)) { // 對數(shù)組的操作 }
棧方法:
push(): 可接受任意個參數(shù),逐個添加到數(shù)組末尾,并返回修改后數(shù)組長度
pop(): 從數(shù)組末尾移除最后一項,減少length的值,然后返回移除的項
隊列方法:
unshift(): 在數(shù)組前面添加任意個項,并返回新數(shù)組的長度
shift(): 移除數(shù)組第一個項,減少length的值,并返回移除的項
排序方法:
reverse(): 反轉(zhuǎn)數(shù)組項的順序
sort(): 默認升序排列,可接收一個比較函數(shù)作為參數(shù),比較函數(shù)有兩個參數(shù),若第一個參數(shù)要在第二個參數(shù)之前,則返回負數(shù),相等則返回0,若第一個參數(shù)要在第二個參數(shù)之后,則返回正數(shù)
> sort()會調(diào)用每項的toString()轉(zhuǎn)型方法,比較字符串,即使是數(shù)值也會轉(zhuǎn)型后比較字符串,因此[0, 1, 5, 10, 15]使用這個方法會變成[0, 1, 10, 15, 5]
操作方法
concat(): 可接收數(shù)組、等作為參數(shù),將數(shù)組合并
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()`: 可接受一個參數(shù)作為分隔符,將數(shù)組轉(zhuǎn)換為字符串 * `slice()`: 基于當前數(shù)組創(chuàng)建一個新數(shù)組,接受一個或者兩個參數(shù),起始位置和結(jié)束位置,不會影響當前數(shù)組。 > 若只有一個參數(shù),則返回從該參數(shù)位置開始到末尾所有的項 > 若兩個參數(shù)則返回起始位置到結(jié)束位置之間的項,但不包括結(jié)束位置
splice(): 主要作用向數(shù)組中插入項,始終返回一個數(shù)組,數(shù)組為原數(shù)組中刪除的項,若沒有則返回一個空數(shù)組,可以有三種用途
- 刪除:刪除任意數(shù)量的項,接受2個參數(shù):要刪除的第一項的位置和要刪除的個數(shù) - 插入:在指定位置插入任意數(shù)量的項,接受3個參數(shù):起始位置、0(要刪除的項數(shù)、要插入的項),如果要插入多個項,可以再傳入第四個,五個,任意個項 - 替換: 可以在任意位置插入任意項,同時刪除任意項,接受3個參數(shù):起始位置、要刪除的項數(shù)、要插入的項
位置方法
indexOf()和lastIndexOf()
都接受2個參數(shù):要查找的項和(可選)表示查找起點位置的索引,indexOf()從頭開始找,lastIndexOf()從末尾開始找
都返回要查找的項在數(shù)組中的位置,沒找到則返回-1,并且查找時是使用全等操作符(===)
迭代方法
共有五個迭代方法,每個方法都接受兩個參數(shù):要在每一項上運行的函數(shù)和(可選的)運行該函數(shù)的作用域?qū)ο蟆绊憈his的值。傳入這些方法中的函數(shù)接收三個參數(shù):數(shù)組項的值、該項在數(shù)組中的位置和數(shù)組對象本身
every(): 對數(shù)組每一項運行給定函數(shù),若該函數(shù)對每一項都返回true,則返回true
some(): 對數(shù)組每一項運行給定函數(shù),若該函數(shù)對任意一項返回true,則返回true
filter(): 對數(shù)組每一項運行給定函數(shù),返回該函數(shù)會返回true的項組成的數(shù)組
map(): 對數(shù)組每一項運行給定函數(shù),返回每次函數(shù)調(diào)用結(jié)果組成的數(shù)組
forEach(): 對數(shù)組每一項運行給定函數(shù),沒有返回值
以上方法都不會修改數(shù)組中的包含的值
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循環(huán)迭代數(shù)組一樣 */
reduce
reduce(function(total, currentValue [,currentIndex]) [,initialValue]): 是一種數(shù)組運算,通常用于將數(shù)組的所有成員"累積"為一個值。
- total:必選,初始值或者累積變量 - currentValue:必選,當前元素 - currentIndex:可選,當前元素的索引 - initialValue:可選,傳遞給函數(shù)的初始值 - 基本用法
/** * reduce(function(total, currentValue, currentIndex) [,initialValue]) 用于數(shù)組計算,通常用于將數(shù)組累積為一個值 */ /** * 參數(shù)tmp是累積變量,item為當前數(shù)組成員,index為數(shù)組下標;每次運行時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的特例 累積變量的初始值可以是一個數(shù)組,例子中初始值是一個空數(shù)組,結(jié)果返回一個新的數(shù)組,等同于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 - 嘗試執(zhí)行代碼塊 } catch(err) { catchCode - 捕獲錯誤的代碼塊 } finally { finallyCode - 無論 try / catch 結(jié)果如何都會執(zhí)行的代碼塊 } // 如果使用了try那么catch和finally必須選一個
通過RegExp類型來支持正則表達式,使用類似Perl的語法來創(chuàng)建正則表達式
var expression = / pattern / flags;
其中模式(pattern)可以是任何簡單或復(fù)雜的正則表達式,每個正則表達式可以有一個或者多個標志(flags),用以標明正則表達式的行為,匹配模式有以下三個標志.
g:全局模式,模式將被用于整個字符串而非在發(fā)現(xiàn)第一個匹配項時立即停止
i:不區(qū)分大小寫模式,即在匹配時忽略大小寫
m:多行模式,即在到達一行文字末尾時還會繼續(xù)查找下一行中是否存在與模式匹配的項
exec(): 接受一個參數(shù),即要使用模式的字符串
返回包含第一個匹配項的信息的數(shù)組,額外附帶2個屬性index和input,index表示匹配項在字符串中的位置,input表示應(yīng)用正則表達式的字符串,若沒有匹配項返回null
對于exec()而言即使在模式匹配設(shè)置了全局標志(g),也只會返回第一個匹配項,在不設(shè)置時,在同一字符串上多次調(diào)用也只會始終返回第一個匹配項的信息;而設(shè)置了,則每次調(diào)用都會繼續(xù)匹配新的項
test():接受一個字符串參數(shù),在模式與該參數(shù)匹配的情況下返回true否則返回false
函數(shù)其實是對象,每一個函數(shù)都是Function的實例,因此函數(shù)名實際上也是一個指向函數(shù)對象的指針,不會與函數(shù)綁定
解析器對函數(shù)聲明和函數(shù)表達式有差別對待
解析器會先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼前可用(可以訪問);至于函數(shù)表達式,則必須等到解析器執(zhí)行到所在代碼行才會真正被解析
// 函數(shù)聲明 console.log(sum(10, 10)) // 20 function sum(a, b) { return a + b } // 函數(shù)表達式 console.log(add(10, 10)) // 報錯 var add = function(a, b) { return a + b }
函數(shù)聲明,在代碼開始執(zhí)行前,解析器通過一個名為函數(shù)聲明提升的過程,讀取并將函數(shù)聲明添加到執(zhí)行環(huán)境中,并放到源代碼樹的頂端,因此可以先調(diào)用再定義
函數(shù)表達式,函數(shù)位于一個初始化語句中,也就是在執(zhí)行到函數(shù)代碼前,變量不會保存有對函數(shù)的引用
在函數(shù)內(nèi)部有兩個特殊對象arguments和this
arguments是一個類數(shù)組對象,保存著函數(shù)的所有參數(shù);它還有一個callee屬性,它是一個指針,指向擁有這個arguments對象的函數(shù)
callee
function factorial(num) { if (num <= 1) { return 1 } else { return num * arguments.callee(num - 1) /* arguments.callee即是factorial函數(shù) */ } } console.log(factorial(10)) // 3628800
caller,es5中定義的函數(shù)對象屬性,返回一個調(diào)用當前函數(shù)的引用,如果是由頂層調(diào)用的話,則返回null
function a() { console.log(arguments.callee.caller) // 因為arguments.callee就是函數(shù)a,所以arguments.callee.caller等于a.caller } function b() { a() } a() // null 因為是頂層調(diào)用 b() // b函數(shù)的源代碼
this,this引用的是(this的值)函數(shù)據(jù)以執(zhí)行的環(huán)境對象,在網(wǎng)頁全局作用域中調(diào)用函數(shù)時候this的引用對象就是window
每個函數(shù)都包含兩個屬性:length和prototype
length: 形參個數(shù)
prototype: 原型
每個函數(shù)包含兩個非繼承而來的方法: apply()和call();
作用都是在特定作用域中調(diào)用函數(shù),實際上等于設(shè)置this的值
apply():接收2個參數(shù),一個是在其中運行的函數(shù)的作用域,一個是Array實例或者arguments對象
call():接收2個參數(shù),一個是在其中運行的函數(shù)的作用域,其余參數(shù)要直接傳遞給函數(shù),也就是逐一列舉
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) // 參數(shù)逐一傳入 } console.log(sum3(10, 10)) // 20
apply()和call(),真正的用武之地并不在于傳遞參數(shù),而是擴充函數(shù)賴以運行的作用域
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(): 它會創(chuàng)建一個函數(shù)的實例,其this的值會被綁定到傳給bind函數(shù)的值
var colors = "skyblue" var c = { colors: "orange" } function say() { console.log(this.colors) } var say2 = say.bind(c) say2() // orange
bind與apply、call不同,不會立刻執(zhí)行
暫無
toFixed(): 接受一個參數(shù),代表保留幾位小數(shù),會四舍五入
var num = 10 console.log(num.toFixed(2)) // 10.00
string包含length屬性,返回字符串長度
字符方法
charAt()和charCodeAt():這兩個方法都接收一個參數(shù),即基于0的字符的位置.其中charAt()以單字符字符串的形式返回給定位置的字符,而charCodeAt()則是返回編碼
var stringTXT = "hellow" console.log(stringTXT.charAt(3)) // l console.log(stringTXT.charCodeAt(3)) // 108
字符串操作方法
concat():用于將一個或多個字符串拼接起來
slice(),substr(),substring():這三個方法都返回被操作字符串的子字符串,也都接受一或兩個參數(shù),第一個參數(shù)指定開始位置,第二個指定結(jié)束位置;slice和substring的第二個參數(shù)指定的是子字符串的最后一個字符后面的位置,substr的第二個參數(shù)則是指定返回字符的個數(shù)
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個參數(shù),第一個為要查找的字符串,(可選)第二個表示查找起點位置的索引,都是從字符串中尋找指定的字符串,然后返回該字符串的位置,若沒有則返回-1,一個從頭開始找,一個從末尾開始找
大小寫轉(zhuǎn)換
toLowerCase()和toUpperCase():全部轉(zhuǎn)換成小寫,大寫
toLocaleLowerCase()和toLocaleUpperCase():全部轉(zhuǎn)換成小寫,大寫,這是根據(jù)特定地區(qū)來轉(zhuǎn)換大小寫,在不知道代碼運行在哪個語言的情況下使用
字符串的模式匹配方法
match():接受一個參數(shù),參數(shù)為正則表達式或者RegExp對象,返回一個數(shù)組,數(shù)組保存著每一個匹配的子字符串
var txt = "abcdefgabcdefgabcdefg" var reg = /ab/gi console.log(txt.match(reg)) // ["ab", "ab", "ab"]
search():接受一個參數(shù),參數(shù)為正則表達式或者RegExp對象,從頭開始匹配,返回第一個匹配項的索引,沒有則返回-1
replace():接收2個參數(shù),字符串或者正則表達式或者RegExp對象,第二個則是用于替換的字符串或者函數(shù);若第一個參數(shù)為字符串則只會替換第一個子字符串,要想替換所有,則必須是正則表達式,并且指定全局標志(g);若第二個參數(shù)是函數(shù),則給這個函數(shù)傳入的三個參數(shù)分別是匹配項第一個匹配項,第二個等等,最后兩個參數(shù)為匹配項的位置和原始字符串
split():將字符串以指定分隔符分割成字符串,分隔符可以是字符串也可以是正則表達式或者RegExp對象;也可以接受第二個參數(shù),用于指定數(shù)組大小
內(nèi)置單體對象encodeURI():主要用于整個uri,它不會對本身屬于uri的特殊字符進行編碼如冒號、正斜杠、問好、井號
encodeURIComponent():主要用于對其中一段進行編碼,它會對任何非標準字符進行編碼
var uri = "http://www.who.com/search?wd=123" console.log(encodeURI(uri)) // 結(jié)果: http://www.who%08.com/search?wd=123 console.log(encodeURIComponent(uri)) // 結(jié)果: http%3A%2F%2Fwww.who%08.com%2Fsearch%3Fwd%3D123
encodeURIComponent使用的比encodeURI多
decodeURI():解碼方法,只能對encodeURI()編碼的進行解碼
decodeURIComponent():解碼方法,可以解碼所有字符
eval():這個方法像是一個完整的ECMAScript解析器,它接受一個字符串參數(shù),就是要執(zhí)行的js代碼字符串
Math.PI: π的值
求極值
min(),max():求最小,最大值;可以接受任意個參數(shù)
舍入方法
ceil():向上求整
floor():向下求整
round():四舍五入
隨機值
random(): 返回一個0-1之間的隨機數(shù),但不包含0和1,從區(qū)間內(nèi)取一個值,可以用一下公式
(max - min) * Math.random() + min
絕對值
abs(): 絕對值
次方
pow(a, n): 第一個為底,第二個參數(shù)為次方值,a的n次方
原型和閉包 對象(undefined,number,string,boolean)屬于簡單的值類型,不是對象。函數(shù)、數(shù)組、對象、null、構(gòu)造函數(shù)都是對象,都是引用類型判斷一個變量是不是對象,值類型用typeof,引用類型用instanceof
在js中數(shù)組、函數(shù)、對象都是對象,對象里面一切都是屬性,只有屬性,沒有方法; 方法也是一種屬性
對象都是通過函數(shù)創(chuàng)建的,函數(shù)是對象
function F() { this.name = "jobs" } var f1 = new F() // 對象可以通過函數(shù)創(chuàng)建 var arr = [1, 2, 3] // 語法糖,本質(zhì)是下面的簡寫 var arr = new Array() // Array是構(gòu)造函數(shù) arr[0] = 1 arr[1] = 2 arr[2] = 3原型
prototype原型
函數(shù)默認有一個prototype屬性,prototype屬性的值是一個對象(屬性的集合),默認只有一個constructor屬性指向這個函數(shù)本身
[image:DF9C0DF3-83B1-4F0C-8F2B-39C112BA24F6-1188-00000B31D26AD3B2/prototype-1.png]
如圖所示,superType是一個函數(shù),右邊是原型
原型作為對象,屬性的集合,可以自定義許多屬性,例如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就可以調(diào)用Fn中的屬性,因為每個對象都有一個隱藏屬性"__proto__",這個屬性引用了創(chuàng)建這個對象的函數(shù)的prototype,所以f1.__proto__ === Fn.prototype,這里的"__proto__"成為隱式原型
隱式原型__proto__是瀏覽器提供的屬性,就是[[prototype]]這個隱藏屬性,__proto__因為不是規(guī)范屬性,所以要避免使用;
es5中用Object.getPrototypeOf(obj)函數(shù)獲得一個對象的[[prototype]]
es6中用Object.setPrototypeOf(obj, prototype)函數(shù)可以直接修改一個對象的[[prototype]]
參數(shù)obj將被設(shè)置原型的對象.
prototype該對象新的原型(可以是一個對象或者null).
每個對象都有一個__proto__,可稱為隱式原型
__proto__是一個隱藏屬性
var obj = {} console.log(obj.__proto__ === Object.prototype)
有上述代碼可知:每個對象都有一個__proto__`屬性指向創(chuàng)建該對象的函數(shù)的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判斷規(guī)則是,沿著a的__proto__來找,沿著b的prototype來找,如果引用的同一個引用就返回true
[image:E4783050-568F-4369-A33E-192AE586FBE7-1188-00000B9545C250D1/instanceof-1.png]
即instanceof表示的就是一種繼承關(guān)系,或者原型鏈的結(jié)構(gòu)
[image:8826A813-C433-43DB-9C3D-CF0964451DDA-1188-00000B97B94D72D0/instanceof-2.png]
繼承JavaScript的繼承是用原型鏈來體現(xiàn)的
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函數(shù)new出來的對象,f1.a是f1對象的基本屬性,而f1.b是從Foo.prototype得來的,因為f1.__proto__指向Foo.prototype
訪問一個對象的屬性時,現(xiàn)在基本屬性中查找,如果沒有,就沿著__proto__鏈向上查找,這就是原型鏈
如何區(qū)分一個屬性是基本的還是從原型中找到的,用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的方法,這就是繼承
執(zhí)行上下文上下文環(huán)境
[image:B0C9A9CF-FB04-4776-A2E5-AA72796DC573-1188-00000BA936740391/this-1.png]
- 第一句報錯a未定義,二三句a為undefined,說明在js代碼一句句執(zhí)行前,瀏覽器就已經(jīng)開始一 些準備工作,其中就包括對變量的聲明,而不是賦值,賦值操作是在運行到語句時才執(zhí)行;
[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]
- 在這里對函數(shù)表達式和普通變量賦值一樣,而函數(shù)聲明則立刻賦值了
準備工作完成的事
變量、函數(shù)表達式 —— 變量聲明,默認賦值為undefined
this —— 賦值
函數(shù)聲明 —— 賦值
這三種數(shù)據(jù)準備情況就是‘執(zhí)行上下文’或者‘執(zhí)行上下文環(huán)境’
js在執(zhí)行代碼片段前都會進行準備工作來生成‘執(zhí)行上下文’,代碼片段分三種情況:全局代碼、函數(shù)體、eval代碼
在函數(shù)中,arguments和函數(shù)參數(shù)會直接賦值;函數(shù)每調(diào)用一次,都會產(chǎn)生一個新的執(zhí)行上下文環(huán)境;而且函數(shù)在定義的時候(不是調(diào)用的時候),就已經(jīng)確定函數(shù)體內(nèi)部自由變量的作用域
在執(zhí)行代碼之前,把將要用到的所有的變量都事先拿出來,有的直接賦值了,有的先用undefined占個空
全局代碼的上下文環(huán)境為
普通變量(包含函數(shù)表達式) | 聲明(默認賦值為undefined) |
函數(shù)聲明 | 賦值 |
this | 賦值 |
如果代碼片段是函數(shù)體,則在此基礎(chǔ)上附加
參數(shù) | 賦值 |
arguments | 賦值 |
自由變量的取值作用域 | 賦值 |
函數(shù)中this到底是什么值,是在函數(shù)真正被調(diào)用時確定的,函數(shù)定義時確定不了;this永遠指向的是最后調(diào)用它的對象,也就是看它執(zhí)行的時候是誰調(diào)用的;因為this取值是執(zhí)行上下文環(huán)境的一部分,每次調(diào)用都會產(chǎn)生一個新的執(zhí)行環(huán)境上下文
分四種狀況
構(gòu)造函數(shù)
function F(num) { this.num = num this.log = "txt" console.log(this) }
- 把函數(shù)作為構(gòu)造函數(shù),那么this就是new出來的對象 - 函數(shù)作為對象的一個屬性 - 如果函數(shù)作為對象的一個屬性,并且作為對象的屬性被調(diào)用時,this指向該對象
var obj = { x: 10, fn: function() { console.log(this) // {x:10, fn: function} console.log(this.x) // 10 } } obj.fn()
- 函數(shù)調(diào)用call和apply,bind時調(diào)用 - 當一個函數(shù)被call和apply調(diào)用時,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
全局和調(diào)用普通函數(shù)
this指向window
作用域作用域
[image:C6407A7F-8B78-4A86-8C15-6697981F687C-1188-00000BFD4FA9B6C0/this-5.png]
[image:08320C13-AE3E-4C60-A615-25442AD209CA-1188-00000BFECEDB8EC1/this-6.png]
作用域中變量的值是在執(zhí)行過程中產(chǎn)生的確定的
如果要查找一個作用域下某個變量的值,就需要找到這個作用域?qū)?yīng)的執(zhí)行上下文環(huán)境,再在其中尋找變量的值
自由變量和作用域鏈要到創(chuàng)建這個函數(shù)的那個作用域中取值——是“創(chuàng)建”,而不是“調(diào)用”,切記切記——其實這就是所謂的“靜態(tài)作用域”
作用域鏈
[image:12DFA8C1-973E-4680-A97D-C57F33ABEBCB-1188-00000C050C4391C4/this-7.png]
面向?qū)ο蟮某绦蛟O(shè)計 屬性類型包含兩種數(shù)據(jù)屬性和訪問器屬性數(shù)據(jù)屬性
數(shù)據(jù)屬性包含一個數(shù)據(jù)值的位置,在這個位置可以讀取和寫入值,數(shù)據(jù)屬性有4個描述其行為的特性
[[Configurable]]:表示能否通過delete刪除屬性,從而重新定義屬性,能否修改屬性特性,能否把屬性修改為訪問器屬性
[[Enumerable]]:能否通過for-in循環(huán)返回屬性
[[Writable]]:能否修改屬性值
[[Value]]:包含這個屬性的數(shù)據(jù)值,默認undefined
直接在對象上定義的屬性,它們的[[Configurable]]、[[Enumerable]]、[[Writable]]的值默認為true,[[Value]]為指定值
var p = { name: "nico" } // [[Value]]的值為 nico
要修改屬性默認特性,必須使用es5的Object.defineProperty()方法,接收三個參數(shù),屬性所在對象,屬性名字和一個描述符對象。其中描述符對象屬性必須是:configurable、enumerable、writable、value.設(shè)置其中一個或多個值(小寫)可以多次調(diào)用Object.defineProperty(),但是Configurable一旦設(shè)置為false(不可配置),就不能再將其設(shè)置為true(可配置),而且為false時其他屬性也受到限制了
在調(diào)用Object.defineProperty()時,若不設(shè)置,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) // 報錯訪問器屬性
訪問器屬性不包含數(shù)據(jù)值,包含一對getter和setter函數(shù)(不過它們不是必須的),在讀取訪問器屬性時,會調(diào)用getter函數(shù),它負責(zé)返回有效的值;在寫入訪問器屬性時會調(diào)用setter函數(shù),它負責(zé)處理數(shù)據(jù);訪問器有如下4個特性
* [[Configurable]]:表示能否通過delete刪除屬性,從而重新定義屬性,能否修改屬性特性,能否把屬性修改為訪問器屬性
[[Enumerable]]:能否通過for-in循環(huán)返回屬性
[[Get]]:在讀取時調(diào)用的函數(shù),默認值為undefined
[[Set]]:在寫入屬性時調(diào)用的函數(shù),默認值為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
這是使用訪問器屬性的常見方式,即設(shè)置一個屬性的值會導(dǎo)致其他屬性發(fā)生變化定義多個屬性不一定要同時使用getter和setter,只指定getter表示屬性不能寫,嘗試寫入屬性會被忽略;只指定setter表示不能讀,否則會返回undefined;在嚴格模式下都會拋出錯誤
Object.defineProperties(),es5中定義的,可以通過描述符一次定義多個屬性,接收2個對象參數(shù),第一個是要添加和修改其屬性的對象,第二個對象的屬性與第一個對象中要添加或修改的屬性要一一對應(yīng)
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個參數(shù):屬性所在對象和要讀取的其描述符的屬性名,返回值為一個對象;如果是數(shù)據(jù)屬性,這個對象的屬性有configurable、enumerable、writable、value;如果是訪問器屬性,這個對象的屬性有configurable、enumerbale、get、set創(chuàng)建對象 工廠模式
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
工廠模式解決了創(chuàng)建多個相似對象的問題,但沒有解決對象識別問題(怎么知道一個對象的類型)構(gòu)造函數(shù)模式
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
與工廠模式對比,沒有顯示的創(chuàng)建對象,直接將屬性和方法賦給了this對象,沒有return語句在這個模式下創(chuàng)建的所有對象既是Object的實例又是Person的實例
創(chuàng)建自定義構(gòu)造函數(shù)意味著可以將它的實例標識為一種特定類型,這正是構(gòu)造函數(shù)模式勝過工廠模式的地方
使用構(gòu)造函數(shù)會使得每個方法都要在每個實例上創(chuàng)建一遍,在上述例子中p1和p2都有say方法,但那不是同一個Fuction的實例,因為在js中函數(shù)是對象,會導(dǎo)致不同的作用域鏈和標識符解析
console.log(p1.say == p2.say) // false原型模式
創(chuàng)建的函數(shù)都有一個prototype(原型)屬性,它是一個指針,指向一個對象,這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法,也就是prototype就是通過調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個對象實例的原型對象
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
理解原型對象
只要創(chuàng)建了新函數(shù),就會為該函數(shù)創(chuàng)建一個prototype屬性,這個屬性指向函數(shù)的原型對象
默認情況下,所有原型對象都會自動獲得一個constructor(構(gòu)造函數(shù))屬性,這個屬性包含一個指向prototype屬性所在函數(shù)的指針,例如前面的代碼中Person.prototype.constructor指向Person;通過這個構(gòu)造函數(shù)可以繼續(xù)為原型對象添加其它屬性和方法
創(chuàng)建了自定義構(gòu)造函數(shù)后,其原型對象默認只會取得constructor屬性;至于其他方法,則從Object繼承而來
當調(diào)用一個構(gòu)造函數(shù)創(chuàng)建一個新的實例后,該實例內(nèi)部包含一個指針(內(nèi)部屬性),指向構(gòu)造函數(shù)的原型對象;es5中這個指針叫[[Prototype]],在腳本中沒有標準的方式訪問[[Prototype]],但Firefox,Safari,Chrome在每個對象上都支持一個屬性__proto__;這個鏈接存在于實例與構(gòu)造函數(shù)的原型對象之間,而不是實例與構(gòu)造函數(shù)之間
可以通過對象實例訪問保存在原型中的值,但卻不能重寫原型中的值
原型模式最大問題是由其共享的本性所導(dǎo)致的,改變一個實例的屬性,所有實例都會變
更簡單的原型語法
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
以對象字面量形式創(chuàng)建,會導(dǎo)致constructor屬性不再指向Person
可以設(shè)置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
但這樣會導(dǎo)致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組合模式 - 最常用方式
概述
組合使用構(gòu)造函數(shù)模式和原型模式
這是創(chuàng)建自定義類型最常見的模式
構(gòu)造函數(shù)模式用于定義實例屬性,而原型模式用于定義方法和共享的屬性
這樣,每個實例都有一份自己的實例屬性的副本,同時又共享著對方法的引用,還支持向構(gòu)造函數(shù)傳參
這種模式是目前使用最廣泛的一種創(chuàng)建自定義類型的方法,可以說是用來定義引用類型的一種默認模式
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動態(tài)原型模式
為了解決獨立的構(gòu)造函數(shù)和原型,動態(tài)原型模式將所有信息封裝到構(gòu)造函數(shù)中,而通過在構(gòu)造函數(shù)中初始化原型,又保持了同時使用構(gòu)造函數(shù)和原型的優(yōu)點;也就是通過檢測某個應(yīng)該存在的方法是否有效來決定是否初始化原型
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方法不存在時,才會將它添加到原型中,這段代碼只有在初次調(diào)用構(gòu)造函數(shù)時才會執(zhí)行
if語句檢查可以使初始化之后應(yīng)該存在的任何屬性或方法,不必一堆if語句來檢測每個屬性和每個方法,只要檢查其中一個即可,還可以使用instanceof來確定類型
寄生構(gòu)造函數(shù)模式與工廠模式一樣,instanceof操作符不能用來確定對象類型,在能使用其他模式的情況下不推薦使用穩(wěn)妥構(gòu)造函數(shù)模式
function Person(name, age) { var o = {} o.say = function() { console.log(name) } return o } var p1 = Person("alice", 20) p1.say() // alice
這樣變量Person中保存的是一個穩(wěn)妥對象,除了調(diào)用say()外,無法訪問其數(shù)據(jù)成員,這種模式instanceof也沒什么意義繼承 借用構(gòu)造函數(shù)
使用call或者apply,將父對象的構(gòu)造函數(shù)綁定在子對象上
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) // 貓科動物
方法都在構(gòu)造函數(shù)中定義,函數(shù)無法復(fù)用,借用構(gòu)造函數(shù)很少多帶帶使用
原型鏈使用prototype屬性,如果子構(gòu)造函數(shù)的prototype對象指向一個父構(gòu)造函數(shù)的實例,那么所有子構(gòu)造函數(shù)的實例都可以繼承父構(gòu)造函數(shù)了
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屬性,由于上述代碼,會導(dǎo)致Cat.prototype.constructor指向Animal,需要重新將構(gòu)造函數(shù)定義回Cat - 如果替換了prototype對象那么下一步必定是將constructor指向原來的構(gòu)造函數(shù) * 由于不能在不影響所有對象實例的情況下傳參和由于原型中包含的引用類型值得問題,很少會多帶帶使用原型鏈原型式繼承(用空對象做中介)
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函數(shù),就是YUI庫如何實現(xiàn)繼承的方法寄生繼承最后一行只是為了實現(xiàn)繼承的完備性,純屬備用性質(zhì)
創(chuàng)建一個僅用于封裝繼承過程的函數(shù)
無法實現(xiàn)函數(shù)復(fù)用
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組合繼承 - 最常用方式
也叫偽經(jīng)典繼承,將原型鏈和借用構(gòu)造函數(shù)的技術(shù)整合一起,從而發(fā)揮二者之長
通過原型鏈實現(xiàn)對原型屬性和方法的繼承,通過借用構(gòu)造函數(shù)來實現(xiàn)對實例屬性的繼承
最常用方式
函數(shù)可復(fù)用,可傳參,不存在引用屬性共享問題
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) // 創(chuàng)建對象 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函數(shù)實現(xiàn)了寄生組合的最簡單形式,在函數(shù)內(nèi)部先創(chuàng)建超類原型副本,為創(chuàng)建的副本添加constructor屬性,最后將副本賦給子類型的原型
瀏覽器環(huán)境 DOM和BOM BOM瀏覽器對象模型,提供了獨立于瀏覽器顯示內(nèi)容而與瀏覽器窗口進行交互的對象location
用于存儲當前頁面URL信息的對象
location的屬性如下:
//假設(shè)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(): 無參數(shù),重新載入當前頁面; location = location也能用于重新載入當前頁面
assign(newURL): 載入新頁面會留下歷史記錄
replace(newURL): 載入新頁面不會留下歷史記錄
histroy存儲了頁面的訪問記錄
window.history.lenght: 存儲的記錄數(shù)
history.forward(): 前進
history.back(): 后退
history.go(): 0重新載入當前頁面; 正值前進幾個頁面; 負值后退幾個頁面
screen提供了桌面信息
screen.width,screen.height: 桌面分辨率,總大小
screen.availWidth,screen.availHeight: 除去操作系統(tǒng)菜單欄(例如windows的任務(wù)欄)以外的區(qū)域大小
alert,prompt,confirm這幾個并不屬于ECMAScript,而是BOM方法定時器
定時器也是BOM方法DOM
文檔對象模型,將xml或html文檔解析成樹形節(jié)點的方法DOM節(jié)點
nodeName : 節(jié)點的名稱
nodeValue :節(jié)點的值
nodeType :節(jié)點的類型
getElementsByTagName、getElementsByName、getElementById
可以用屬性形式訪問attribute,因為class為保留字,所以class要用className訪問
屬性:nextSibling與previousSibling,得到下一個兄弟節(jié)點、上一個兄弟節(jié)點;空行也算
屬性:nextElementSibling 與previousElementSibling,得到下一個上一個兄弟元素節(jié)點
innerHtml,可用于修改節(jié)點內(nèi)容
style屬性用于修改樣式
document.createElement(): 創(chuàng)建元素節(jié)點
document.createTextNode: 創(chuàng)建文本節(jié)點
cloneNode(): 該方法有一個參數(shù),true深拷貝,包括所有子節(jié)點, false淺拷貝,只針對當前節(jié)點
var odv = document.getElementsByTagName("div")[0]; var p2 = document.getElementsByTagName("p")[1]; odv.appendChild(p2.cloneNode(false)); odv.appendChild(p2.cloneNode(true)); // 淺拷貝,文本節(jié)點不會拷貝
appendChild(newChild): 將節(jié)點插入到 節(jié)點的子節(jié)點列表的末尾
insertBefore(newChild, refChild): 將節(jié)點插入節(jié)點指定子節(jié)點的前面
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): 從子節(jié)點列表中移除指定節(jié)點
replaceChild(newChild, oldChild): 將指定子節(jié)點替換成新節(jié)點
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")的調(diào)用
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) : 第一個參數(shù)為事件名不加on,第二個參數(shù)為函數(shù),第三個為布爾值默認為false在冒泡階段執(zhí)行,true在捕獲階段執(zhí)行
removeEventListener(): 該方法與上一個參數(shù)相同,它是移除監(jiān)聽器;但若是第二個參數(shù)為匿名函數(shù)則移除不了
捕捉和冒泡捕捉:事件先發(fā)生在document上,依次傳遞給body等,最終達到該元素上
冒泡:事件先發(fā)生在該元素上,再依次向上,然后到body,直至document對象上
阻斷事件傳播stopPropagation(): 這樣就使得事件無法傳播了,只發(fā)生在自己身上
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);跨瀏覽器事件監(jiān)聽(兼容IE)
DOM2屬性 | IE對應(yīng)屬性 | 說明 |
---|---|---|
addEventListener | attachEvent | 事件監(jiān)聽 |
event | window.event | IE中的全局事件對象 |
target | srcElement | 事件元素的target屬性 |
stopPropagation | cancelBubble | only-IE屬性,設(shè)置為true |
preventDefault | returnValue | only-IE屬性,設(shè)置為false |
removeEventListener | detachEvent | 移除事件監(jiān)聽 |
就是HTML、CSS和JS分開命名空間
為了減少命名沖突,通常減少全局變量的使用;更好的方法是將不同變量和方法定義在不同命名空間中;本質(zhì)是只定義一個全局變量,并將其它變量和方法定義為該變量的屬性將對象用作命名空間
// 新建全局變量MYAPP var MYAPP = MYAPP || {}; // 添加屬性 MYAPP.event = {}; // 添加方法 MYAPP.event = { getEvent: function(e) { // ...... }, // ......other methods }命名空間中構(gòu)造器應(yīng)用
我們可以在命名空間中使用構(gòu)造器函數(shù)
// 本例中,我們用Element構(gòu)造器創(chuàng)建一個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設(shè)計模式 設(shè)計模式有23種甚至更多,下面為4種常用模式單例模式 工廠模式 裝飾器模式 觀察者模式var sub = { callbacker: [], // 發(fā)布 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用于申明變量,并且只在該代碼塊內(nèi)有效
let不存在變量提升,只能先聲明再使用
暫時性死區(qū),在代碼塊內(nèi)未使用let申明變量前,變量都是不可用的
不允許重復(fù)聲明變量
let和const實際上為js提供了塊級作用域
constconst就是常量
一旦聲明,必須就賦值,且不可變更
無法重復(fù)聲明
全局對象的屬性全局對象是最頂層的對象,在瀏覽器環(huán)境中是window對象,在nodeJS中是global對象
es5中全局對象屬性與全局變量等價
es6中var,function命令聲明的全局變量依然是全局對象的屬性;而let、const、class命令聲明的全局變量則不再是全局對象的屬性
變量的解構(gòu)賦值 數(shù)組的結(jié)構(gòu)賦值 基本用法let [a, b, c] = [1, "a", ["c"]]; console.log(a, b, c); // 1, "a", ["c"]即匹配模式,等號兩邊格式一樣,即可進行變量的賦值
若右邊表達式不是數(shù)組,則會報錯;只要有Iterator接口的數(shù)據(jù)結(jié)構(gòu)都可以使用數(shù)組形式的解構(gòu)賦值
適用于var、let、const命令
若解構(gòu)失敗變量值為undefined
默認值解構(gòu)賦值允許有默認值
ES6內(nèi)部使用嚴格相等運算符(===),所以一個數(shù)組成員不嚴格等于undefined是不會使用默認值的
var [a = 1, b = 2, c = 3, d = 4] = [undefined, null, "c", d]; console.log(a, b, c, d); //1 null "c" 4對象的解構(gòu)賦值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 標題 /*對象的解構(gòu)賦值也能設(shè)置默認值,同樣只有在值嚴格為undefined時,默認值才會有用*/ var {bat = 123, bas = 456, bad} = {bat: undefined, bas: null, bad: "bad"}; console.log(bat, bas, bad); // 123 null "bad" /*若解構(gòu)失敗變量值為undefined*/ /*對象的解構(gòu)賦值,可以方便的將對象方法賦值到某個變量中*/ var {pow, random} = Math; // 將Math對象的次方和隨機數(shù)方法賦值給了pow和random console.log(pow(2, 3)); // 8 console.log(random()); // 隨機數(shù) /*因為數(shù)組也是特殊對象,因此數(shù)組也能進行對象的解構(gòu)賦值*/ var arr = [1, 2, 3]; var {0: first, [arr.length - 1]: last} = arr; console.log(first, last); // 1 3字符串的解構(gòu)賦值// 將字符串轉(zhuǎn)成了類似數(shù)組的對象 const [a, b] = "hi"; console.log(a, b); // h i // 字符串有l(wèi)ength屬性,因此可以對這個對象進行解構(gòu)賦值 var { length: len } = "hello"; console.log(len); // 5函數(shù)參數(shù)的解構(gòu)賦值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]解構(gòu)賦值的應(yīng)用交換變量值
[x, y] = [y, x];從函數(shù)返回多個值
函數(shù)參數(shù)定義和設(shè)置默認值
遍歷Map結(jié)構(gòu)
輸入模塊的指定方法
提取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]數(shù)組的擴展 新增方法 Array.fromArray.from方法用于將類似數(shù)組的對象和可遍歷對象(包含set、map)轉(zhuǎn)換成數(shù)組實際應(yīng)用中可以將DOM操作返回的NodeList和函數(shù)內(nèi)arguments轉(zhuǎn)為數(shù)組
還能接受第二個參數(shù),作用類似于數(shù)組的map方法,對每個元素進行處理,將處理后的值放入返回的數(shù)組
Array.of用于將一組值轉(zhuǎn)換為數(shù)組
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] /*因為數(shù)組的構(gòu)造函數(shù),只有在參數(shù)不小于2時才會作為數(shù)組值,一個參數(shù)時作為數(shù)組長度;Array.of則是保持一致,無論參數(shù)多少都作為數(shù)組元素*/copyWithincopyWithin(target, start, end): 將指定位置的成員復(fù)制到其他位置(會覆蓋原有成員),然后返回當前數(shù)組,也就是會修改當前數(shù)組
參數(shù):
target(必須): 從該位置開始替換
start(可選):從該位置讀取,默認為0,若為負值則為倒數(shù)
end(可選):讀取到該位置結(jié)束,默認為數(shù)組長度,若為負值則為倒數(shù)
find和findIndex參數(shù)為一個函數(shù),將數(shù)組內(nèi)元素依次執(zhí)行該回調(diào)函數(shù),找出第一個返回值為true的成員,find是返回這個成員,若沒有符合條件的成員則返回undefined;findIndex是返回該成員位置,若沒有符合條件的成員則返回-1
回調(diào)函數(shù),接收三個參數(shù):當前值、當前位置、原數(shù)組
fill用給定值,填充一個數(shù)組,會覆蓋原有全部值
可以接受第二、三個參數(shù),用于指定填充的起始和結(jié)束位置
數(shù)組實例的keys、values、entries都用于遍歷數(shù)組,返回一個遍歷器,可用for...of來遍歷
keys()是對鍵名,values()是對鍵值,entries()是對鍵值對
數(shù)組實例的includesincludes返回一個布爾值,表示數(shù)組是否包含給定的值
該方法可選第二個參數(shù),代表起始搜索位置,默認為0,若為負值則倒數(shù)
[1, 2, 3].includes(2) // true函數(shù)擴展 函數(shù)的默認值可以設(shè)置函數(shù)默認值,有默認值的參數(shù)最好作為尾參
可使用rest參數(shù), 即...參數(shù)
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參數(shù)是一個數(shù)組,可以使用任意數(shù)組方法
rest參數(shù)后面不能再跟任何參數(shù)
rest參數(shù)可以替代Array.prototype.slice.call(arguments)
擴展運算符 基本含義擴展運算符就是三個點...,用于將數(shù)組轉(zhuǎn)為用逗號分隔的參數(shù)序列
function add(...val) { let sum = 0; for (l
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/107742.html
摘要:具體內(nèi)容請參考。感謝大家閱讀,另外,在這邊幫朋友推一個愛心眾籌,希望大家能夠奉獻點愛心,朋友母親,身患直腸癌,目前在北京武警總醫(yī)院接收治療,可留言留下您的聯(lián)系方式,日后感激大家 判斷數(shù)組是否包含某一特定元素是很常見的需求,javascript中有很多實現(xiàn)方法,今天有空匯總了一下,按兼容性由強到弱排序,返回類型一律為boolean: 假設(shè)數(shù)組為arr,目標元素為target 循環(huán)遍歷: ...
摘要:返回字符串中指定位置的字符返回指定位置的字符的編碼輸出用于連接多個字符串。輸出方法用于把一個字符串分割成字符串數(shù)組。返回布爾值,表示參數(shù)字符串是否在原字符串的頭部。 1、charAt(index):返回字符串中指定位置的字符; charCodeAt(index):返回指定位置的字符的Unicode編碼 var str = abcdefghi; console.log(str.cha...
摘要:特意對前端學(xué)習(xí)資源做一個匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進步。 特意對前端學(xué)習(xí)資源做一個匯總,方便自己學(xué)習(xí)查閱參考,和好友們共同進步。 本以為自己收藏的站點多,可以很快搞定,沒想到一入?yún)R總深似海。還有很多不足&遺漏的地方,歡迎補充。有錯誤的地方,還請斧正... 托管: welcome to git,歡迎交流,感謝star 有好友反應(yīng)和斧正,會及時更新,平時業(yè)務(wù)工作時也會不定期更...
摘要:簡介前端發(fā)展迅速,開發(fā)者富有的創(chuàng)造力不斷的給前端生態(tài)注入新生命,各種庫框架工程化構(gòu)建工具層出不窮,眼花繚亂,不盲目追求前沿技術(shù),學(xué)習(xí)框架和庫在滿足自己開發(fā)需求的基礎(chǔ)上,然后最好可以對源碼進行調(diào)研,了解和深入實現(xiàn)原理,從中可以獲得更多的收獲隨 showImg(https://segmentfault.com/img/remote/1460000016784101?w=936&h=397)...
摘要:最后代碼執(zhí)行代碼執(zhí)行,,調(diào)用優(yōu)先順序成員訪問帶參數(shù)列表函數(shù)調(diào)用無參數(shù)列表查找一個字符串中指定字符出現(xiàn)的位置經(jīng)典問題 1、 JavaScript中如何檢測一個變量類型是String?請寫出函數(shù)實現(xiàn) //分析:String的兩種創(chuàng)建方法: //第一種方法: var str = str //str只是一個以String為數(shù)據(jù)類型的值,但并不屬于String對象的實例 //第二種方法: var...
摘要:收集的一些前端面試題從面試題發(fā)現(xiàn)不足,進而查漏補缺,比通過面試更難得及各大互聯(lián)網(wǎng)公司前端筆試面試題篇及各大互聯(lián)網(wǎng)公司前端筆試面試題篇面試題個和個經(jīng)典面試題前端開發(fā)面試題如何面試前端工程師很重要個變態(tài)題解析如何通過餓了么面試輕 收集的一些前端面試題 從面試題發(fā)現(xiàn)不足,進而查漏補缺,比通過面試更難得 1 BAT及各大互聯(lián)網(wǎng)公司2014前端筆試面試題--Html,Css篇 2 BAT...
閱讀 742·2021-07-25 21:37
閱讀 3654·2019-08-30 15:55
閱讀 2572·2019-08-30 15:54
閱讀 1717·2019-08-30 15:44
閱讀 3123·2019-08-30 15:44
閱讀 859·2019-08-30 15:43
閱讀 1021·2019-08-29 15:36
閱讀 3038·2019-08-29 10:58