javascript
【JS从入门到精通】08-构造函数与原型对象
筆記來源:尚硅谷最新版JavaScript基礎全套教程完整版(140集實戰(zhàn)教學,JS從入門到精通)_嗶哩嗶哩_bilibili
文章目錄
- 構(gòu)造函數(shù)與原型對象
- 1、使用工廠方法創(chuàng)建對象
- 2、構(gòu)造函數(shù)
- 構(gòu)造函數(shù)的執(zhí)行流程
- 構(gòu)造函數(shù)修改
- 3、原型對象
- 原型prototype
- hasOwnProperty
- 原型的原型
- toString
- 4、垃圾回收(GC)
構(gòu)造函數(shù)與原型對象
1、使用工廠方法創(chuàng)建對象
function createPerson(name, age, gender){// 創(chuàng)建一個新的對象var obj=new Object();//向?qū)ο笾刑砑訉傩?/span>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(); // 豬八戒使用工廠方法創(chuàng)建的對象,使用的構(gòu)造函數(shù)都是Object
所以創(chuàng)建的對象都是Object這個類型,就導致我們無法區(qū)分出多種不同類型的對象
2、構(gòu)造函數(shù)
創(chuàng)建一個構(gòu)造函數(shù),專門用來創(chuàng)建Person對象的構(gòu)造函數(shù)就是一個普通的函數(shù)
創(chuàng)建方式和普通函數(shù)沒有區(qū)別,不同的是構(gòu)造函數(shù)習慣上首字母大寫構(gòu)造函數(shù)
和普通函數(shù)的區(qū)別就是調(diào)用方式的不同
- 普通函數(shù)是直接調(diào)用
- 構(gòu)造函數(shù)需要使用new關(guān)鍵字來調(diào)用
構(gòu)造函數(shù)的執(zhí)行流程
使用同一個構(gòu)造函數(shù)創(chuàng)建的對象,我們稱為一類對象,也將一個構(gòu)造函數(shù)稱為一個類。
我們將通過一個構(gòu)造函數(shù)創(chuàng)建的對象,稱為是該類的實例
使用instanceof可以檢查一個對象是否是一個類的實例語法:對象 instanceof 構(gòu)造函數(shù)
如果是則返回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的情況:
- 當以函數(shù)的形式調(diào)用時,this是window
- 當以方法的形式調(diào)用時,誰調(diào)用方法this就是誰
- 當以構(gòu)造函數(shù)的形式調(diào)用時,this就是新創(chuàng)建的那個對象
構(gòu)造函數(shù)修改
創(chuàng)建一個Person構(gòu)造函數(shù)
在Person構(gòu)造函數(shù)中,為每一個對象都添加了一個sayName方法,目前我們的方法是在構(gòu)造函數(shù)內(nèi)部創(chuàng)建的
也就是構(gòu)造函數(shù)每執(zhí)行一次就會創(chuàng)建一個新的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 + ".");}; }這樣就導致了構(gòu)造函數(shù)執(zhí)行一次就會創(chuàng)建一個新的方法,執(zhí)行10000次就會創(chuàng)建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 + "."); };將函數(shù)定義在全局作用域,雖然節(jié)省了空間,但卻污染了全局作用域的命名空間
而且定義在全局作用域中也很不安全
3、原型對象
原型prototype
我們所創(chuàng)建的每一個函數(shù)(不論是普通函數(shù)還是構(gòu)造函數(shù)),解析器都會向函數(shù)中添加一個屬性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當函數(shù)以普通函數(shù)的形式調(diào)用prototype時,沒有任何作用
當函數(shù)以構(gòu)造函數(shù)的形式調(diào)用prototype時,它所創(chuàng)建的對象中都會有一個隱含的屬性,指向該構(gòu)造函數(shù)的原型對象,我們可以通過__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原型對象就相當于一個公共區(qū)域,所有同一個類的實例都可以訪問到這個原型對象
我們可以將對象中共有的內(nèi)容,統(tǒng)一設置到原型對象中
// 向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以后我們創(chuàng)建構(gòu)造函數(shù)時,可以將這些對象共有的屬性和方法,統(tǒng)一添加到構(gòu)造函數(shù)的原型對象中
這樣不用分別為每一個對象添加,也不會影響到全局作用域,就可以使每個對象都具有這些屬性和方法了
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我們發(fā)現(xiàn),原型對象中也沒有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根據(jù)上述原理,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方法,不會對其他對象產(chǎn)生影響
如果想要所有對象都執(zhí)行該方法,可以修改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)
就像人生活的時間長了會產(chǎn)生垃圾一樣,程序運行過程中也會產(chǎn)生垃圾這些垃圾積攢過多以后,會導致程序運行的速度過慢
所以我們需要一個垃圾回收的機制,來處理程序運行過程中產(chǎn)生垃圾
當一個對象沒有任何的變量或?qū)傩詫λM行引用,我們將永遠無法操作該對象
此時這種對象就是一個垃圾,這種對算過多會占用大量的內(nèi)存空間,導致程序運行變慢
在JS中擁有自動的垃圾回收機制,會自動將這些垃圾對象從內(nèi)存中銷毀,我們不需要也不能進行垃圾回收的操作
我們需要做的只是要將不再使用的對象設置null即可
var obj = new Object(); // ... obj = null總結(jié)
以上是生活随笔為你收集整理的【JS从入门到精通】08-构造函数与原型对象的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 领峰:现货贵金属预测,掌握市场行情做出准
- 下一篇: 【微信企业应用】THINKPHP下事件回