1 構造函數web
構造函數是專門用於建立對象的
function Person(myName, myAge) { // let obj = new Object(); // 系統自動添加的 // let this = obj; // 系統自動添加的 this.name = myName; this.age = myAge; this.say = function () { console.log("hello world"); } // return this; // 系統自動添加的 }
1.當咱們new Person("lnj", 34);系統作了什麼事情
1.1會在構造函數中自動建立一個對象
1.2會自動將剛纔建立的對象賦值給this
1.3會在構造函數的最後自動添加return this;
let obj1 = new Person("lnj", 34); let obj2 = new Person("zs", 44); console.log(obj1); console.log(obj2);
構造函數的優化:編程
上面構造函數的定義有一個弊端,以下數組
let obj1 = new Person("lnj", 34);
let obj2 = new Person("zs", 44);
因爲兩個對象中的say方法的實現都是同樣的, 可是保存到了不一樣的存儲空間中
因此有性能問題
console.log(obj1.say === obj2.say); // false
經過三個等號來判斷兩個函數名稱, 表示判斷兩個函數是否都存儲在同一塊內存中
優化方式1:安全
function mySay() { console.log("hello world"); } function Person(myName, myAge) { // let obj = new Object(); // 系統自動添加的 // let this = obj; // 系統自動添加的 this.name = myName; this.age = myAge; this.say = mySay; // return this; // 系統自動添加的 } let obj1 = new Person("lnj", 34); let obj2 = new Person("zs", 44); console.log(obj1.say === obj2.say); // true
可是這種方式也是有弊端的,app
1.1閱讀性下降了
1.2污染了全局的命名空間
優化方式2:webstorm
function Person(myName, myAge) { // let obj = new Object(); // 系統自動添加的 // let this = obj; // 系統自動添加的 this.name = myName; this.age = myAge; // this.say = fns.mySay; // return this; // 系統自動添加的 } Person.prototype = { say: function () { console.log("hello world"); } } let obj1 = new Person("lnj", 34); obj1.say(); let obj2 = new Person("zs", 44); obj2.say(); console.log(obj1.say === obj2.say); // true
經過改寫構造函數的 原型對象,讓方法say變得公用編程語言
3 prototype特色:函數
1.1存儲在prototype中的方法能夠被對應構造函數建立出來的全部對象共享
1.2prototype中除了能夠存儲方法之外, 還能夠存儲屬性
1.3prototype若是出現了和構造函數中同名的屬性或者方法, 對象在訪問的時候, 訪問到的是構造函中的數據
2.prototype應用場景
prototype中通常狀況下用於存儲全部對象都相同的一些屬性以及方法
若是是對象特有的屬性或者方法, 咱們會存儲到構造函數中
function Person(myName, myAge) { this.name = myName; this.age = myAge; this.currentType = "構造函數中的type"; this.say = function () { console.log("構造函數中的say"); } } Person.prototype = { currentType: "人", say: function () { console.log("hello world"); } } let obj1 = new Person("lnj", 34); obj1.say(); console.log(obj1.currentType); let obj2 = new Person("zs", 44); obj2.say(); console.log(obj2.currentType);
4 prototype,constructor, __proto__的三角戀關係性能
1.每一個"構造函數"中都有一個默認的屬性, 叫作prototype
prototype屬性保存着一個對象, 這個對象咱們稱之爲"原型對象"
2.每一個"原型對象"中都有一個默認的屬性, 叫作constructor
constructor指向當前原型對象對應的那個"構造函數"
3.經過構造函數建立出來的對象咱們稱之爲"實例對象"
每一個"實例對象"中都有一個默認的屬性, 叫作__proto__
__proto__指向建立它的那個構造函數的"原型對象"
function Person(myName, myAge) { this.name = myName; this.age = myAge; } let obj1 = new Person("lnj", 34); console.log(Person.prototype); console.log(Person.prototype.constructor); console.log(obj1.__proto__);
5 Function函數優化
1.JavaScript中函數是引用類型(對象類型), 既然是對象,
因此也是經過構造函數建立出來的,"全部函數"都是經過Function構造函數建立出來的對象
2.JavaScript中只要是"函數"就有prototype屬性
"Function函數"的prototype屬性指向"Function原型對象"
3.JavaScript中只要"原型對象"就有constructor屬性
"Function原型對象"的constructor指向它對應的構造函數
4.Person構造函數是Function構造函數的實例對象, 因此也有__proto__屬性
Person構造函數的__proto__屬性指向"Function原型對象"
5 Object函數
1. JavaScript函數是引用類型(對象類型), 因此Function函數也是對象
2."Function構造函數"也是一個對象, 因此也有__proto__屬性
"Function構造函數"__proto__屬性指向"Function原型對象"
3. JavaScript中還有一個系統提供的構造函數叫作Object
只要是函數都是"Function構造函數"的實例對象
4.只要是對象就有__proto__屬性, 因此"Object構造函數"也有__proto__屬性
"Object構造函數"的__proto__屬性指向建立它那個構造函數的"原型對象"
5.只要是構造函數都有一個默認的屬性, 叫作prototype
prototype屬性保存着一個對象, 這個對象咱們稱之爲"原型對象"
6.只要是原型對象都有一個默認的屬性, 叫作constructor
constructor指向當前原型對象對應的那個"構造函數"
function Person(myName, myAge) { this.name = myName; this.age = myAge; } let obj1 = new Person("lnj", 34); console.log(Function.__proto__); console.log(Function.__proto__ === Function.prototype); // true console.log(Object); console.log(Object.__proto__); console.log(Object.__proto__ === Function.prototype); // true console.log(Object.prototype); console.log(Object.prototype.constructor); console.log(Object.prototype.constructor === Object); // true console.log(Object.prototype.__proto__); // null
6 函數對象關係
1.全部的構造函數都有一個prototype屬性, 全部prototype屬性都指向本身的原型對象
2,全部的原型對象都有一個constructor屬性, 全部constructor屬性都指向本身的構造函數
3.全部函數都是Function構造函數的實例對象
4.全部函數都是對象, 包括Function構造函數
5.全部對象都有__proto__屬性
6.普通對象的__proto__屬性指向建立它的那個構造函數對應的"原型對象"
7.全部對象的__proto__屬性最終都會指向"Object原型對象"
8."Object原型對象"的__proto__屬性指向NULL
Object ,Function,實例對象的總圖:
function Person(myName, myAge) { this.name = myName; this.age = myAge; } let obj1 = new Person("lnj", 34); console.log(Function.prototype.__proto__); console.log(Person.prototype.__proto__); console.log(Function.prototype.__proto__ === Person.prototype.__proto__);//true console.log(Function.prototype.__proto__ === Object.prototype);//true console.log(Person.prototype.__proto__ === Object.prototype);//true
7 原型鏈
1.對象中__proto__組成的鏈條咱們稱之爲原型鏈
2.對象在查找屬性和方法的時候, 會先在當前對象查找
若是當前對象中找不到想要的, 會依次去上一級原型對象中查找
若是找到Object原型對象都沒有找到, 就會報錯
function Person(myName, myAge) { this.name = myName; this.age = myAge; // this.currentType = "構造函數中的type"; // this.say = function () { // console.log("構造函數中的say"); // } } Person.prototype = { // 注意點: 爲了避免破壞原有的關係, 在給prototype賦值的時候, 須要在自定義的對象中手動的添加constructor屬性, 手動的指定須要指向誰 constructor: Person, // currentType: "人", // say: function () { // console.log("hello world"); // } } let obj1 = new Person("lnj", 34); // obj1.say(); console.log(obj1.currentType); // console.log(Person.prototype.constructor);
8 屬性注意點
在給一個對象不存在的屬性設置值的時候, 不會去原型對象中查找, 若是當前對象沒有就會給當前對象新增一個不存在的屬性
function Person(myName, myAge) { this.name = myName; this.age = myAge; } Person.prototype = { constructor: Person, currentType: "人", say: function () { console.log("hello world"); } } let obj = new Person("lnj", 34); // console.log(obj.currentType); // "人" // console.log(obj.__proto__.currentType); // "人" // 注意點: 在給一個對象不存在的屬性設置值的時候, 不會去原型對象中查找, 若是當前對象沒有就會給當前對象新增一個不存在的屬性 obj.currentType = "新設置的值"; console.log(obj.currentType); // 新設置的值 console.log(obj.__proto__.currentType); // "人"
9 js三大特性之一-封裝性
1.局部變量和局部函數
不管是ES6以前仍是ES6, 只要定義一個函數就會開啓一個新的做用域
只要在這個新的做用域中, 經過let/var定義的變量就是局部變量
只要在這個新的做用域中, 定義的函數就是局部函數
2.什麼是對象的私有變量和函數
默認狀況下對象中的屬性和方法都是公有的, 只要拿到對象就能操做對象的屬性和方法
外界不能直接訪問的變量和函數就是私有變量和是有函數
構造函數的本質也是一個函數, 因此也會開啓一個新的做用域, 因此在構造函數中定義的變量和函數就是私有和函數
*/
/*
3.什麼是封裝?
封裝性就是隱藏實現細節,僅對外公開接口
4.爲何要封裝?
4.1不封裝的缺點:當一個類把本身的成員變量暴露給外部的時候,那麼該類就失去對屬性的管理權,別人能夠任意的修改你的屬性
4.2封裝就是將數據隱藏起來,只能用此類的方法才能夠讀取或者設置數據,不可被外部任意修改. 封裝是面向對象設計本質(將變化隔離)。這樣下降了數據被誤用的可能 (提升安全性和靈活性)
function Person() { this.name = "lnj"; // this.age = 34; let age = 34; this.setAge = function (myAge) { if(myAge >= 0){ age = myAge; } } this.getAge = function () { return age; } this.say = function () { console.log("hello world"); } /* // 因爲構造函數也是一個函數, 因此也會開啓一個新的做用域 // 因此在構造函數中經過var/let定義的變量也是局部變量 // 因此在構造函數中定義的函數也是局部函數 var num = 123; let value = 456; function test() { console.log("test"); } */ } let obj = new Person(); // 結論: 默認狀況下對象的屬性和方法都是公開的, 只要拿到對象就能夠操做對象的屬性和方法 // console.log(obj.name); // obj.age = -3; // console.log(obj.age); // obj.say(); // console.log(age); obj.setAge(-3); console.log(obj.getAge());
10 私有屬性注意點
在給一個對象不存在的屬性設置值的時候, 不會去原型對象中查找, 若是當前對象沒有就會給當前對象新增一個不存在的屬性
因爲私有屬性的本質就是一個局部變量, 並非真正的屬性, 因此若是經過 對象.xxx的方式是找不到私有屬性的, 因此會給當前對象
11 屬性方法分類
1.在JavaScript中屬性和方法分類兩類
1.1實例屬性/實例方法
在企業開發中經過實例對象訪問的屬性, 咱們就稱之爲實例屬性
在企業開發中經過實例對象調用的方法, 咱們就稱之爲實例方法
1.2靜態屬性/靜態方法
在企業開發中經過構造函數訪問的屬性, 咱們就稱之爲靜態屬性
在企業開發中經過構造函數調用的方法, 咱們就稱之爲靜態方法
function Person() { this.name = "lnj"; this.say = function () { console.log("hello world"); } } // 經過構造函數建立的對象, 咱們稱之爲"實例對象" let obj = new Person(); console.log(obj.name); obj.say(); obj.age = 34; console.log(obj.age); obj.eat = function () { console.log("eat"); } obj.eat(); // 構造函數也是一個"對象", 因此咱們也能夠給構造函數動態添加屬性和方法 Person.num = 666; Person.run = function () { console.log("run"); } console.log(Person.num); Person.run();
12 bind call apply
1.this是什麼?
誰調用當前函數或者方法, this就是誰
*/
/*
2.這三個方法的做用是什麼?
這三個方法都是用於修改函數或者方法中的this的
2.1.bind方法做用
修改函數或者方法中的this爲指定的對象, 而且會返回一個修改以後的新函數給咱們
注意點: bind方法除了能夠修改this之外, 還能夠傳遞參數, 只不過參數必須寫在this對象的後面
2.2.call方法做用
修改函數或者方法中的this爲指定的對象, 而且會當即調用修改以後的函數
注意點: call方法除了能夠修改this之外, 還能夠傳遞參數, 只不過參數必須寫在this對象的後面
2.3.apply方法做用
修改函數或者方法中的this爲指定的對象, 而且會當即調用修改以後的函數
注意點: apply方法除了能夠修改this之外, 還能夠傳遞參數, 只不過參數必須經過數組的方式傳遞
let obj = { name: "zs" } function test(a, b) { console.log(a, b); console.log(this); } test(10, 20); window.test(); let fn = test.bind(obj, 10, 20); fn(); test.call(obj, 10, 20); test.apply(obj, [10, 20]); function Person() { this.name = "lnj"; this.say = function () { console.log(this); } } let p = new Person(); p.say(); let fn = p.say.bind(obj); fn(); p.say.call(obj); p.say.apply(obj);
13 js三大特性之繼承性
方式一:
function Person() { this.name = null; this.age = 0; this.say = function () { console.log(this.name, this.age); } } let per = new Person(); per.name = "lnj"; per.age = 34; per.say(); // 在企業開發中若是構造函數和構造函數之間的關係是is a關係, 那麼就可使用繼承來優化代碼, 來減小代碼的冗餘度 // 學生 is a 人 , 學生是一我的 function Student() { // this.name = null; // this.age = 0; // this.say = function () { // console.log(this.name, this.age); // } this.score = 0; this.study = function () { console.log("day day up"); } } Student.prototype = new Person(); Student.prototype.constructor = Student; let stu = new Student(); stu.name = "zs"; stu.age = 18; stu.score = 99; stu.say(); stu.study();
弊端:
調用子類構造函數建立對象的時候,沒法訪問父類的屬性
function Person(myName, myAge) { this.name = myName; this.age = myAge; this.say = function () { console.log(this.name, this.age); } } // let per = new Person("lnj", 34); // per.say(); // 學生 is a 人 , 學生是一我的 function Student(myName, myAge, myScore) { //沒法訪問到父類的屬性 this.score = myScore; this.study = function () { console.log("day day up"); } } // let stu = new Student(); // stu.name = "zs"; // stu.age = 18; // stu.score = 99; // stu.say(); // stu.study();
方式二:
function Person(myName, myAge) { // let per = new Object(); // let this = per; // this = stu; this.name = myName; // stu.name = myName; this.age = myAge; // stu.age = myAge; this.say = function () { // stu.say = function () {} console.log(this.name, this.age); } // return this; } function Student(myName, myAge, myScore) { // let stu = new Object(); // let this = stu; Person.call(this, myName, myAge); // Person.call(stu); this.score = myScore; this.study = function () { console.log("day day up"); } // return this; } let stu = new Student("ww", 19, 99); // stu.name = "zs"; // stu.age = 18; // stu.score = 99; console.log(stu.score); stu.say(); stu.study();
弊端:訪問不到 父類 原型對象 中的屬性和方法
方式三:
function Person(myName, myAge) { // let per = new Object(); // let this = per; // this = stu; this.name = myName; // stu.name = myName; this.age = myAge; // stu.age = myAge; this.sex = 1; // this.say = function () { // stu.say = function () {} // console.log(this.name, this.age); // } // return this; } Person.prototype.say = function () { console.log(this.name, this.age); } function Student(myName, myAge, myScore) { Person.call(this, myName, myAge); this.score = myScore; this.study = function () { console.log("day day up"); } } // 注意點: 要想使用Person原型對象中的屬性和方法, 那麼就必須將Student的原型對象改成Person的原型對象才能夠 Student.prototype = Person.prototype; Student.prototype.constructor = Student; let stu = new Student("ww", 19, 99); console.log(stu.score); stu.say(); stu.study();
弊端:讓子類的原型對象和父類的原型對象是一個,若是在其中一個 修改原型對象,會影響另外一個
方式四:終極方案
1.js中繼承的終極方法
1.1在子類的構造函數中經過call藉助父類的構造函數
1.2將子類的原型對象修改成父類的實例對象
function Person(myName, myAge) { // let per = new Object(); // let this = per; // this = stu; this.name = myName; // stu.name = myName; this.age = myAge; // stu.age = myAge; // return this; } Person.prototype.say = function () { console.log(this.name, this.age); } function Student(myName, myAge, myScore) { Person.call(this, myName, myAge); this.score = myScore; this.study = function () { console.log("day day up"); } } /* 弊端: 1.因爲修改了Person原型對象的constructor屬性, 因此破壞了Person的三角戀關係 2.因爲Person和Student的原型對象是同一個, 因此給Student的元素添加方法, Person也會新增方法 */ // Student.prototype = Person.prototype; Student.prototype = new Person(); Student.prototype.constructor = Student; Student.prototype.run = function(){ console.log("run"); } let per = new Person(); per.run();
/* 1.什麼是強類型語言, 什麼是是弱類型語言 1.1什麼是強類型語言: 通常編譯型語言都是強類型語言, 強類型語言,要求變量的使用要嚴格符合定義 例如定義 int num; 那麼num中未來就只可以存儲整型數據 1.2什麼是弱類型語言: 通常解釋型語言都是弱類型語言, 弱類型語言, 不會要求變量的使用要嚴格符合定義 例如定義 let num; num中既能夠存儲整型, 也能夠存儲布爾類型等 1.3因爲js語言是弱類型的語言, 因此咱們不用關注多態 2.什麼是多態? 多態是指事物的多種狀態 例如: 按下 F1 鍵這個動做, 若是當前在 webstorm 界面下彈出的就是 webstorm 的幫助文檔; 若是當前在 Word 下彈出的就是 Word 幫助; 同一個事件發生在不一樣的對象上會產生不一樣的結果。 3.多態在編程語言中的體現 父類型變量保存子類型對象, 父類型變量當前保存的對象不一樣, 產生的結果也不一樣 */ // function Animal(myName) { // this.name = myName; // this.eat = function () { // console.log(this.name + " 動物吃東西"); // } // } function Dog() { // Animal.call(this, myName); this.eat = function () { console.log(" 狗吃東西"); } } // Dog.prototype = new Animal(); // Dog.prototype.constructor = Dog; function Cat() { // Animal.call(this, myName); this.eat = function () { console.log(" 貓吃東西"); } } // Cat.prototype = new Animal(); // Cat.prototype.constructor = Cat; // function feed(Dog animal) { // animal.eat(); // 狗吃東西 // } // function feed(Cat animal) { // animal.eat(); // 貓吃東西 // } // function feed(Animal animal) { // animal.eat(); // 狗吃東西 // } function feed(animal){ animal.eat(); } let dog = new Dog(); feed(dog); let cat = new Cat(); feed(cat);