構造函數
function Star (uname, age){this.uname = unamethis.age = agethis.sing = function(){ log('唱歌~') }}let xzq = new Star('薛之謙', 30)let ldh = new Star('劉德華', 20)log(ldh) // { uname: '劉德華', age: 20, sing: f }ldh.sing() // 唱歌~log(ldh.sing === xzq.sing) // false
# 實例成員:構造函數內部,通過this添加的成員,如上面的:uname、age、sing實例成員,只能通過實例化的對象來訪問,如:ldh.sing()才行,Star.sing()就不行# 靜態成員:在構造函數本身上,添加的成員,如:Star.sex = '男'靜態成員只能通過構造函數訪問,如:log(Star.sex) // 男不能通過實例化對象來訪問(ldh.sex就不行)# 構造函數 new 的執行過程1、new構造函數,可以在內存中創建一個空的對象2、this就會指向剛才創建的空對象3、執行構造函數里面的代碼,就給這個空對象添加屬性、方法4、返回這個對象(所以構造函數里面不用return)
prototype 原型對象
# js規定,每一個構造函數都有一個prototype屬性,這個prototype就是一個對象所以,我們可以把'公共的方法'添加到這個'原型對象prototype上'(原型對象prototype的作用就是共享方法)所以:公共的屬性,定義到,構造函數里面公共的方法,定義到,原型對象prototype上
function Star (uname, age){this.uname = unamethis.age = age}Star.prototype.sing = function(){ log('唱個歌') }let ldh = new Star('劉德華', 20)let xzq = new Star('薛之謙', 30)log(ldh.sing === xzq.sing) // true# console.log( ldh ) // 系統會自動,在對象的身上,添加一個'__proto__',指向構造函數的原型對象# prototypeconsole.log( ldh.__proto__ === Star.prototype ) // true
方法的查找規則:
首先看`ldh對象`,它身上是否有sing()方法,如果有,就執行它的這個方法如果沒有這個方法,但因為`__proto__`存在,就去`構造函數的原型對象prototype上`去找這個sing()方法
proto:對象原型
每個對象身上都有一個`__proto__`對象原型,指向`指向構造函數的原型對象prototype`之所以,對象可以使用`構造函數的原型對象prototype`上的屬性、方法是因為,對象有`__proto__(對象原型)`的存在`__proto__對象原型` 和 `構造函數的原型對象prototype`是等價的`__proto__對象原型`的意義:在于為對象的查找機制提供一個方向,或者說一條線路,但它是一個非標準屬性,因此實際開發中,不可用使用這個屬性,它只是內部指向原型對象prototype
原型鏈
function Star(uname, age){this.uname = unamethis.age = age}let ldh = new Start('劉德華', 123)log( ldh.__proto__ === Star.prototype ) // truelog( Star.prototype.__proto__ === Object.prototype ) // truelog( Star.prototype.__proto__ ) // null
原型鏈的查找規則
當訪問一個對象的屬性(方法)時,首先看這個對象本身有沒有該屬性,如果沒有,就查找它的原型(也就是`__proto__對象原型`,指向的是,`prototype原型對象`)如果還沒有,就查找,原型對象的原型(Object的原型對象)依次類推,直到找到Object為止(null)`_proto_對象原型`的意義:在于為對象的查找機制提供一個方向,或者說一條路線,但是它是一個非標準屬性,因此實際開發中,不可以使用這個屬性,它只是內部指向原型對象prototype
可以通過原型對象,為JavaScript的(原來的)內置對象,進行擴展自定義的方法
如下:通過數組的原型對象,添加求和的方法
Array.prototype.sum = function(){console.log(this) // 指向它的調用者let sum = 0for(let i=0; i<this.length; i++){sum += this[i]}return sum}let arr = [1, 2, 3] // let arr = new Array(1,2,3)console.log(arr.sum()) // 6
constructor 指回 原來的原型對象
// 定義一個構造函數Starfunction Star(uname, age) {this.uname = unamethis.age = age}Star.prototype.sing = function () {console.log('唱歌~~')}// 對象.xxx:這樣是向對象添加xxx屬性,并不會覆蓋這個對象Star.prototype.song = function () {console.log("我會唱歌")}Star.prototype.dance = function () {console.log("我會跳舞")}// 對象 = {}:這樣是重新給對象賦值,會把原來的對象覆蓋掉// 其實這里就是把 構造函數Star 的原型對象prototype 覆蓋了,但是并不會影響uname、age在構造函數中定義的屬性Star.prototype = {aaa() { console.log("我會唱歌aa") },bbb() { console.log("我會唱歌bbb") },// ....// ....// ....}// 手動用 constructor 指回原來的原型對象Star.prototype = {constructor: Star, // 指回原來的原型對象ccc() { console.log("我會唱歌ccc") },ddd() { console.log("我會唱歌ddd") },// ....// ....// ....}let ldh = new Star('劉德華', 123)console.log('ldh=', ldh) // ldh= Star {uname: '劉德華', age: 123}console.log('ldh.uname=', ldh.uname) // ldh.uname= 劉德華console.log('ldh.age=', ldh.age) // ldh.age= 123// ldh.sing() // Uncaught TypeError: ldh.sing is not a functionldh.song() // Uncaught TypeError: ldh.song is not a function// ldh.aaa() // Uncaught TypeError: ldh.aaa is not a function// ldh.bbb() // Uncaught TypeError: ldh.bbb is not a functionldh.ccc() // 我會唱歌ccc.ldh.ddd() // 我會唱歌ddd