大綱:
構(gòu)造函數(shù)
手寫new命令
原型鏈
Object對象的相關(guān)方法
(x)易錯點
- constructor表示構(gòu)造函數(shù)和原型對象之間的關(guān)聯(lián)關(guān)系媚送,如果修改了protype屬性温自,要同時修改constructor屬性,防止引用出錯
var P = function () {};
var p = new P();
var C = function () {};
C.prototype = p; -------- C.prototype修改成了p亿扁,所以c.constructor === p.constructor === P.prototype.constructor,
var c = new C();
c.constructor.prototype === p // false --------------- 要想是p,就需要指定c.constructor = C
c.constructro.prototype === P.prototype // true
(1) 實例只能訪問構(gòu)造函數(shù)prototype上的屬性髓考,不能直接修改構(gòu)造函數(shù)的prototype屬性
(2) 如果要修改,只能通過 x.constructor.prototype.color='yellow'方式修改
function A() {}
A.prototype.color = 'red'
const x = new A()
const y = new A()
x.color = 'yellow' ------------- 因為x.color是給x本身添加屬性并賦值弃酌,而不是修改x的原型對象的屬性
y.color????? // 'red'
- instanceof
1. instanceof原理:檢查 ( 右邊構(gòu)造函數(shù)的prototype屬性 ) 是否在 ( 左邊對象的原型鏈上 )
2. instanceof失效的情況:
- 如果一個對象的__proto__是null氨菇,instanceof就會判斷失效
- Object.prototype.__prototo__ === null
- Object.prototype instanceof Ojbect // false
// Object.create(null) instanceof Object // false儡炼,因為創(chuàng)建的實例沒有任何屬性和方法,也沒有原型
(1)構(gòu)造函數(shù)
- 函數(shù)名大寫查蓉,this代表將要生成的實例乌询,使用new命令生成實例
- new命令:執(zhí)行構(gòu)造函數(shù),返回實例對象(new命令本身就可以執(zhí)行構(gòu)造函數(shù)豌研,所以后面的括號可以不要)
- 如何保證構(gòu)造函數(shù)和new命令一起使用妹田?(忘記使用new了)
- 在構(gòu)造函數(shù)內(nèi)部使用嚴格模式:use strict,在嚴格模式下this不能指向window鹃共,默認是undefined鬼佣,undefined不能添加屬性,就會報錯
- 在構(gòu)造函數(shù)內(nèi)部判斷是否使用了new命令
- new命令的原理霜浴?
- 生成一個空對象(作為要返回的實例對象)
- 將空對象的隱式原型指向構(gòu)造函數(shù)的prototype屬性
- 將構(gòu)造函數(shù)中的this指向新生成的空對象
- 執(zhí)行構(gòu)造函數(shù)
-
手寫new命令
前置知識:
1. new命令返回值
- new命令總是返回一個對象晶衷,要么是( 實列對象 ),要么return后面所跟的 (對象)
2. 構(gòu)造函數(shù)中的return語句阴孟,使用new命令時的返回情況
- return 一個原始類型的值晌纫,使用new命令返回的是:-------------------------- this對象
- return 一個對象,使用new命令返回的是:--------------------------------- return后面緊跟的那個對象温眉,而不是this對象
- 如果構(gòu)造函數(shù)中沒有return語句缸匪,則默認返回的是:-------------------------- this對象
3. 如何判斷一個數(shù)據(jù)的數(shù)據(jù)類型?
- typeof:返回 number类溢,string凌蔬,boolean,undefined闯冷,symbol砂心,ojbect,function(七種)
- instanceof:- 原理是檢測 ( 右邊構(gòu)造函數(shù)的顯示原型prototype )是否在左邊 ( 實列對象的原型鏈上 )
- instanceof只能用于對象蛇耀,不能用于原始類型的值
- Object.prototype.toString().call(參數(shù)) ----------- 返回"[object 類型]"
- js中的數(shù)據(jù)類型 number, string, boolean, null, undefined, symbol, object (七種)
4. arguments對象
- 返回實參組成的類似數(shù)組的對象辩诞,該對象具有l(wèi)ength屬性
5. 如何把arguments對象轉(zhuǎn)換成真正的數(shù)組
- Array.from(arguments)
- Array.prototype.slice.call(arguments)
6. new命令的原理
- 新建一個空對象,作為要返回的實列對象
- 將空對象的隱式原型__proto__指向構(gòu)造函數(shù)的顯示原型prototype
- 將構(gòu)造函數(shù)中的this指向空對象
- 執(zhí)行構(gòu)造函數(shù)
7. 如何新建一個對象
- Object.create(b) : 以參數(shù)對象為原型纺涤,生成實列對象
- new Object()
- 對象字面量
- 注意:const a = Object.create(b) 即可以實現(xiàn) a.__proto__ === b == 構(gòu)造函數(shù).prototype
8. push unshift 和 pop shift
- push unsift 向數(shù)組添加數(shù)據(jù)译暂,改變原數(shù)組,有參數(shù)撩炊,返回值是添加過后的數(shù)組長度 ( 不是返回添加的值外永,因為參數(shù)中已經(jīng)知道 )
- pop shift 刪除數(shù)據(jù),改變原數(shù)組拧咳,沒有參數(shù)伯顶,所以返回值是刪除的數(shù)據(jù)值
9. new命令實行后的效果:
- 生成的對象可以訪問構(gòu)造函數(shù)的屬性
- 生成的對象可以訪問構(gòu)造函數(shù)prototype上的屬性
10. 手寫new命令
function Constructor(name, age) {
this.name = name
this.age = age
// 構(gòu)造函數(shù)如果執(zhí)行new命令,默認返回的是this對象
// 這里模擬的是new命令,所以手動返回this對象
// 如果返回其他對象祭衩,不是this對象灶体,需要在構(gòu)造函數(shù)返回值中做判斷
return this
}
Constructor.prototype.address = function() {
console.log('shanghai')
}
function _new() {
const obj = new Object()
// 等于 const obj = {}
// 等于 const obj = Object.create(null) ------- 以null為原型,生成實例對象
const paramsConstructor = Array.prototype.shift.call(arguments)
// 等于 [].prototype.shift.call(arguments)
// 等于 Array.prototype.shift.apply(arguments)
// shift 刪除數(shù)組的第一個參數(shù)掐暮,改變原數(shù)組蝎抽,返回被刪除的值 ---------- push, unshift 返回被添加刪除的值
// unshift 在數(shù)組的最前面添加數(shù)據(jù),返回添加過后數(shù)組的長度 ---------- pop, shift 返回更新后的數(shù)組長度
// 把arguments對象中的構(gòu)造函數(shù)參數(shù)取出
obj.__proto__ = paramsConstructor.prototype
// 將空對象的隱式原型指向構(gòu)造函數(shù)的顯示原型
const res = paramsConstructor.apply(obj, arguments)
// 將構(gòu)造函數(shù)中的this指向空對象
// 空對象就能訪問構(gòu)造函數(shù)中的屬性
// apply第二個參數(shù)是數(shù)組路克,但是類似數(shù)組的對象也可以织中,會轉(zhuǎn)化成數(shù)組
return /Object/.test(Object.prototype.toString.call(res)) ? res : obj
// 如果構(gòu)造函數(shù)的返回的是一個和this無關(guān)對象則返回該對象,即res(this對象也返回)
// 如果返回不是對象衷戈,就返回this對象,即空對象ojb
}
const b = _new(Constructor, 'wu', 10)
console.log(b)
1.https://github.com/mqyqingfeng/Blog/issues/13
-
new命令可以用Object.setPrototypeOf()方法來模擬
function A() {
this.name = 'wang'
}
const a = new A()
----
const resa = Object.setPrototypeOf({}, A.prototype) --------------- 將A.prototype設(shè)置成空對象的原型對象
A.call(resa) ------------------------------------------------------ 將構(gòu)造函數(shù)中的this指向空對象层坠,并執(zhí)行構(gòu)造函數(shù)
(2) 原型鏈
- 原型對象的作用: 定義所有實列對象所共享的屬性和方法
- 所有對象都是 Objecr.prototype 的實例殖妇,所有對象都有toString和valueOf方法,因為都繼承了Object.prototype上的這兩個方法
-
Object.prototype.__proto__ === null
null沒有任何屬性和方法破花,也沒有自己的原型谦趣,原型鏈到此中止 - constructor屬性定義在prototype上,所以construstor能被所有實例對象所共享
即a.constructor === A.prototype.constructor = A
- constructor屬性的作用
constructor的作用就是得知:實例對象到底是由哪個構(gòu)造函數(shù)產(chǎn)生的
- 有了constructor屬性座每,就可以從一個實例新建另一個實例
特殊的原型鏈
特殊的原型鏈:
結(jié)論:
(1) 所有 ( 函數(shù)對象 ) 都是 ( Function構(gòu)造函數(shù) ) 的實例
- 所以 Function.__proto__ === Function.prototype
- 所以 fn.__protot__ === Function.prototype
- 所以 Function instanceof Function // true
(2) 所有函數(shù)的prototype對象都是Obect構(gòu)造函數(shù)的實例(!但是Object除外)
- Function.prototype instanceof Object // true
- function.prototype.__proto__ === Object.prototype
- Object.protype instanceof Object // false
(3)
Function instanceof Function ------------------- true
Function instanceof Object ------------------- true
Object instanceof Object ------------------- true
Object instanceof Function ------------------- true
原型鏈
20170503152146141.png
(3)Object對象的相關(guān)方法
1. Object.getPrototypeOf
Object.getPrototypeOf()返回參數(shù)對象的原型對象前鹅,是獲取原型對象的標準方法
Object.getPrototypeOf(params) 返回參數(shù)對象的原型對象,是獲取原型對象的標準方法
function A() {}
const a = new A()
const res = Object.getPrototypeOf(a)
console.log(a.__proto__ === res) // true
console.log(A.prototype === res) // true
2. Object.setPrototypeOf(origin, pro)
將第二個參數(shù)設(shè)置成第一個參數(shù)的原型峭梳,返回該參數(shù)對象即第一個對象
Object.setPrototype(a,b) 將b對象設(shè)置成a對象的原型對象舰绘,返回值是a對象
const a = {}
const b = {name: 'wang'}
const res = Object.setPrototypeOf(a, b)
console.log(res) // {}
console.log(Object.getPrototypeOf(a)) // {name: 'wang'}
Object.setPrototypeOf(a, b)可以用來模擬new命令
function A() {
this.name = 'wang'
}
const a = new A()
----
const resa = Object.setPrototypeOf({}, A.prototype) --------------- 將A.prototype設(shè)置成空對象的原型對象
A.call(resa) ------------------------------------------------------ 將構(gòu)造函數(shù)中的this指向空對象,并執(zhí)行構(gòu)造函數(shù)
3. Object.create()
Object.create()以參數(shù)對象為原型葱椭,返回實例對象
以下生成對象的方式等價
Object.create({})
Object.create(Object.prototype)
new Object()
如果想要生成不繼承任何屬性的對象捂寿,可以用如下寫法
var obj = Object.create(null)
obj.valueOf()
// TypeError: Object [object Object] has no method 'valueOf'
因為obj的原型是null,所以obj不具備 Object.prototype上掛在的屬性和方法孵运,比如 valueOf秦陋,toString
Object.create()參數(shù)必須是個對象,不能為空或者不是對象
4. Object.prototype.isPrototypeOf
實例對象的isPrototypeOf用來判斷該對象是否為參數(shù)對象的原型
var o1 = {};
var o2 = Object.create(o1); // o1是o2的原型對象
var o3 = Object.create(o2); // o2是o3的原型對象
o2.isPrototypeOf(o3) // true ---------------------- 實例對象的isPrototypeOf用來判斷該實例對象是否是參數(shù)對象的原型
o1.isPrototypeOf(o3) // true