js高級

js面向對象編程

面向對象介紹

什麼是對象

  1. 是單個事物的抽象
  2. 對象是個容器, 封裝了屬性和方法
  3. 數據集或功能集
  4. ECMAScript-262把對象定義爲:無序屬性的集合, 其屬性可以包含基本值/對象或者函數
  5. 對象的屬性和方法, 叫做成員
  6. 對象的每個屬性或方法都有一個名字, 而每個名字都映射到一個值

什麼是面向對象

  1. 特點: 封裝/繼承/多態(抽象)
    封裝性: 對象是將數據與功能組合到一起, 即封裝
    繼承性: 自己沒有, 別人有, 拿過來爲自己所用, 併成爲自己的東西
    多態性:

  2. 有點: 靈活/可複用/高度模塊化

程序中面向對象的基本體現

創建對象

// 1. 字面量
var obj = {
	name: 'zs',
	age: 18
}
// 2. 使用object對象創建對象, Object對象是所有對象的祖宗, 函數也是對象
var obj = new Object(); 
// 3. 自定義構造函數
function Person(name, age) {
	this.name = name,
	this.age = age
}
var zs = new Person('zs', 18);
new 做的事情分爲四個步驟
1. new 在內存中開闢一片空間, 創建了一個新的對象
2. this 指向了這個新創建出來的對象
3. 讓構造函數執行
4. 返回新創建出來的那個對象

// 4. 工廠函數
function createPerson(name, age) {
	return {
		name:name,
		age: age
	}
}

簡單方式

簡單方式的改進: 工廠函數

更優雅的方式: 構造函數

構造函數的問題

原型

更好的解決方案: prototype

構造函數/實例/原型三者之間的關係

  1. 每一個構造函數, 在加載到內存的時候, 瀏覽器會幫助我們自動創建一個對象, 這個對象我們稱之爲構造函數的原型對象, 簡稱原型
  2. 我們通過構造函數的prototype屬性可以訪問到自己的原型對象
  3. 原型對象身上有一個constructor屬性, 可以訪問到自己對應的構造函數
  4. 構造函數的實例, 可以調用原型對象上的屬性, 如果構造函數裏也有這個屬性, 那麼會執行構造函數上的, 如果構造函數沒有這個屬性, 才執行原型對象上的

屬性成員的搜索原則: 原型鏈

實例對象讀寫原型對象成員

更簡單的原型語法

原生對象的原型

原型對象使用建議

函數進階

函數的定義方式

函數聲明

函數表達式

函數聲明與函數表達式的區別

函數的調用方式

函數內this指向的不同場景

函數也是對象

call/apply/bind

call

apply

bind

小結

函數的其他成員

函數的靜態成員和實例成員

高階函數

作爲參數

作爲返回值

函數閉包

作用域/作用域鏈/預解析

什麼是閉包

閉包的思考題

正則表達式

正則表達式簡介

什麼是正則表達式

正則表達式的作用

正則表達式的特點

正則表達式的測試

正則表達式的組成

元字符串

常用元字符串

限定符

其他

案例

js中使用正則表達式

創建正則對象

參數

正則匹配

正則提取

正則替換

案例:表單驗證

實現繼承的方式

var base = {
	name:'',
	age: '',
	sayHello() {
		console.log('hello');
	}
}

// 1. 混入式繼承(用的極少)
var obj = {};
for(var k in base) {
	obj[k] = base[k];
}

// 2. 原型繼承(用的比較多)
function Person() {
}
Person.prototype = base;
var p = new Person();

function Student() {
}
Student.prototype = Person.prototype;

// 3. 經典繼承 Object.create
// 下面的代碼的作用
// 1. 創建一個新對象obj1
// 2. 把obj1的原型(__proto__)設置爲base
// 傳進去的base就是我們要繼承的對象, obj1對象的原型上面, 就是base上面的成員
var obj1 = Object.create(base);
console.log(obj1);

// 4. 借用構造函數繼承(call apply)(繼承的是屬性, 無法繼承到原型上的方法)
function Person() {
	this.name = "";
	this.age = ""
}
function Student() {
	Person.call(this);
}
var stu = new Student();
console.log(stu);

// 5. 組合式繼承 = 原型繼承 + 借用構造函數繼承
function Person() {
	this.name = '喵喵';
    this.age = '';
    this.play = [1,2,3];
}
Person.prototype.sayHello = function () {
    console.log('我最棒, 真的');    
}
function Student() {
    this.color = 'yellow';
    Person.call(this);
}
Student.prototype = new Person();
var p = new Person();
var s = new Student();
var h = new Student();
s.play.push(4); //  如果不加構造函數繼承的話, 這裏的改變, 也會改變其他實例上的這個數組, 這就改的太喪心病狂了. 加了以後, 就可以隨便改了, 怎麼改都是改自己實例, 而不會連其他實例的都一起改變
s.color = 'ss';
console.log(p);
console.log(s);
console.log(h);
h.sayHello();

// 6. es6實現繼承的方法
class Person{
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}
	sayHello() {
		console.log('hello');
	}
	static sayHi() {
		console.log('hi');
	}
}
// extends 關鍵字使用的其實就是 組合式繼承
class Student extends Person{
	constructor() {
		// 在子類構造函數中, 第一步事情, 調用父類的構造函數
		super(); // 相當於es5的Person.call(this); 不寫會報錯
		this.stuNo = 10000;
	}
}
let stu = new Student('喵喵', 0.67);
console.log(stu.stuNo);
stu.sayHello();
Student.sayHi(); // Person的靜態成員也被繼承了


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章