javascript
【JS从入门到精通】08-构造函数与原型对象
筆記來源:尚硅谷最新版JavaScript基礎全套教程完整版(140集實戰教學,JS從入門到精通)_嗶哩嗶哩_bilibili
文章目錄
- 構造函數與原型對象
- 1、使用工廠方法創建對象
- 2、構造函數
- 構造函數的執行流程
- 構造函數修改
- 3、原型對象
- 原型prototype
- hasOwnProperty
- 原型的原型
- toString
- 4、垃圾回收(GC)
構造函數與原型對象
1、使用工廠方法創建對象
function createPerson(name, age, gender){// 創建一個新的對象var obj=new Object();//向對象中添加屬性obj.name = name;obj.age = age;obj.gender = gender;obj.sayName = function(){console.log(this.name);};//將新的對象返回return obj; }var obj1 = createPerson("孫悟空", 1000, "男"); var obj2 = createPerson("豬八戒", 3600, "男"); var obj3 = createPerson("沙悟凈", 10000, "男");obj1.sayName(); // 孫悟空 obj2.sayName(); // 豬八戒 obj3.sayName(); // 豬八戒使用工廠方法創建的對象,使用的構造函數都是Object
所以創建的對象都是Object這個類型,就導致我們無法區分出多種不同類型的對象
2、構造函數
創建一個構造函數,專門用來創建Person對象的構造函數就是一個普通的函數
創建方式和普通函數沒有區別,不同的是構造函數習慣上首字母大寫構造函數
和普通函數的區別就是調用方式的不同
- 普通函數是直接調用
- 構造函數需要使用new關鍵字來調用
構造函數的執行流程
使用同一個構造函數創建的對象,我們稱為一類對象,也將一個構造函數稱為一個類。
我們將通過一個構造函數創建的對象,稱為是該類的實例
使用instanceof可以檢查一個對象是否是一個類的實例語法:對象 instanceof 構造函數
如果是則返回true,否則返回false
console.log(person1 instanceof Person); //true console.log(person2 instanceof Person); //true console.log(person3 instanceof Person); //true console.log(dog instanceof Person); //false所有的對象都是Object的后代,所以任何對象和Object進行instanceof檢查時都會返回true
console.log(person1 instanceof Object); //true console.log(person2 instanceof Object); //true console.log(person3 instanceof Object); //true console.log(dog instanceof Object); //truethis的情況:
- 當以函數的形式調用時,this是window
- 當以方法的形式調用時,誰調用方法this就是誰
- 當以構造函數的形式調用時,this就是新創建的那個對象
構造函數修改
創建一個Person構造函數
在Person構造函數中,為每一個對象都添加了一個sayName方法,目前我們的方法是在構造函數內部創建的
也就是構造函數每執行一次就會創建一個新的sayName方法也是所有實例的sayName都是唯一的
function Person(name, age, gender){this.name = name;this.age = age;this.gender = gender;this.sayHello = function(){console.log("My'name is " + this.name + ", " +"I'm " + this.age + " years old, " +"and I'm a " + this.gender + ".");}; }這樣就導致了構造函數執行一次就會創建一個新的方法,執行10000次就會創建10000個新的方法,而10000個方法都是一模一樣的
這是完全沒有必要,完全可以使所有的對象共享同一個方法
function Person(name, age, gender){this.name = name;this.age = age;this.gender = gender;this.sayHello = fun; } // 將sayName方法在全局作用域中定義 function fun(){console.log("My'name is " + this.name + ", " +"I'm " + this.age + " years old, " +"and I'm a " + this.gender + "."); };將函數定義在全局作用域,雖然節省了空間,但卻污染了全局作用域的命名空間
而且定義在全局作用域中也很不安全
3、原型對象
原型prototype
我們所創建的每一個函數(不論是普通函數還是構造函數),解析器都會向函數中添加一個屬性prototype
function Person(){}function MyClass(){}console.log(Person.prototype); // {constructor: ?} // constructor: ? Person() // arguments: null // caller: null // length: 0 // name: "Person" // prototype: {constructor: ?} // __proto__: ? () // [[FunctionLocation]]: 09-原型對象.html:8 // [[Scopes]]: Scopes[1] // __proto__: Object console.log(Person.prototype == MyClass.prototype); // false當函數以普通函數的形式調用prototype時,沒有任何作用
當函數以構造函數的形式調用prototype時,它所創建的對象中都會有一個隱含的屬性,指向該構造函數的原型對象,我們可以通過__proto__來訪問該屬性
var mc1 = new MyClass(); var mc2 = new MyClass(); var mc3 = new MyClass(); console.log(mc1.__proto__ == MyClass.prototype); // true console.log(mc2.__proto__ == MyClass.prototype); // true console.log(mc3.__proto__ == MyClass.prototype); // true原型對象就相當于一個公共區域,所有同一個類的實例都可以訪問到這個原型對象
我們可以將對象中共有的內容,統一設置到原型對象中
// 向MyClass中添加屬性a MyClass.prototype.a = "123"; console.log(mc1.a); // 123 // 向MyClass中添加方法sayHello MyClass.prototype.sayHello = function(){ alert("hello"); } mc3.sayHello();當我們訪問對象的一個屬性或方法時,它會先在對象自身中尋找,如果有則直接使用,如果沒有則會去原型對象中尋找,如果找到則直接使用
mc2.a = "456"; console.log(mc2.a); // 456以后我們創建構造函數時,可以將這些對象共有的屬性和方法,統一添加到構造函數的原型對象中
這樣不用分別為每一個對象添加,也不會影響到全局作用域,就可以使每個對象都具有這些屬性和方法了
hasOwnProperty
function MyClass(){} MyClass.prototype.name = "I'm prototype's name."; var mc = new MyClass(); mc.age = 18; // 使用in檢查對象中是否含有某個屬性時,如果對象中沒有但是原型中有,也會返回true console.log("name" in mc); // true console.log("age" in mc); // true // 可以使用對象的hasOwnProperty()來檢查對象自身中是否含有該屬性 // 使用該方法只有當對象自身中含有屬性時,才會返回true console.log(mc.hasOwnProperty("name")); // false console.log(mc.hasOwnProperty("age")); // true console.log(mc.hasOwnProperty("hasOwnProperty")); // false那么,hasOwnProperty是原型對象中定義的方法嗎?
因為對象中沒有定義hasOwnProperty方法,那應該就是在原型對象中定義的了,果真如此嗎?
我們用hasOwnProperty方法看下有沒有hasOwnProperty它自己
console.log(mc.__proto__.hasOwnProperty("hasOwnProperty")); // false我們發現,原型對象中也沒有hasOwnProperty方法,那hasOwnProperty究竟是哪里來的呢?
原型的原型
原型對象也是對象,所以它也有原型,當我們使用一個對象的屬性或方法時
-
會先在自身中尋找,自身中如果有則直接使用
-
如果沒有則去原型對象中尋找,有則使用
-
如果沒有則去原型的原型中尋找,直到找到Object對象的原型
-
Object對象的原型沒有原型,如果在Object中依然沒有找到,則返回undefined
console.log(mc.helloWorld); // undefined
那么,按照這個原理,我們在原型的原型中使用hasOwnProperty方法看看
console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty")); // true那既然原型對象有原型,那原型的原型還有原型嗎?
話不多說,直接打印看下
console.log(mc.__proto__.__proto__.__proto__); // null根據上述原理,mc.__proto__.__proto__就是Object對象了
Object對象雖然沒有原型,但也有__proto__,只是為null而已
toString
當我們直接在頁面中打印一個對象時,事件上是輸出的對象的toString()方法的返回值(這里并非視頻中所說的那樣,有待確認)
如果我們希望在輸出對象時不輸出[object Object],可以為對象添加一個toString()方法
function Person(name, age, gender){this.name = name;this.age = age;this.gender = gender; } var per1 = new Person("孫悟空", 1000, "man"); var per2 = new Person("豬八戒", 3600, "man"); // 當我們直接在頁面中打印一個對象時,事件上是輸出的對象的`toString()`方法的返回值 console.log(per1); // Person {name: "孫悟空", age: 1000, gender: "man"} console.log(per1.toString()); // [object Object] // 如果我們希望在輸出對象時不輸出`[object Object]`,可以為對象添加一個`toString()`方法 per1.toString = function(){return "Person[name=" + this.name + ", age=" + this.age + ", gender=" + this.gender + "]"; } console.log(per1); // Person {name: "孫悟空", age: 1000, gender: "man", toString: ?} console.log(per1.toString()); // Person[name=孫悟空, age=1000, gender=man]上述只是修改per1對象的toString方法,不會對其他對象產生影響
如果想要所有對象都執行該方法,可以修改Person原型的toString
console.log(per2.toString()); // [object Object] // 修改Person原型的toString Person.prototype.toString = function(){return "Person[name=" + this.name + ", age=" + this.age + ", gender=" + this.gender + "]"; } console.log(per2.toString()); // Person[name=豬八戒, age=3600, gender=man]4、垃圾回收(GC)
就像人生活的時間長了會產生垃圾一樣,程序運行過程中也會產生垃圾這些垃圾積攢過多以后,會導致程序運行的速度過慢
所以我們需要一個垃圾回收的機制,來處理程序運行過程中產生垃圾
當一個對象沒有任何的變量或屬性對它進行引用,我們將永遠無法操作該對象
此時這種對象就是一個垃圾,這種對算過多會占用大量的內存空間,導致程序運行變慢
在JS中擁有自動的垃圾回收機制,會自動將這些垃圾對象從內存中銷毀,我們不需要也不能進行垃圾回收的操作
我們需要做的只是要將不再使用的對象設置null即可
var obj = new Object(); // ... obj = null總結
以上是生活随笔為你收集整理的【JS从入门到精通】08-构造函数与原型对象的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 领峰:现货贵金属预测,掌握市场行情做出准
- 下一篇: 【微信企业应用】THINKPHP下事件回