javascript
《javascript面向对象编程指南》读书笔记
《javascript面向對象編程指南》讀書筆記
- 《javascript面向對象編程指南》讀書筆記
- 第一章 面向對象的JavaScript
- 第二章 基本數據類型與流程控制
- 變量
- 數據類型
- typeof
- 數字
- 字符串
- 轉義字符
- bool值
- 邏輯運算符
- 比較運算符
- undefined與null
- 數組
- 數組元素的增刪改查
- 多維數組
- Map(ES6規范)
- Set(ES6規范)
- 流程控制
- 條件語句
- 循環語句
- 第三章 函數
- 函數定義
- 參數
- 返回值
- 內建函數
- 變量作用域
- 變量提升
- 匿名函數
- 回調函數
- 即時函數(自執行函數)
- 內部(私有)函數
- 函數中this指向的坑
- 返回函數的函數
- 能重寫自己的函數
- 閉包
- 作用域鏈
- 寫法
- 應用
- 第四章 對象
- js中對象與數組的區別
- 對象聲明和訪問
- 聲明
- 屬性的訪問
- 屬性的增刪改
- 全局對象
- constructor屬性
- instanceof操作符
- 對象作為參數傳遞
- 比較對象
- 內建對象
- Object
- Array
- length屬性
- 一些內建方法
- Function
- 函數對象的內建屬性:
- call和apply
- Boolean
- Number
- String
- Math
- Date
- RegExp
- replace
- 回調式替換
- Error對象
- 第五章 原型
- 原型屬性
- 原型對象上的屬性和方法
- 原型鏈
- 枚舉屬性
- isPrototypeOf()
- __proto__
- 原型作用
- 原型陷阱
- 第六章 繼承
- 實現方法1
- 實現方法2
- ES6中繼承寫法
- 第七章 瀏覽器環境
- BOM(瀏覽器對象模型)
- window對象
- window.navigator
- window.location
- window.history
- H5中history的API
- window.frames
- window.screen
- window.open/window.close
- window.moveTo()、window.moveBy()、window.resizeTo()、window.resizeBy()
- window.alert()、window.confirm()、window.prompt()
- window.setTimeout()、window.setInterval()
- window.document
- window對象
- DOM(文檔對象模型)
- DOM節點的訪問
- 方法一 索引訪問法
- 方法二 快捷訪問法
- DOM節點的修改
- DOM節點的新建
- DOM節點的移除
- 只適用于HTML的DOM對象
- DOM節點的訪問
- 事件
- 注冊事件三種方式
- 捕捉法和冒泡法
- 阻斷冒泡
- 防止默認行為
- 事件類型
- XMLHttpRequest對象
- BOM(瀏覽器對象模型)
第一章 面向對象的JavaScript
HTML專注于內容,CSS專注于表現,JavaScript專注于行為。
JavaScript術語包含三個部分:
- ECMAScript:語言的核心部分(變量、函數、循環等等),獨立于瀏覽器,可以在其他環境中使用。
- 文檔對象模型(DOM)
- 瀏覽器對象模型(BOM)
ECMAScript和JavaScript的區別:
ECMAScript是為了規范各種前端腳本語法的標準(后端node.js也包含ECMAScript),JavaScript只是其的一種實現。
第二章 基本數據類型與流程控制
變量
- 變量名可以由字母、數字、下劃線、美元符號組合而成。
- 變量名不能以數字開頭。
- 變量名區分大小寫。
數據類型
共6大數據類型
- 值類型
- 數字
- 字符串
- 布爾值
- undefined
- null
- 引用類型
- object
typeof
- 作用:查看變量的類型是什么
- 取值:
- "number"
- "string"
- "boolean"
- "undefined"
- "object"
- "function" (相比6種數據類型,null變成了function)
注意:
- typeof(null) === 'object'; //true
- 檢測變量存在且初始化過用typeof(somevar) !== "undefined"
數字
字符串
轉義字符
| \\、\'、\" | 由于\、'、"在js中是關鍵符號,所以需要轉義 |
| \n | 換行符 |
| \r | 回車符 |
| \t | 制表符 |
| \u | \u后面的字符將會被視為Unicode碼 |
bool值
if(變量)時,以下值被當作false。
- 空字符串
- null
- undefined
- 數字0
- 數字NaN
注意:
- 不代表以上值 == false,如null == false; //false
- if('false')、if('0')都為true,因為非空字符串當作true
邏輯運算符
優先級:!> && > || ,但為了可讀性,最好加括號。
惰性求值:前面的滿足,后面不會執行。
比較運算符
| == | 相等運算符 | null == undefined;//true '1'==true; //true '1'==1; //true | ||
| === | 嚴格相等運算符 | 類型相同&&值相同 | null === undefined; //false 1 === '1'; //false | |
| != | 不相等運算符 | NaN!=NaN;//true '1'!=1; //false | ||
| !== | 嚴格不相等運算符 | '1'!==1; //true | ||
| > | 大于運算符 | '2'>1 ;//true | ||
| >= | 大于等于運算符 | 1>='1'; //true | ||
| < | 小于運算符 | 1<'2'; //true | ||
| <= | 小于等于運算符 | 1<='1'; //true |
注意:
- 以上表格僅針對值類型,對于引用類型,若引用的是同一個對象,則相等且嚴格相等。
- 后四種沒有對應的嚴格大于、嚴格大于等于、......。
undefined與null
- 聲明而不初始化一個變量時,javascript會自動用undefined值來初始化。
- 當與數字進行運算時,undefined返回NaN,null則會被當作0進行運算
例子:
let somevar;somevar === undefined;//true 1*undefined;//NaN;1*null;//0數組
數組為引用類型,typeof([]) === 'object' //true
數組元素的增刪改查
- 聲明:let a = [2,4,5]
- 增加:a[4]=6;//跳過了a[3],a[3]將為undefined
- 刪除:delete a[0];//刪除后數組長度不變,被刪除地方的值變為undefined
- 更新:a[4]=7
- 訪問:a[0]
注意:
- delete元素不會改變數組長度,要想改變數組長度見第四章的Array的pop和splice方法。
- 字符串也以當作數組用索引訪問每個字符。
多維數組
Map(ES6規范)
- 存在必要:JavaScript中的{}的鍵只能是字符串,若要以其他數據類型(包括引用類型)為鍵則可以用到map。
初始化:
let m1 = new Map(); // 空Map let m2 = new Map([['Michael', 95], ['Bob', 75], ['Tracy', 85]]);- 操作:
|屬性/方法|作用|
|---|---|
|size|返回成員數量|
|clear()|清空所有成員,無返回值|
|has(key)|判斷是否存在指定成員,返回值為 true / false|
|get(key)|獲取指定成員的值,如不存在則返回 undefined|
|set(key, value)|為key設置鍵值,如已經存在該key則更新,否則添加新元素,返回值是實例本身|
|delete(key)|刪除key的鍵值對,返回值為 true / false| 注意:map的鍵必須唯一,若加入重復的鍵,后面的值會沖掉前面的值。
Set(ES6規范)
初始化:
let s1 = new Set(); // 空Set let s2 = new Set([1, 2, 3]); // 含1, 2, 3- 操作:
|屬性/方法|作用|
|---|---|
|size|返回成員數量|
|clear()|清空所有成員,無返回值|
|has(ele)|判斷是否存在指定成員,返回值為 true / false|
|add(ele)|添加元素ele,如果已經存在,沒有變動,否則添加,返回值是實例本身|
|delete(ele)|刪除某個值,返回值為 true / false| 注意:
- Set中的值必須唯一,重復的會自動保留一個。(map鍵、set重復的標準:值類型必須值嚴格相等,引用類型必須引用同一個對象)
- Set沒有數組那種通過索引取值的方法,只能夠遍歷。
流程控制
條件語句
- if、if else、if else if...else
- switch
- 三元表達式
循環語句
- while
- do while
- for
- for in
- for of(es6規范)
- forEach
注意:for in循環遍歷鍵,而for of和forEach會遍歷鍵值。
第三章 函數
函數定義
聲明式定義
function func(){} //在全局中,或函數中的函數,多用此法定義函數標識記法
let func = function(){} //函數當作對象一個屬性時,用詞定義法,如下:let student = {name:zhangsan,study:function(){console.write('study hard!');}}
js中函數也是一種數據(應該屬于六種數據類型的object,雖說typeof為'function',而不是'object'),故命名規則和變量一樣用駝峰,而不是C#中的帕斯卡。
參數
arguments:可以通過索引獲取傳過來的所有參數,類似數組但不是。
function foo(x) {for (let i=0; i<arguments.length; i++) {console.log(arguments[i]);} }rest(ES6規范):獲取多余的參數。
function foo(a, b, ...rest) {console.log('a = ' + a);console.log('b = ' + b);console.log(rest); }foo(1, 2, 3, 4, 5); // 結果: // a = 1 // b = 2 // Array [ 3, 4, 5 ]foo(1); // 結果: // a = 1 // b = undefined // Array []
返回值
- 若函數沒有返回值,默認返回undefined。(new 調用構造函數除外)
內建函數
parseInt()
parseInt('123abc1');//輸出123,遇到第一個字母或其他非法符號截斷 parseInt('FF',16);//輸出255,第二個參數為進制 parseInt('0x377');//輸出887,以0x開頭代表16進制,無需指定進制 parseInt('0377');//輸出377,雖然以0開頭代表八進制,但易與十進制混淆,所以還是當成十進制 parseInt('1.258e2');//125
轉換字符串為整數- parseFloat()
- isNaN()
判斷變量不是數字不能用a!==NaN,因為NaN===NaN返回false,所以只能用isNaN判斷。 isFinite()
isFinite(Infinity);//false isFinite(-Infinity);//false isFinite(1e309);//false,因為超出了js能表示的最大數字
表示是否有限,注意Infinity、-Infinity代表正負無限- encodeURI()
- 存在必要:URL中如/?&等都是關鍵字符,有特殊含義,若需要他們僅僅作為字符出現,則需要'轉義'
- 編碼:一般對中文、空格編碼,保持 ASCII字母、數字、~!*()@#$&=:/,;?+' 不變。
- 使用場景:對整個url編碼,返回一個完整格式的url。
- decodeURI()
對應encodeURL的解碼。 - encodeURIComponent()
- 編碼:保留 ASCII字母、數字、~!*()',其他字符編碼。
- 使用場景:對部分url編碼,如queryString中一項參數的值也是一個url,則為了轉義其中的/?&等關鍵字,需要先用encodeURIComponent編碼,再與整個url拼接起來
- encodeURIComponent()
對應encodeURL的解碼。 - escape()、unescape()
**已棄用,用于字符串的編解碼,多用于將中文轉義成16進制表示 - eval()
- 作用:將一段字符串當作js腳本執行。
- 缺點:
- 安全性差
- 動態執行代碼,效率差
alert()
彈窗,且會阻塞js線程。
變量作用域
- var聲明的作用域為函數體。
- let、const聲明的作用域為大括號。
- 函數內不加var、let、const修飾的作用域為全局。不過,要等到函數被調用后變量才會創建。
- 全局變量也可以通過window.變量名獲取到
變量提升
- 定義:執行過程進入函數時,函數內變量的定義會提升到函數開始處。
- 特點:提升定義,賦值不提升。
例子:
let a = 123; function f(){alert(a);let a = 1;alert(a); } f(); //輸出:先彈出'undefined',再彈出1.解釋:因為函數域始終優先與全局域,所以全局的123沒作用。上面代碼被等價的改寫為下面
let a = 123; function f(){let a; //變量會被提升至此,且js引擎默認初始化為undefinedalert(a);a = 1; //賦值不會提升,只提升了定義alert(a); } f();
匿名函數
- 一般用來執行一次性的函數,如自執行函數或回調函數
- 一般寫成箭頭函數形式()=>{}。(ES6規范)
回調函數
- 函數作為一個參數傳遞個另一個函數,并在后面這個函數中調用。
即時函數(自執行函數)
多用于執行一些一次性的或初始化的任務。
function (name){alert('Hello'+name+'!'); }('dude'); //匿名自執行函數內部(私有)函數
函數內再定義函數。
function outer(param) {function inner(theinput) {return theinput * 2;}return 'The result is ' + inner(param); }函數中this指向的坑
坑1:
let xiaoming = {birth: 1990,age: function () {//根據出生日期獲取xiaoming年齡let y = new Date().getFullYear();return y - this.birth;} };let fn = xiaoming.age;//fn指向了age函數,fn跟xiaoming沒任何關系 fn(); //輸出:Uncaught TypeError: Cannot read property 'birth' of undefined //原因:相當于window調用的fn,age中的this.birth就是window.birth.坑2:
'use strict';let xiaoming = {birth: 1990,age: function () {//根據出生日期獲取xiaoming年齡console.log(this.birth);//這里的this正常的指向xiaoming對象function getAgeFromBirth() {let y = new Date().getFullYear();return y - this.birth;//嵌套函數中的this又指向了window}return getAgeFromBirth();} }; xiaoming.age(); //輸出:Uncaught TypeError: Cannot read property 'birth' of undefined //原因:對象中的嵌套函數(第二層及以上)中的this指向window,只有直接子級函數的this指向該對象本身。解決辦法:
返回函數的函數
function a(){alert('A!');return function(){alert('B!');} } let func = a();//彈出'A' func();//彈出'B' //或者直接如下 a()();//先彈出'A',后彈出'B'能重寫自己的函數
function a() {alert('A!');a = function(){alert('B!');}; }a();//彈出'A!'a();//彈出'B!'應用場景:瀏覽器兼容性探測,初始化時根據瀏覽器類型,重寫某些方法。
閉包
作用域鏈
私有變量可以訪問自身作用域(var為函數,let、const為塊)和其外層作用域,就形成了一條作用域鏈。
寫法
用一個全局變量指向內層的函數,這樣通過這個全局變量就可以訪問內層函數同級的變量,突破了作用域鏈。(看著像從外層訪問里層)
函數所綁定的是作用域本身,而不是在函數定義時該作用域中的變量或變量當前所返回的值。
若需要綁定(非引用類型)變量當前值的快照,則可以通過調用傳參。因為函數傳參是傳的當前值的拷貝。
應用
getter與setter
//變量寫成局部變量,不可直接訪問。通過getter和setter暴露取值和賦值的接口。 let getValue, setValue; (function() {let secret = 0;getValue = function(){return secret;};setValue = function (v) {if (typeof v === "number") {secret = v;}}; }());getValue();//輸出0 setValue(123); getValue();//輸出123 setValue(false);//false驗證失敗,賦值不成功 getValue();//輸出123
通過setter給變量賦值可以加驗證。迭代器
第四章 對象
js中對象與數組的區別
| 數字 | 數組 |
| 字符串 | 對象 |
| 任意類型 | map |
在一些程序語言中,通常會存在兩種不同的數組形式。
js中數組表示索引型數組,對象表示關聯型數組。
對象聲明和訪問
聲明
1.文本標識法
let obj = {breed: 'Turtle',occupation: 'Ninja' };對象的屬性名若不符合變量命名規范,則屬性名需要加引號。
let obj = {'this':'abc','123':123 }2.構造函數
function Hero() {this.occupation = 'Ninja'; } let hero = new Hero();- 構造函數中無需寫return,自動返回this。若顯式return了一個object,則以顯示return的為準。
- 構造函數首字母大寫。
屬性的訪問
1.通過變量名.屬性名訪問
hero.occupation;2.通過變量名[屬性名]訪問
hero['occupation'];此種訪問有兩種使用場景:
屬性的增刪改
增:hero.name = 'zhangsan';
改:hero.name = 'lisi';
刪:delete hero.name;
全局對象
瀏覽器環境中,全局對象為window。
調用全局變量可以 a 或 window.a 或 this.a 。
constructor屬性
指向實例化時所用的構造函數。若用文本標識法創建對象,則它的constructor指向Object()。
h2.constructor; //輸出 //function Hero(name){ // this.name = name; //} let o = {}; o.constructor; //輸出 function Object(){[native code]}instanceof操作符
用于判斷某個對象是否由某個指定的構造器或其父級構造器所創建。
h instanceof Hero;//true h instanceof Object;//true對象作為參數傳遞
- 對象類型的以引用類型傳遞,引用同一份。
- 值類型拷貝一份再傳遞。
比較對象
當且僅當倆引用指向同一對象時,倆對象相等且嚴格相等。
let fido = {breed: 'dog'}; let benji = {breed: 'dog'};fido == benji;//輸出false內建對象
內建對象大致分三類。
Object
Object是所有對象的父級對象。
let o = {}和let o = new Object()等價。
Object含以下三個內建屬性:
Array
數組也是一種對象。
let a = []; typeof a;//Object a instanceof Object;//true相比對象的特殊之處
length屬性
length屬性會隨著數字鍵名的數量而更新,而忽略非數字鍵名屬性。
a[0] = 0;a.prop = 2;//非數字鍵名不會增加lengtha.length;//輸出1a;//輸出[0,prop:2];- 當手動設置length的值大于數組中元素數量時,剩下的部分會被undefined填充。
當手動設置length的值小于數組中的元素數量時,多出的部分元素被移除。
一些內建方法
原素組會改變的方法:
- push————在數組末端添加一個新元素,并返回改變后數組的長度
- pop————移除數組末端的一個元素,返回該元素
- unshift————在數組頭部添加若干元素,返回數組長度
- shift————移除數組頭部的一個元素,返回該移除的元素
- sort————排序,返回排序后的數組。(原數組也會變)
- reverse————數組元素順序翻轉過來
- indexOf————獲取數組中某元素的索引(若為引用類型,必須為同一份引用)
splice————萬能改變數組的方法,截取數組同時填充若干元素,返回截取后的數組。
let a = [1,3,5,7,9]; let b = a.splice(1,2,100,101,102);//第二個參數為截取長度,與slice的第二個參數不同 console.log(a);//[1,100,101,102,7,9] console.log(b);//[3,5]
原數組不受影響,返回一個改變后的數組的方法:
- join————用某個字符串連接數組中的每個元素。(split為把字符串切割成數組)
- slice————截取數組,兩參數為截取起止索引,包括開始,不包括結束索引
- concat————合并兩個數組返回
Function
函數對象的內建屬性:
- constructor————繼承自Object(因為js中函數也是一種對象),其引用Function()這個構造函數
- length————記錄該函數聲明時的參數數量
- prototype
- 每個函數的prototype屬性都指向一個對象
- 只有在函數是構造函數是才發揮作用
- 該函數創建的所有對象都會持有一個該prototype 屬性的引用,并可以將其當做自身的屬性來使用。
call和apply
call和apply可以指定方法的執行上下文,從而可以實現一個對象去"借用"另一個對象的方法為己所用。
例如,arguments對象沒有數組的內建方法,可以像如下方式調用
通過該方法可以實現子類對象中調用父類對象中的方法
例如:Array繼承自Object,Array中重寫了Object中的toString方法,但在Array中想調用Object中的方法時可以Object.prototype.toString.call([])
apply和call的唯一區別是,apply傳參放在一個數組里。
Boolean
作用:
其他幾種基本數據類型也有以上功能
五個基本類型數據都有一個對應的Object類型封裝。
('abcdefg').slice(0,2)會發生裝箱拆箱。
因為slice方法在String類型對象上,所以會先把值類型轉換為引用類型,得到結果后再轉換回值類型。
Number
作用與Boolean相同,但增加了一些屬性和方法。
把Number當成一個對象,該對象里有以下屬性:
- Number.MAX_VALUE————最大值
- Number.MIN_VALUE————最小值
- Number.POSITIVE_INFINITY————正無窮
- Number.NEGATIVE_INFINITY————負無窮
- Number.NaN————NaN
把Number當成構造函數,該構造函數prototype指向對象上有以下方法:
- toFixed————保留小數位
- toPrecision————把數字格式化為指定的長度
- toExponential————轉化位指數寫法
toString————重寫了object的toString,有一個可選的radix參數(默認10)
(255).toString(16);//'ff'
String
- toUpperCase————轉大寫
- toLowerCasse————轉小寫
- charAt————返回指定位置的字符,位置不存在時返回空字符串
- indexOf————返回第一個匹配的位置
- lastIndexOf————返回最后一個匹配的位置
- slice————根據起止索引截取部分字符串,不包括截止索引,若截止索引為負值,則相當于與字符串長度相加后的值
- subString————與slice唯一區別是對截止索引為負值時,subString會當作0處理
- split—————根據所傳遞的分割字符串,將目標字符串分割成一個數組
- concat————連接兩個字符串返回
Math
Math用法與上面不同,不能new。
常用屬性:
- Math.PI————常用數字π
- Math.E————歐拉常數e
- Math.SQRT2————2的平方根
- Math.LN2————2的自然對數
- Math.LN10————10的自然對數
常用方法:
- Math.random————獲取0到1之間的某個數
- Math.floor————向下取整
- Math.ceil————向上取整
- Math.round————四舍五入
- Math.max————獲取最大值
- Math.min————獲取最小值
- Math.pow————指數運算
- Math.sqrt————求平方根
- Math.sin、Math.cos————正弦、余弦
Date
用于創建Date對象的構造器函數,可以傳遞以下幾種參數
- 無參數,默認返回當前時間
- 一個用于表現日期的字符串
- 分開傳遞年、日、月、時間等值
- 一個timestamp值
注意:js中的月份是從0開始,0表示一月,1表示二月...
常用方法
var now = new Date(); now; // Wed Jun 24 2015 19:49:22 GMT+0800 (CST) now.getFullYear(); // 2015, 年份 now.getMonth(); // 5, 月份,注意月份范圍是0~11,5表示六月 now.getDate(); // 24, 表示24號 now.getDay(); // 3, 表示星期三 now.getHours(); // 19, 24小時制 now.getMinutes(); // 49, 分鐘 now.getSeconds(); // 22, 秒 now.getMilliseconds(); // 875, 毫秒數 now.getTime(); // 1435146562875, 以number形式表示的時間戳同時有相應的set方法設置值。
注意:getDay表示獲取星期,getDate才表示獲取日
RegExp
寫法:
組成部分:
修飾符:
- i————ignoreCase,忽略大小寫
- g————global,找出所有的匹配
- m————跨行搜索
RegExp對象的方法:
- test————返回一個布爾值
- exec————返回一個匹配到的數組,若加g修飾符,數組可能會有多個元素,不加則最多只有一個
字符串中使用正則的方法:
- match————返回包含匹配內容的數組
- search————返回第一個匹配內容所在位置
- replace————將匹配的文本替換為指定的字符串
- split————根據指定的正則表達式將字符串分割成若干個數組元素
replace
s.replace(/[A-z]/,'');//返回elloJavaScriptWorld,替換首個大寫字母為空 s.replace(/[A-Z]/g,'');//返回elloavacriptorld,替換所有大寫字母為空 s.replace(/[A-Z]/g,"_$&");//返回_Hello_Java_Script_World,用$&代替所匹配的文本 s.replace(/([A-Z])/g, "_$1");//返回_Hello_Java_Script_World,若正則表達式中分了組(即帶括號),那么可以用$1表示分組中的第一組,$2表示第二組,依此類推注意:replace中第一個參數不是正則而是字符串時,只會替換掉第一個。這是與其他語言不同的。
"pool".replace('o','*');//返回"p*ol" "pool".replace('/o/g','*');//返回"p**l"回調式替換
function replaceCallback(match){return ""+match.toLowerCase(); }s.replace(/[A-Z]/g,replaceCallback);//輸出_hello_java_script_world該回調函數接受一系列參數(以上示例僅用到了第一個參數)
- 首參數是所匹配的內容
- 尾參數是被搜索的字符串
- 倒數第二個參數是匹配內容所在位置
- 剩下的參數是分組所匹配的字符串
Error對象
包括一些派生的ReferenceError、RangeError、EvalError、SyntaxError、TypeError、URIError。
Error類對象都有兩個屬性:
- name————構造當前Error對象的構造器名稱
- message————出錯的詳細信息描述
IE瀏覽器跟Chrome、FireFox拋出異常的name和message不同,可以自定義拋出一個匿名對象。
throw {name: "MyError",message: "OMG! Something terrible has happened" }第五章 原型
js中的繼承就是基于原型的。
原型屬性
函數也是對象,每個函數上都有一個prototype屬性。
function foo(a,b){return a*b; }typeof foo.prototype;//輸出"object"函數的原型屬性只有在函數當作構造函數使用(即使用new調用)時才起作用。
原型對象上的屬性和方法
- 原型對象上的屬性和方法無論實例化多少個對象都只存在一份。
- 如果實例屬性名和原型對象上的屬性名相同(或方法名相同,因為js中不存在方法重載),則實例屬性優先級高。
- 原型對象上的方法也可以通過this.屬性名訪問實例屬性值和原型對象上的屬性。
原型鏈
每個對象都會有一個構造器,而原型本身也是一個對象,這意味著它必然也有一個構造器,而這個構造器又會有自己的原型。于是這種結構可能會一直不斷地持續下去,并最終形成原型鏈。
枚舉屬性
- 內建對象.propertyIsEnumerable('屬性名||方法名||原型鏈上的屬性名||原型鏈上的方法名')返回false。
- 對象.propertyIsEnumerable('原型鏈上的屬性名||原型鏈上的方法名')返回false。
- for in 會例舉出實例對象和其原型鏈上的屬性或方法。但不會例舉內建對象的原型屬性。如Object的原型對象的屬性和方法。
isPrototypeOf()
判斷一個對象是否是另一個對象的原型對象
let monkey = {hair:true,feeds:'bananas',breathes:'air' };function Human(name){this.name = name; } Human.prototype = monkey;let george = new Human('George'); monkey.isPrototypeOf(george);//返回true獲取一個對象的原型對象
Object.getPrototypeOf(george);//返回monkey對象 george.constructor.prototype;//這樣也可以獲取__proto__
生成一個對象時,js引擎自動在對象上加了一個__proto__屬性,指向該對象的原型對象。然后原型對象也是對象,也有一個__proto__屬性指向一個原型對象...如此下去,便形成了一條原型鏈。
__proto__只能在學習或調試環境下使用
注意:以上為對象層面的原型鏈。new一個對象時,js引擎把構造函數、原型對象層面的鏈狀關系轉化為對象層面的原型鏈。構造原型對象和構造函數之間的鏈狀關系才是我們所需編寫的代碼。
原型作用
原型陷阱
- 對原型對象執行完全替換時,可能會出發原型鏈中的某種異常。
- 在對象生成后才完全替換原型對象。
此種情況下,先前生成的對象的__proto__還是鏈接著原先的原型對象。 - 完全替換原型對象后生成對象。
此種情況下,__proto__鏈接著被替換掉的原型對象。 - prototype.constructor屬性是不可靠的。
最佳實踐:當我們重寫對象的prototype時,需要重置相應的constructor屬性。
第六章 繼承
js引擎所做的:查找對象屬性時,先在對象自身屬性中查找,再沿著__proto__鏈著的對象上查找。
我們所需做的:通過構造函數和原型對象構建鏈接關系。(new一個對象時,js引擎把轉化為通過__proto__把對象之間連接起來)
實現方法1
Child.prototype = new Parent(); Child.prototype.constructor = Child;//重置原型對象上的constructor屬性,不然就指向了Parent缺點:該方法不僅繼承了父類的實例屬性,還繼承了父類的原型屬性
實現方法2
function extend(Child,Parent){let F = function(){};F.prototype = Parent.prototype;Child.prototype = new F();Child.prototype.constructor = Child; }該方法只會繼承父類的原型屬性,不會繼承父類的實例屬性。
ES6中繼承寫法
ES6中引入了class關鍵字,但并非js中有了類,只是一個實現繼承的語法糖,實際還是通過原型實現繼承。
class Student {constructor(name) {this.name = name;//實例屬性、方法放在constructor中}hello() { //原型屬性、方法放在外面alert('Hello, ' + this.name + '!');} }class PrimaryStudent extends Student { //extends關鍵字代表繼承自誰constructor(name, grade) {super(name); // 記得用super調用父類的構造方法!this.grade = grade;}myGrade() {alert('I am at grade ' + this.grade);} }第七章 瀏覽器環境
運行javascript代碼需要宿主環境,一般是瀏覽器環境。
BOM(瀏覽器對象模型)
BOM(瀏覽器對象模型)是一個用于訪問瀏覽器和計算機屏幕的對象集合。可以通過window訪問這些對象。
window對象
window對象是瀏覽器中的全局對象,所有的全局變量和函數都可以通過window對象的屬性訪問。
window.navigator
navigator是一個反應瀏覽器及其功能信息的對象。如navigator.userAgent可以識別不同的瀏覽器。
window.location
location是一個用于存儲當前載入頁面url信息的對象。
屬性:
//若果當前頁面的url為http://search.phpied.com:8080/search?p=java&what=script#resultsfor(var i in location) {if(typeof location[i] === “string”) {console.log(i + ' = "' + location[i] + '"');} } //輸出: //href = "http://search.phpied.com:8080/search?q=java&what=script#results" //hash = "#results" //host = "search.phpied.com:8080" //hostname = "search.phpied.com" //pathname = "/search" //port = "8080" //protocol = "http:" //search = "?q=java&what=script"注:location的href中除了hash變化不會引起向服務端發起請求外,其他部分變化都會重新向服務端發起請求。
方法:
- reload()————重新加載當前頁面
- assign()————導航到其他頁面
- replace()————也是導航到其他頁面,但是不會在瀏覽器的歷史記錄表中留下記錄
window.history
window.histoty屬性允許我們以有限的權限操作同一個瀏覽器會話中的已訪問頁面。
- history.length————查看用戶在這之前訪問了多少頁面
- histoty.forward()————前進
- history.back()————后退
- history.go(-1)————后退一步,同理可以傳其他正、負、0數,實現前進、后退、重載當前頁面
H5中history的API
作用:讓無跳轉的單站點也可以將它的各個狀態保存為瀏覽器的多條歷史記錄。當通過歷史記錄重新加載站點時,站點可以直接加載到對應的狀態。
API:
- history.pushState()
完整是history.pushState(stateObject, title, url),包括三個參數。
第一個為狀態參數,存放需要記錄的狀態;第二個是標題,目前瀏覽器忽略它,傳空字符串;第三個為當前狀態對應的url地址。 - history.repalceState()
與pushState唯一區別是不會新生成歷史記錄,而是將當前歷史記錄替換掉。 window.onpopstate
//假如當前網頁地址為http://example.com/example.html,則運行下述代碼后: window.onpopstate = function(event) {alert("location: " + document.location + ", state: " + JSON.stringify(event.state)); }; //綁定事件處理函數 history.pushState({page: 1}, "title 1", "?page=1"); //添加并激活一個歷史記錄條目 http://example.com/example.html?page=1,條目索引為1 history.pushState({page: 2}, "title 2", "?page=2"); //添加并激活一個歷史記錄條目 http://example.com/example.html?page=2,條目索引為2 history.replaceState({page: 3}, "title 3", "?page=3"); //修改當前激活的歷史記錄條目 http://ex..?page=2 變為 http://ex..?page=3,條目索引為3 history.back(); // 彈出 "location: http://example.com/example.html?page=1, state: {"page":1}" history.back(); // 彈出 "location: http://example.com/example.html, state: null history.go(2); // 彈出 "location: http://example.com/example.html?page=3, state: {"page":3}
頁面前進后退時,若當前url有對應的stateObject則觸發事件,并在參數中包含stateObject。
window.frames
window.frames屬性是當前頁面中所有框架的集合。
frames中的每個元素都包含了一個頁面,都有各自的window全局對象。
window.screen
screen所提供的是瀏覽器以外的環境信息。
- screen.colorDepth————當前顯示器的色位
- screen.width————屏幕寬
- screen.height————屏幕高
- screen.availWith————屏幕可用寬(與width不同之處是availWith不包括任務欄)
- screen.availHeight————屏幕可用高(不包括任務欄)
window.open/window.close
打開窗口、關閉窗口
window.moveTo()、window.moveBy()、window.resizeTo()、window.resizeBy()
注:Chrome、edge中測試均無反應,已廢棄。
window.alert()、window.confirm()、window.prompt()
- window.alert()————彈出提示框
- window.confirm()————彈出確定框,可以選擇確定或取消,相應返回true或false
- window.prompt()————彈出帶輸入框的窗口,輸入后點確定,返回所輸入的文本
window.setTimeout()、window.setInterval()
setTimeout:在一定時間后執行
function boo(){console.log('boo!'); }let id = setTimeout(boo,2000);//2秒后執行boo方法 clearTimeout(id);//根據id取消計時器setInterval:每隔多少毫秒執行一次
let id = setInterval(boo,2000);//每隔2秒執行一次 clearInterval(id);//根據id取消計時器window.document
DOM(文檔對象模型)
DOM是一種將XML或HTML文檔解析成樹形節點的方法。通過DOM的方法與屬性,我們可以訪問到頁面中的任何元素,并進行元素的修改刪除及添加操作。
基于DOM Level1用于解析所有XML文檔的那部分稱為Core DOM,在Core DOM上進行擴展的那部分稱為HTML DOM。
DOM節點的訪問
方法一 索引訪問法
- nodeType————節點類型,常用的1(元素)、2(屬性)、3(文本)...
- nodeName————節點名稱,對HTML標簽來說,一般就是標簽名(即tagName屬性),對文本則是#text
- nodeValue————節點值,對文本節點來說,值就是實際文本。
document表示當前所訪問的文檔。
document.documentElement表示document上的HTML節點。
document.documentElement(即HTML節點)有三個,即head元素、body元素,以及兩者之間的空白(空白默認為文本節點)。
- 節點相關:
- hasChildNodes()————判斷某節點是否包含子節點
- childNodes————NodeList類型的子節點集合,通過索引可以訪問到子節點
- parentNode————某節點的父節點
- 屬性相關:
- hasAttributes()————檢查元素是否存在屬性
- attributes————屬性集合,通過索引訪問
- getAttribute()————獲取對應屬性名的值
- 直接在節點后面.屬性名,如節點對象.id訪問id屬性的值,節點對象.className訪問class屬性的值
- 節點中的內容相關:
- textContent————節點中的文本
- innerHTML————節點中的html的字符串
若一段HTML結構如下:
<html><head></head><!--這中間雖然什么都沒有,但其實還是有一個text節點--><body><p class="opener">first paragraph</p><p><em>second</em> paragraph</p><p id="closer">final</p><!-- and that's about it --></body> </html> document.documentElement.childNodes[1];//#text,因為head和body之間存在一個空白,該空白為text節點 document.documentElement.childNodes[1].parentNode;//<html>...</html> let bd = document.documentElement.childNodes[2]; bd.childNodes.length;//9,因為四個節點(包括注釋)之間、子節點和父節點之間一共存在5個空白的text節點,所以一共9個節點bd.childNodes[1].hasAttributes();//true,第一個標簽有個class屬性。注意索引0是空白text,索引1才是p標簽 bd.childNodes[1].attributes.length;//1 bd.childNodes[1].attributes[0].nodeName;//'class' bd.childNodes[1].attributes[0].nodeValue;//'opener' bd.childNodes[1].attributes['class'].nodeValue;//'opener' bd.childNodes[1].getAttribute('class');//'opener' bd.childNodes[1].className;//'opener' bd.childNodes[1].nodeName;//'p' bd.childNodes[1].textContent;//'first paragraph' bd.childNodes[1].innerHTML;//'first paragraph' bd.childNodes[3].textContent;//'second paragraph' bd.childNodes[3].innerHTML;//'<em>second</em> paragraph' bd.childNodes[1].childNodes[0].nodeValue;//'first paragraph'方法二 快捷訪問法
索引法的問題:
- 訪問的節點層次很深時,需要寫很長的代碼
- 節點之間存在空白text節點,導致計算索引很麻煩
快捷方法:
- getElement系列:
- getElementsByTagName()————以標簽名為參數,返回當前html頁面中所有匹配該標簽名的元素集合
- getElementsByClassName()————以類名為參數,返回所有該類名的元素集合
- getElementById()————以id為參數返回一個element
- getElementsByName()————以name屬性為參數,返回所有該name屬性的元素集合
- querySelector系列
- querySlector()————通過css選擇器返回第一個元素
- querySelectorAll————通過css先選擇器返回所有元素
注:getElement系列除了getElementById返回一個Element外,其他都返回一個HTMLCollection集合,HTMLCollection是動態的,會隨著文檔樹的變化動態更新。
querySelector系列返回一個NodeList,NodeList是靜態的,獲取后,文檔樹變化不會影響NodeList.
body雖然說嵌套在html標簽里,但document.body就可以訪問到body,而不用document.documentElement.body。
- nextSibling————下一個相鄰節點
- previousSibling————上一個相鄰節點
- firstChild————第一個子節點,一般為空白text
- lastChild————最后一個子節點,一般為空白text
DOM節點的修改
- innerHTML————修改元素里的HTML
- nodeValue————修改元素的內容,text類型元素則為文本值
- style————修改元素的樣式
DOM節點的新建
- createElement()————新建元素
- createTextNode()————新建文本節點
- cloneNode()————拷貝節點,參數傳false則為淺拷貝,傳true則為深拷貝
- appendChild()————添加到最后
- insertBefore()————插入到某元素前面
- replaceChild()————替換某元素
注意:后三個方法調用方是父容器節點。
let p = document.createElement('p'); p.innerHTML = '<em>yet</em> another'; p.style.border = '2px dotted blue'; document.body.appendChild(p); let list=document.getElementById("myList") list.insertBefore(p,list.childNodes[0]);//第一個參數為新節點,第二個參數為插入誰的前面item.replaceChild(p,list.childNodes[0]);//第一個參數為替換者,第二個為被替換者document.body.appendChild(p.cloneNode(false));//將只會拷貝一個p標簽,相當于document.body.appendChild(document.createElement('p')); document.body.appendChild(p.cloneNode(true));//p及p標簽里的子元素都將拷貝DOM節點的移除
- removeChild()————移除節點
- replaceChild()————替換節點
- innerHTML='' ————把innerHTML置為空字符串
只適用于HTML的DOM對象
以上總結的都是屬于DOM Level 0(或叫Core DOM),既適用于XML又適用于HTML。以下的只適用于HTML。
- document.body————HTML中的body元素
- document.images————當前頁中所有圖片的集合,等價于Core DOM中的document.getElementsByTagName('img')
- document.links————包含所有<a href='...'/>的集合
- document.anchors—————包含所有<a name='...'>的集合
document.forms————包含所有表單的集合
document.write()————在頁面載入時插入一些HTML元素,當載入完成后調用則會覆蓋整個HTML。一般沒什么用。
- document.cookie————獲取或設置cookie
- document.title————獲取或設置title
- document.referrer————記錄前面訪問的頁面的URL,同HTTP 頭信息中的Referer
- document.domain————獲取或設置當前域名,注意設置只能比真實域名更簡短,如www.yahoo.com改為yahoo.com
document.location————同window.location
事件
注冊事件三種方式
1.內聯HTML屬性法
<div onclick="alert('Ouch!')">click me</div>缺點:Javascript代碼和HTML耦合在一起。
2.元素屬性法
<div id="my-div">click</div> let myelement = document.getElementById('my-div'); myelement.onclick = function() { alert('Ouch!'); }缺點:只能指定一個事件函數。
3.事件監聽器法
<p id="closer">final</p> let mypara = document.getElementById('closer'); mypara.addEventListener('click', function(){alert('Boo!')}, false); mypara.addEventListener('click', console.log.bind(console), false);移除某個監聽器:
function func(){alert('Woo'); } mypara.addEventListener('click', func, false); mypara.removeEventListener('click', func, false);注意:移除某個監聽器時,傳遞的方法參數必須是同一個方法的引用,即使寫一個完全相同的方法爺不行。故需要移除的監聽器在注冊時不能用匿名方法。
捕捉法和冒泡法
addEventListner方法的第三個參數,當置為true時為捕捉法,默認為false即冒泡法。
<body><ul><li><a href="http://phpied.com">my blog</a></li></ul> </body>單擊鏈接
- 事件捕捉————單機首先發生在document上,然后依次傳遞給body、列表、列表項,并最終到達該鏈接,稱為捕捉法。
- 事件冒泡————單機首先發生在鏈接上,然后逐層向上冒泡,直到document對象,稱為冒泡法
按照DOM2的規定,事件傳播分三階段:先捕捉標簽,然后到達標簽,再冒泡。
阻斷冒泡
在最里層的處理器中加e.stopPropagation(),就不會觸發上層父容器的事件。
function paraHandler(e){ alert('clicked paragraph'); e.stopPropagation(); }防止默認行為
在瀏覽器中某些元素的事件有一些預定義行為,例如,單機鏈接會載入另一個頁面。可以在事件處理器中加e.preventDefault()來阻斷默認行為。
// 在點擊所有鏈接前詢問是否導航至目標鏈接,若選擇否,則不導航 let all_links = document.getElementsByTagName('a'); for (let i = 0; i < all_links.length; i++) {all_links[i].addEventListener('click',function(e){if (!confirm('Are you sure you want to follow this link?')){e.preventDefault();}},false // don't use capturing); }事件類型
- 鼠標類事件
- 鼠標鍵的按下、松開、單擊、雙擊
- 鼠標的懸停、移出、拖動
- 鍵盤類事件
- 鍵盤鍵的按下、輸入、松開
- 載入/窗口類事件
- 載入(圖片、頁面或其他組件完成載入操作)、卸載(指用戶離開當前頁面)、卸載之前(由腳本提供的、允許用戶終止卸載的選項)
- 中止(指用戶在IE 中停止頁面或圖片載入)、錯誤(指在IE 發生了JavaScript錯誤或圖片載入失敗)。
- 調整大小(指瀏覽器窗口大小被重置)、滾動(指頁面進行了滾動操作)、上下文菜單(即右鍵菜單出現)。
- 表單類事件
- 獲得焦點(指某字段獲得輸入)、失去焦點(指離開該字段)。
- 改變(指改變某字段的值后離開)、選中(指某文本字段中的文本被選中)。
- 重置(指擦除用戶輸入的所有信息)、提交(指發送表單)。
現代瀏覽器還有dragstart、dragend、drop事件,觸控設備還有touchstart、touchmove、touchend事件。
XMLHttpRequest對象
let xhr = new XMLHttpRequest(); xhr.onreadystatechange = myCallback; xhr.open('GET','somefile.text',true); xhr.send('');//若要攜帶參數則以格式'key=value&key2=value2'fuction myCallback(){if(xhr.readyState<4){return;}if(xhr.status!==200){alert('Error!');return;}alert(xhr.responseText); }轉載于:https://www.cnblogs.com/victor-leeson/p/10963802.html
總結
以上是生活随笔為你收集整理的《javascript面向对象编程指南》读书笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 女程序员做了个梦。。。
- 下一篇: Spring Boot 2.3.3 稳定