文章目錄
- 一、原型繼承
- 二、Class關鍵字
- 1.ES6之前
- 2.ES6後
- 3.補充
- 三、Map和Set
- 四、Iterator(疊代器)
- 1.周遊數組
- 2.周遊Map
- 3.周遊Set
- 五、JS中不完善的報錯+手動改進(throw+【argument】+補充:【...rest】)
- 1.函數參數中報錯不完善
- 2.var局部作用域中的bug
- 六、使JS的原生方法失效+恢複
- 七、多個js檔案全局周遊沖突問題
- 八、方法與函數
一、原型繼承
執行個體中,tom本身沒有run方法,無法調用run
但如果想調用,則可讓tom的原型對象指向Student,這樣,tom對象在調用run方法時,在本對象中查不到run方法時,則會去tom對象的__proto__屬性中去查找run方法,也就是先在tom對象的原型鍊上查找緊鄰上一個原型對象中的方法
當然,要注意的是,将tom的原型指向Student時,Student的原型也會連接配接過來
每個對象和原型都有原型,對象的原型指向原型對象,而父的原型又指向父的父,這種原型層層連接配接起來的就構成了原型鍊。
作為一個對象,當你通路其中的一個屬性或方法的時候,如果這個對象中沒有這個方法或屬性,那麼JavaScript引擎将會通路這個對象的__proto__屬性所指向的上一個對象,并在那個對象中查找指定的方法或屬性,如果不能找到,那就會繼續通過那個對象 的__proto__屬性指向的對象進行向上查找,直到這個連結清單結束
二、Class關鍵字
1.ES6之前
在ES6之前,隻能這樣定義類
<script>
"use strict";
function Student(name) {
this.name = name;
}
//給Student類新增一個方法,上面的Student(name)為構造函數
//給類增加方法,是以需指向Student(name)函數的原型對象
Student.prototype.hello = function () {
console.log('Hello ' + this.name);
}
</script>
引入一張圖
2.ES6後
在ES6時,引入了Class關鍵字,使得此操作更加友善、合理和規範
<script>
"use strict";
class Student {
constructor(name) {
this.name = name;
}
hello() {
console.log('Hello ' + this.name)
}
}
</script>
繼承用關鍵字extends
<script>
"use strict";
class Student {
constructor(name) {
this.name = name;
}
hello() {
console.log('Hello ' + this.name)
}
}
class PrimaryStudent extends Student {
constructor(name, grade) {
super(name);
this.grade = grade;
}
say() {
console.log('I‘m a primary student');
}
}
</script>
如圖,extends本質也是原型鍊的思想
(注:下圖Object原型後面還有連接配接的原型)
3.補充
(1)得到原型類:
方法一:對象執行個體名._proto_
方法二:類名.prototype
三、Map和Set
二者為ES6的新增資料類型。
Map:(鍵值對)
常用方法:
- set(‘key’, value):添加某個值。
- delete(value):删除某個值。
- get(‘key’):得到此鍵的某個值
Set:(去重的無序集合)
常用方法:
- add(value):添加某個值。
- delete(value):删除某個值。
- has(value):某值是否在集合内。
- clear():清除集合中所有元素。
四、Iterator(疊代器)
為ES6新特性。
1.周遊數組
普通的周遊方法如下:
for in:周遊下标
for of:周遊值
2.周遊Map
for of:周遊鍵+值
3.周遊Set
for of:周遊值
五、JS中不完善的報錯+手動改進(throw+【argument】+補充:【…rest】)
1.函數參數中報錯不完善
例子:
<script>
"use strict";
function abs(x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
函數傳遞多個參數,或不傳遞參數,或是傳遞另一種類型的參數,都不會報錯,最多是NaN值,進而可能導緻間接報錯,但不會出現直接報錯
加一段判斷參數類型的語句,來手動抛出異常(但也隻能解決隻傳一個參數時的類型問題)
<script>
"use strict";
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a Number~';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
由于可利用JS的關鍵字arguments來接收多個函數參數,否則,若函數隻定義了一個參數,則其它傳入的參數(從第二個參數往後的所有參數),都不會參與到函數中,但卻保留在arguments中
<script>
"use strict";
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a Number~';
}
console.log('x=>' + x);
console.log('argument周遊');
for (let i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
是以,再次改進代碼,即可寫出一個報錯完整的函數
<script>
"use strict";
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a Number~';
}
if (arguments.length > 1) {
throw 'Please Input one arg~'
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
</script>
補充:另外,還有一個…rest(ES6新增),寫在函數定義的參數清單最後面,用于接收除已定義參數外的額外傳入的參數
<script>
"use strict";
function talk(x, ...rest) {
let i;
for (i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
console.log('-----------------------')
console.log(rest);
}
</script>
2.var局部作用域中的bug
<script>
"use strict";
for (var i = 0; i < 2; i++) {
console.log('in: ' + i);
}
//仍然可以輸出i
console.log('out: ' + i);
</script>
改進:将var改為let
<script>
"use strict";
for (let i = 0; i < 2; i++) {
console.log('in: ' + i);
}
//不可以輸出i
console.log('out: ' + i);
</script>
六、使JS的原生方法失效+恢複
預先記錄原方法引用,随後消除原方法:
<script>
"use strict";
let x = 'xxx';
var old_alert = window.alert;
window.alert = function (){
}
window.alert(123);
window.old_alert('old: ' + x);
</script>
當然,也可以設定恢複
<script>
"use strict";
let x = 'xxx';
var old_alert = window.alert;
window.alert = function (){
}
window.alert(123);
// window.old_alert('old: ' + x);
//恢複
window.alert = old_alert;
window.old_alert('re-old: ' + x);
</script>
七、多個js檔案全局周遊沖突問題
問題:由于我們所有的全局變量都會綁定到window對象上,是以,如果使用不同的js檔案,遇到相同名字的全局變量時,就會産生沖突。
解決方法:在每個js中都自定義一個唯一的全局變量對象,将這個腳本檔案中的所有全局變量都賦予該全局變量對象,進而降低全局命名沖突的問題。(JQuery也參考了這個思想)
例如:
<script>
"use strict";
//唯一全局變量
var appT = {};
appT.name = 'zlc';
appT.add = function(x, y) {
return x + y;
}
//使用時
console.log(window.appT.add(1, 2));
</script>
八、方法與函數
(在講述的時候需格外注意,不要将方法說成函數)
方法:
或是這樣的形式
方法調用:obj.method(),需要加括号
函數:
用函數的apply方法調用函數:格式:函數名.apply(對象, 參數清單);
普通函數調用和apply函數調用,結果相同
直接調用getAge()函數将會報錯