面向物件基礎知識概括
=============資料屬性和訪問器屬性
資料屬性 和 訪問器屬性
get 獲取 Own 自己的property 屬性 Descriptor 描述符
value:zhangsan //該key對應的值
writable : true //可修改
enumerable: true //可列舉性 是否可被遍歷
configurable:true //可配置性 能否被刪除
預設都是可修改,可被遍歷到,可被刪除
define 定義 property 屬性
Object.definProperty(obj,key,Descriptor);預設不可被修改,遍歷,刪除
const obj = { name : "zhangsan", age : 18 } Object.defineProperty(obj,'age',{ value : 18, writable:true, // 預設為false 是否可修改 enumerable : false, // 預設為false 是否可遍歷 configurable: true //預設為false 是否可刪除 }) obj.age = 20; for(let key in obj){ console.log(key) //name,age } console.log(obj); delete obj.age; console.log(obj) //{name: "zhangsan"}
存取描述符
兩個方法 get() set()
存取描述符不可與資料描述符同時存在,即get set 不可與 value writable 同時存在
案例:輸入屬性值,進行判斷
const obj = { name : "zhangsan", // 如果這裡沒加下劃線,那麼下面get訪問也不用加 // _age : 38, _score: 60 } Object.defineProperty(obj,'score',{ //這裡的引數score必須對應下面的set,包括下劃線 // value : 18, // writable:false, // 預設為false 是否可修改 enumerable : false, // 預設為false 是否可遍歷 configurable: false, //預設為false 是否可刪除 get() { //訪問物件屬性時自動被呼叫 return this._score; //獲取obj.score的值 }, //輸入的值 set(value){ //設定物件屬性時自動被呼叫 //判斷值 if(value < 0 || value > 100){ console.log("請輸入正確分數"); }else{ this._score = value; //輸入的值賦值給obj.score (注:這裡不能使用下劃線) console.log("錄入成功"); return value;// 返回輸入的值 } } })
===========面向物件
面向物件程式設計,一種程式設計正規化(程式設計風格,程式設計方式)。
將現實問題構建關係,抽象成類,為類定義屬性,方法。再將類【例項化】成【例項】,訪問例項屬性,呼叫例項方法進行使用。
例項化:新增 新建 建立
例如:張三想要個女兒,生的那個女兒就是例項。
Arr let arr = new Array();
程式設計正規化
1.宣告式程式設計 HTML,CSS告訴計算機需要XX
2.指令式程式設計 每一步都需要告訴計算機(比如宣告一個變數),強調了做事的步驟
1.面向過程 分析出解決問題的每一步,逐步實現
2.面向物件 把構成問題的事物分解成各個物件,讓具體物件去實現相應事情
ATM
類
種類,模板,模具
數量龐大就可以用類區分,歸納
類屬於物件,物件有這些類
類是物件的一種抽象概括,物件是類的具體實現,類是模板,用於生成多個例項。
封裝:封裝,繼承,多型
封裝:資訊隱藏,把實現功能的方法包裝起來。函式是對於演算法的封裝,類是對於屬性和方法的封裝
函式的三要素,隨機數函式, 餐館吃飯(只關心菜品,不用關心廚師如何做出來)。
繼承:子類可以繼承父類的所有屬性和方法,還可以擴充套件自己的屬性和方法。
=========封裝
1.物件的方式表現出來,看不出例項和類的關聯
把屬性和方法組成類的過程就叫做封裝
//cat 想要表示貓的類 const cat = { //cat的屬性 name : '', age : '', gender : '', color : '' }; const cat1 ={ name : 'xiaohei', age : '1', gender : 'male', color : 'block' } const cat1 ={ name : 'xiaohuang', age : '2', gender : 'female', color : 'yellow' }
2.ES6 class 宣告類
關鍵字class
//此處的Dog實際是一個建構函式 class Dog { constructor(name,age,gender){ this.name = name; this.age = age; this.gender = gender; } } let xiaohei = new Dog('xiaohei',2,'male'); //xiaohei例項化出來的具體某個物件 console.log(xiaohei); //案例:我叫張三,我的小狗叫小黑 class Person{ constructor(name){ this.name = name; console.log(this);// Person{name: "張三"} } talk(){ console.log(
我叫${this.name},我的小狗叫${xiaohei.name}); } } let zhangsan = new Person("張三") zhangsan.talk(); // 我叫張三,我的小狗叫xiaohei
==========工廠模式
` //工廠模式
function CatFactory(name,age,gender){
return {
name : name,
age : age,
gender : gender
}
}
let cat_obj = CatFactory('xiaohuang','1','female');
console.log(cat_obj);
function Dogfactory(name,age,gender,type){
return {
name,
age,
gender,
type
}
}
let dog1_obj = Dogfactory('小白',2,'female','金毛'),
dog2_obj = Dogfactory('小黃',3,'male','拉布拉多');
console.log(dog1_obj,dog2_obj);`
========混合模式(建構函式+原型prototype)
將例項物件共享的方法,放在類原型上,實現方法共享,節省記憶體
function Cat(name,age,gender){ //用this,不能用return this.name = name; this.age = age; this.gender = gender; } Cat.prototype.eat = function(){ console.log('餓了,乾飯去'); } let Cat1 = new Cat('xiaohuang',2,'female'), Cat2 = new Cat('xiaobai',2,'male'); Cat1.eat(); Cat2.eat();
======靜態方法(工具型) 例項方法
let arr = new Array(); arr.push(); //得到例項物件後通過例項物件去呼叫的方法,屬性 Math.random(); Json.parse() //直接在類,建構函式身上使用的
======使用new關鍵字在內部經歷的四個步驟
1.建立了一個該型別的空物件, 就像是 let _obj = {};
2.將這個新物件的_proto_(隱式原型)指向了類(建構函式)的prototype(原型)就像是 cat1._proto_ =>Cat.prototype
3.將建構函式(類)內部的this 指向該例項物件,並執行程式碼 就像是 this => _obj
4.返回該物件
=======原型
每一個函式都有一個屬性,prototype表示原型(原型物件)。
class Dog{} new Dog()
原型的作用:
給所有例項提供公共的訪問。
`let arr = [];
console.log(Array.prototype);
const obj1 = {
name : "zhangsan"
}
console.log(obj1.name,obj1.age);// zhangsan un
Object.prototype.age = 18;
console.log(obj1.name,obj1.age);//zhangsan 18`
2.物件和隱式原型
每一個例項物件都有一個_proto_,稱為隱式原型,指向建立該物件的類的原型。
const arr1 = []; //new Array()
console.log(arr1.proto === Array.prototype);//true
3.原型和構造器
每一個類(函式)的prototype上都有constructor指向函式本身
每個原型都有一個constructor屬性,指向該關聯的建構函式。
console.log(Array.prototype.constructor === Array);//true
4.原型鏈
鏈 鏈式呼叫 快 美化程式碼 簡潔方便
作用域鏈 找變數
原型鏈 找公共屬性 方法是特殊的屬性,一個例項在呼叫屬性,方法時,會以此從例項自身 -> 建立該例項的建構函式的原型 -> Object的原型。
檢視是否有對應的屬性或方法。專業上稱為原型鏈。
function Pig(){}; let pi_obj = new Pig(); console.log(pi_obj); Pig.prototype.eat = function(){ console.log(666); } pi_obj.eat();//666 pi_obj.toString();
instanceof 判斷 該物件是不是該類(函式)的例項物件。
function Pp(){} let P_obj = new Pp(); console.log(P_obj instanceof Pp);//true let pp = {} console.log(pp instanceof Pp);//false
=========繼承
當 類 和 類 之間發生了is關係,就看做繼承。
繼承的作用:子類繼承父類,繼承所有的屬性和方法。子類可以擴充套件自己的屬性和方法。實現程式碼複用。
糟糕的繼承關係,出現程式碼冗餘,關係臃腫。
class Animal{ //動物 constructor(type,name,age,gender){ this.type = type, this.name = name, this.age = age, this.gender = gender } eat(){ console.log("餓了,乾飯去"); } } class Pig extends Animal{ constructor(type,name,age,gender,color){ super(type,name,age,gender); //替代了 this.xx = xx this.color = color; } } let cat_obj = new Animal('cat','xiaobai',2,'male'); cat_obj.eat(); console.log(cat_obj); let pig_obj = new Pig('pig','xiaohei',3,'female','red'); pig_obj.eat(); console.log(pig_obj);
========= this
1.全域性環境下,this => windows。
2.普通函式(包括巢狀) this => windows。
3.通過物件呼叫的方法,this=>物件。
4.通過事件 this => 事件源。
5.建構函式 new 出來的例項,this => 例項。
6.箭頭函式的this指向取決於當前箭頭函式宣告的環境(執行上下文 EC)。
箭頭函式需要獲取函式定義時所在的EC的this,箭頭函式定義在哪個作用域中,就繼承當前作用域的this的指向。
1.全域性 this => window。
let foo =() => { console.log(this);//window }
EC 3類 :全域性環境(全域性EC),區域性環境(區域性EC,函式級別上下文),eval環境(eval EC);
const obj = { name : "zhangsan" } talk(){ console.log(this)//指向obj }
2.物件不會生成作用域。
let count = () => { console.log(this); console.log(this.name); } var number = 5; let obj = { say : count }; obj.say();
const zhangsan = { name : 'zhangsan', talk : function(){ console.log(this); //zhangsan物件 let lisi = { name : 'lisi', talk : () =>{ console.log(this); // zhangsan物件 (因為這個箭頭函式沒有this指向且在zhangsan.talk()的作用域中) } } lisi.talk(); } } zhangsan.talk();
let obj = { a : 10, fn :() =>{ let bar = () =>{ console.log(this);//window } bar(); } } obj.fn();
======修改 this 的指向
1.call 呼叫
語法:fn.call(target);
2.apply 應用
3.bind 捆綁
call,apply改變this的同時立即呼叫函式,bind 改變後返回一個新函式,需要重新呼叫。
function foo(){ console.log(this); } const obj = { name : "zhangsan" } foo() // window //對於傳參:call 直接跟在target後, apply 以陣列的方式 bind 呼叫函式的()裡傳 foo.call(obj,5); // zhangsan (foo的this的指向改為指向obj) foo.apply(obj,[5]); // zhangsan foo.bind(obj)(5); // zhangsan
var obj = { a:1, b : function(){ console.log(this.a); } } var a = 2; let fn = obj.b; obj.b(); //1 //指向obj物件 fn(); //2 //單純的將函式賦值給fn,指向全域性 obj.b.call(window)//2 //call(window) 全域性變數a
=======作用域 scope
作用: 生效 域:區域 ,變數生效的範圍,也叫詞法環境。
作用域的產生時間:函式定義(宣告)時產生。
作用域分類
3類
全域性作用域(全域性EC)
區域性作用域(區域性EC,函式級別上下文)
eval作用域(eval EC);
=======執行上下文 EC (execution context)
程式碼當前的執行環境,又稱為執行上下文環境。
上下文 語文 css this
EC的產生時間,函式呼叫時產生
全域性EC:預設環境。產生時間:開啟頁面---關閉頁面 生命週期
node node 執行 ---- 關閉
區域性(函式)EC,呼叫時----呼叫結束 生命週期
`=======執行上下文 EC (execution context)
程式碼當前的執行環境,又稱為執行上下文環境。
上下文 語文 css this
EC的產生時間,函式呼叫時產生
全域性EC:預設環境。產生時間:開啟頁面---關閉頁面 生命週期
node node 執行 ---- 關閉
區域性(函式)EC,呼叫時----呼叫結束 生命週期 `
=======EC的組成
當呼叫函式,新的EC會被建立,在JS引擎內部,這個EC的生命週期還會被分為:
1.建立階段
2.啟用階段
3.銷燬階段
建立階段
VO(variable object)變數物件:arguments,宣告式函式,var宣告的變數。
scope:確定作用域鏈
this:確定環境物件
啟用階段
函式的引用
變數賦值
執行其他程式碼
銷燬階段
(注:變數提升不提升值,即不賦值)!
VO是執行上下文建立階段內部建立的一個物件,用於記錄在當前作用域中所有可用的變數
VO中的屬性都是不可訪問的,只有等啟用階段VO變AO(active object)才能被訪問。
function outer(){ console.log(a); //undefined 變數提升不賦值 console.log(inner()); //2 函式提升 var a = 1; function inner(){ return 2; } } outer();
var a = 10; fn(); function fn(){ //內部的var不會提升到外部 var b = 5; console.log(a); //un console.log(b); //5 var a = "abc"; }
var a = 1; function fn(){ console.log(a);//un a = 2; console.log(a); //2 var a = 3; // 這個var a 提升到函式內部最上層 console.log(a); //3 } console.log(a); //1 fn(); console.log(a); //1
var fn = function(){ console.log(a);// 函式a本身 var a = 1; console.log(a); //1 a(); //報錯不是一個函式,因為此時a=1 function a(){} } fn();
var a = 1; function fn(){ a = 10; return a; function a(){} } console.log(fn());//10 console.log(a); //1
var a = 100; function foo(){ bar(a); //執行結束出棧 console.log(a); //100 } function bar(a){ // AO進棧 console.log(--a); //99 } foo();
function foo(num){ if(num > 3){ foo(--num);//依次執行,出棧不再執行 } console.log(num); //3,3,4 } foo(5)
======= 作用域鏈 scope chain SC
作用域鏈是一套 EC 的訪問規則,由當前上下文和上層上下文中一系列VO組成。
訪問規則:先訪問自身EC,若找不到變數,則訪問宣告時所在的EC的變數,以此類推到全域性。
var food = "巧克力味的粑粑"; function eat(){ console.log(
吃${food}`);//宣告在全域性,就在全局裡面找
}
function fn(){
var food = "粑粑味的巧克力";
eat();
}
fn();
var food = "巧克力味的粑粑";
function fn(){
var food = "粑粑味的巧克力";
function eat(){
console.log(`吃${food}`);
}
eat();
}
fn();`
let a1 = 1,a2 =2,a3 = 3; function foo(){ let a2 = 6; console.log(a1,a2,a3); //1,6,un var a3 = 9; //a3變數提升 a1 = 8; function bar(b){ a3 = 7; let a4 = 6; console.log(a1,a2,a3);//8,6,7 } bar(7); } foo(); console.log(a1,a2,a3);//8,2,3 console.log(a4);//報錯
垃圾:無用的東西
對於計算機:多餘的,無用的資料
儲存資料,計算機都會開闢空間來儲存組織,但無限開闢空間則會出現爆棧影響效能。
計算機會在適當的時候自動清理無用的資料,自動執行,並不可見,引擎中有一個後臺的程序被稱為“垃圾回收器”。
function foo(){ let a = 5; console.log(a);//5 被標記“進入環境” } foo(); console.log(a);//無法被訪問 “離開環境”
回收方案:
1.標記清除
2.引用計數
const obj = { name : "zhangsan" } obj = null;//切斷了引用,計數為0,回收
======= 閉包 closure
原本應該被清理的資料,由於還有引用(使用),導致該銷燬的資料沒有被銷燬。
難以描述的概念,書籍,文件對於閉包的描述都不一樣。
MDN:函式和對其周圍狀態的引用捆綁在一起構成閉包,閉包可以讓你從函式內部訪問外部函式作用域,每當函式被建立,就會在函式生成時生成閉包。
javaScript高階程式設計:閉包是指有權訪問另一個作用域中變數函式。
廣義:所有函式都會生成閉包,因為只要有函式,就有SC。
狹義:函式的巢狀,內部函式在訪問外部函式作用域,內部函式在自身以外被呼叫。
function outer(){ let number = 5; return function(){ console.log(number); } } let result = outer(); result();//5
====== 深淺拷貝
深拷貝:都是針對複雜資料型別,改變原有物件裡的值,新的物件的值不會改變。
淺拷貝:改變原有物件裡的值,新的物件的值也會改變
1.for, for of ,... , concat, map, slice, filter,Object.assgin(newArr,arr);
2.for in, ... ,Objcet.assgin(newobj,obj),Object.keys()等價於for in,JSON,obj =>str,str => newObj
陣列深拷貝
` let arr = [1,2,3];
let newArr = [];
// newArr = arr.slice(0,4); //使用陣列擷取方法
// let newArr = arr.map(item => { //使用map
// return item;
// })
// newArr = arr.filter(item =>{ //使用filter
// return item;
// })
// newArr = [...arr]; //使用擴充套件運算子
// Object.assign(newArr,arr); //使用Object.assgin()
// for(let item of arr){ //使用for of
// newArr.push(item);
// }
arr[0] = 'a';
console.log(arr);
console.log(newArr);物件深拷貝 : 新物件不會因為舊物件屬性的更改而發生改變
let zsObj = {
name : "zhangsan",
age: 18
}
let new_obj = {};
// for(let key in zsObj){
// new_obj[key] = zsObj[key]; //使用for in 賦值
// console.log(zsObj,new_obj);
// }
// Object.assign(new_obj,zsObj); //使用Object.assgin()
// new_obj = {...zsObj}; //使用擴充套件運算子
// new_obj = JSON.stringify(zsObj); //使用JSON
// console.log(JSON.parse(new_obj));
zsObj.name = 'lisi';
console.log(zsObj);
console.log(new_obj);`
深拷貝考慮:
1.遞迴考慮爆棧。
2.物件方法是否要拷貝,正則,JSON能夠儲存的資料型別不包括函式,undefined,data。
3.業務範疇,不能脫離業務場景。
4.庫,框架已經封裝好了克隆的方法,直接用。