原型和原型鏈
原型
- 所有的
變量
都有一個(gè)隱式原型proto屬性(錯)
- 所有的
對象
都有一個(gè)隱式原型proto屬性(對)
- 所有的
函數(shù)
都有一個(gè)顯式原型prototype屬性(錯)
- 所有的
構(gòu)造函數(shù)
都有一個(gè)顯式原型prototype屬性(對)
- 屬性值:原型對象
-
構(gòu)造函數(shù)
的prototype
指向一個(gè)空的Object對象(錯)
- 所有
構(gòu)造函數(shù)
的prototype
的__proto__
指向Object的prototype(對)
將偽數(shù)組轉(zhuǎn)化為真數(shù)組&怎么判斷一個(gè)變量是不是數(shù)組
- 它從 Array.prototype 中繼承了一些它的專屬方法,如 push() , pop() , sort() , slice() , splice() 等,這些方法在偽數(shù)組和Object對象中是沒有的。
- slice方法返回一個(gè)從開始到結(jié)束(不包括結(jié)束)選擇的數(shù)組的一部分淺拷貝到一個(gè)新數(shù)組對象伞鲫。原始數(shù)組不會被修改。
-
obj instanceof Array
可以判斷是否為數(shù)組
var arr = {length:3,0:"a",1:"b",2:"c"};
arr.push('d');//報(bào)錯 偽數(shù)組不能使用數(shù)組的方法
var arr2 = Array.prototype.slice.call(arr);
arr2.push("d")
console.log(arr2)
默認(rèn)值
- Array.prototype指向一個(gè)空數(shù)組
- Function.prototype指向一個(gè)空的Function
-
map()
方法創(chuàng)建一個(gè)新數(shù)組签舞,其結(jié)果是該數(shù)組中的每個(gè)元素都調(diào)用一個(gè)提供的函數(shù)后返回的結(jié)果秕脓。
-
join()
方法將數(shù)組(或一個(gè)類數(shù)組對象)的所有元素連接到一個(gè)字符串中。
function test(arr,fn){
arr =arr||Array.prototype;
fn =fn||Function.prototype;
return arr.map(fn).join(" ");
}
console.log(test());
==
的使用規(guī)則
- 引用數(shù)據(jù)類型進(jìn)行比較時(shí):
- 先調(diào)用本身的valueof(),如果valueof方法返回的基本數(shù)據(jù)類型則直接做比較
- 如果valueof()返回的不是基本數(shù)據(jù)類型,則調(diào)用比較對象本身的tostring()
- 基本數(shù)據(jù)進(jìn)行比較時(shí):
- 先通過number()轉(zhuǎn)化成一個(gè)number類型后再做比較
//正常情況下[""]的valueof方法返回原數(shù)組[""]
再調(diào)用[""].tostring()返回""
再調(diào)用number()返回0
console.log([""]==false)//true
//方法的重寫
Array.prototype.valueof = function(){
return 1;
}
console.log([""]==flase)//false
原型鏈的繼承
- 模擬jQuery中的
html()
on()
- 體現(xiàn)出jQuery的鏈?zhǔn)秸{(diào)用 讀寫二合一
//構(gòu)造函數(shù) new Element()--->返回一個(gè)真實(shí)的dom節(jié)點(diǎn)
function Element(id){
this.ele = document.getElementById(id);
}
Element.prototype.innerText= function(val){
var ele = this.ele;
if(val){
ele.innerText = val;
return this;//鏈?zhǔn)秸{(diào)用
}else{
return ele.innerText;
}
}
Element.prototype.on = function(val,fn){
var ele = this.ele;
if(ele.addEventListener){
ele.addEventListener(val,fn);
return this
}
}
var textNode = new Element("test");
textNode.innerText("text")//寫
textNode.innerText("text").innerText()//鏈?zhǔn)秸{(diào)用
console.log(textNode.innerText("text").innerText())//讀
textNode.on("click",function(){
alert(1);
}).innerText('text')
綜合面試題
//運(yùn)算符的優(yōu)先級
//左右查詢
//原型鏈
//this
//屬性的查找
//提升
function getName() {
alert (5);
}
function Foo() {
getName = function () { alert (1); };
return this;
}
Foo.getName = function () {
alert (2);
};
Foo.prototype.getName = function () {
alert (3);
};
var getName = function () {
alert (4);
};
Foo.getName(); //2
getName();//4
Foo().getName(); //1
getName(); //1
new Foo.getName(); //2
new Foo().getName()//3
原型&原型鏈
- 原型對象:它不是一個(gè)空的Object對象儒搭,但是它的proto永遠(yuǎn)指向Object的prototype
- 原型鏈的頭
Object.prototype.__proto__===>null
Function.__proto__ === Function.prototype
Object.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__=== null
javascript中的屬性
變量的查找
屬性描述符(元屬性)
- 修飾屬性的屬性(元屬性)
- 獲取對應(yīng)屬性的描述符
-
Object.getOwnPropertyDescriptor(obj,"name")
第一個(gè)參數(shù):對應(yīng)的對象;第二個(gè)參數(shù):對應(yīng)對象的屬性
-
writable
決定是否可以修改屬性的值
- 一般和value綁定在一起
- 當(dāng)writable為false時(shí),對應(yīng)的屬性的值是無法修改的搂鲫。
在默認(rèn)情況下:繼續(xù)修改的話會靜默失敗
在嚴(yán)格模式下:會報(bào)錯
-
configurable
來決定屬性是否可以配置
- 是否可以被delete
- 刪除
configurable:true 可以刪
configurable:false 不可以刪
- 重新配置
能不能重新定義屬性的描述符
configurable:true 可以重新配置
configurable:false
writable可以從true變?yōu)閒alse
其他兩個(gè)屬性不可以動
var damu={};
Object.defineProperty(damu,"age",{
value:18,
writable:true
})
Object.defineProperty(damu,"age",{
value:19,
configurable:true//報(bào)錯
})
console.log(damu)//age:19
var a=3;
b=4;
console.log(Object.getOwnPropertyDescriptor(window,"a"))
console.log(Object.getOwnPropertyDescriptor(window,"b"))
delete a;//a configurable:false不能刪除
delete b;//b configurable:true可以被刪除
console.log(a)//3
console.log(b)//報(bào)錯
-
enumerable
可枚舉:能否出現(xiàn)在對象的for in循環(huán)
- 判斷屬性是否可枚舉
(不會遍歷原型鏈)obj.propertyIsEnumerable("a")
- 獲取可枚舉屬性列表
(不會遍歷原型鏈)Object.keys(obj)
- 獲取所有屬性的列表
(不會遍歷原型鏈)Object.getOwnPropertyNames(obj)
var damu={};
Object.defineProperty(damu,"a",{
enumerable:false
})
Object.defineProperty(damu,"b",{
enumerable:true
})
Object.defineProperty(damu,"c",{
enumerable:true
})
Object.defineProperty(damu,"d",{
enumerable:true
})
Object.defineProperty(damu,"e",{
enumerable:false
})
Object.defineProperty(damu,"f",{
enumerable:false
})
for(item in damu){
console.log(item);//輸出b,c,d
}
for(item in damu){
if(damu.hasOwnProperty(item)){
console.log(item);
}
}
Object.defineProperty(Object.prototype,"text",{
value:"text"
enumerable:true
})
console.log(damu.text)//text可以找到
console.log(damu.propertyIsEnumerable("f"))//false
console.log(damu.propertyIsEnumerable("text"))//false不會在原型鏈上找
console.log(Object.keys(damu))傍药;//可枚舉類型(不會在原型鏈上找)
console.log(Object.getOwnPropertyNames)//所有屬性列表(不會在原型鏈上找)
定義對象屬性的兩種方法
var damu={
wife:"zdy"
}
damu.wife="fbb";
console.log(damu);
var damu={}
Object.defineProperty(damu,"age",{
value:18
})
console.log(damu);
對象的不變性
對象的常量屬性
- 將屬性的
writable
和configurable
設(shè)置為false
禁止對象擴(kuò)展
-
Object.preventExtensions(obj)
傳入一個(gè)對象
密封對象
- 在禁止對象擴(kuò)展Object.preventExtensions(obj)的基礎(chǔ)上把現(xiàn)有屬性的configurable都調(diào)整為false
- 調(diào)用
Object.seal(obj)
密封一個(gè)對象
- 密封之后禁止了對象去擴(kuò)展屬性,原有的屬性不可以進(jìn)行重新定義或者刪除魂仍,但屬性值是可以修改的
冰封對象
- 在密封對象(Object.seal(obj))的基礎(chǔ)上把現(xiàn)有屬性的writable都調(diào)整為false
- 調(diào)用
Object.freeze(obj)
密封一個(gè)對象
- 凍結(jié)之后禁止了對象去擴(kuò)展屬性拐辽,原有的屬性不可以進(jìn)行重新定義或者刪除,屬性值不可以進(jìn)行修改
深度凍結(jié)對象
- 在js中2磷谩Qρ怠!所有方法的創(chuàng)建都是淺不變形的仑氛,他們只會影響目標(biāo)對象和他的直接屬性
- 一般項(xiàng)目中不會深度凍結(jié)對象(如果需要使用,考慮是不是設(shè)計(jì)錯誤)
- 如果使用深度凍結(jié)對象時(shí)需要使用
for in
一直循環(huán)
var obj={
hoddy:{
hoddy1:"a",
hoddy2:"b",
hoddy3:"c",
hoddy4:"d",
hoddy5:"e"
}
};
Object.freeze(obj);
obj.hoddy.hoddy1 = "g"http://hoddy1會發(fā)生改變
console.log(obj)
for(item in obj){
Object.freeze(obj[item]);
}
存在性檢查
- in(會遍歷原型鏈)
"a" in obj
- hasOwnProperty(不會遍歷原型鏈,只在對象中查找)
obj.hasOwnProperty("a")
訪問描述符
- 當(dāng)你給一個(gè)屬性定義
set
或者get
锯岖,或者兩者都有時(shí)介袜,這個(gè)屬性會被定義為訪問描述符
- 對于訪問描述符來說,Javascript會忽略他們的
value和writable
特性出吹。取而代之的是set和get函數(shù)遇伞。
-
value writable
和set get
只能有一組
- 訪問描述符可以使我們在對屬性進(jìn)行取賦值操作時(shí)預(yù)先變規(guī)定邏輯(比如if else)
- 訪問描述符可以使我們的屬性變的更加安全!4防巍p椤!封裝
總結(jié)
- 屬性描述符
用來修飾屬性的屬性(元屬性) 5個(gè)
- 數(shù)據(jù)描述符
具有writable和value屬性描述符的屬性 我們稱之為數(shù)據(jù)描述符
- 訪問描述符
具有set和get屬性描述符的屬性 我們稱之為訪問描述符
-
writable為true的數(shù)據(jù)描述符
- 屬性的查找:在實(shí)例對象的直接屬性沒有找到對應(yīng)的屬性則上原型鏈秋麸,如果整條原型鏈都沒有該屬性渐排,返回undefined
- 屬性的設(shè)置:不管什么情況,設(shè)置操作只會影響對象的直接屬性
屬性的查找
- 在對象中查找是否具有相同名稱的屬性灸蟆,如果找到驯耻,就會返回這個(gè)屬性的值。
- 如果沒有找到炒考,則遍歷原型鏈
- 無論·如何都沒找到可缚,返回undefined
屬性的設(shè)置
-
如果屬性直接存在于對象中 不在原型鏈上(或者屬性直接存在于對象中 也在原型鏈上) 找到直接存在于對象中的屬性
- 數(shù)據(jù)描述符(沒有setter/getter):直接修改對象中的屬性的值(注意writbale的值)
- 訪問描述符:直接調(diào)用set方法
-
如果屬性不直接存在于對象中 在原型鏈上
- 該屬性是數(shù)據(jù)描述符(沒有setter/getter)
- writbale為true
直接在對象中添加一個(gè)屬性,我們稱之為屏蔽屬性
- writbale為false
報(bào)錯斋枢,不會生成屏蔽屬性
- 該屬性是訪問描述符
調(diào)用set帘靡,不會生成屏蔽屬性
- 如果屬性不直接存在于對象中 也不在原型鏈上 在對象的直接屬性中添加一個(gè)屬性(數(shù)據(jù)描述符)