聲明本文僅用于學(xué)習(xí)交流,切勿用作其他用途。
[TOC]
js 本來(lái)是沒(méi)有對(duì)象的,不知道是不是因?yàn)閱紊砭昧?,所以被迫有了?duì)象。
對(duì)象創(chuàng)建
對(duì)象創(chuàng)建一般我們都是通過(guò)new function來(lái)的,Es6中可以直接寫(xiě)class,這樣子用法就是new一個(gè)class了。
當(dāng)然也可以使用Object.create 和 Object.assign
對(duì)象的屬性行為,這可是很有意義的
說(shuō)到這個(gè)屬性行為呀,我想起了基礎(chǔ)數(shù)據(jù)類(lèi)型的Symbol,以這個(gè)Symbol作為key值的對(duì)象,通過(guò)for...in 是拿不到這個(gè)Symbol的,不信大可以試試如下代碼
var smb = Symbol("key1");
var a = {};
a[smb] = "hello wolrd";
console.log(Object.keys(a)) ;//看看這里是不是打印的[]就知道啦
//之前說(shuō)過(guò)哦,要通過(guò)Object.getOwnPropertySymbols才能拿到哦
console.log(Object.getOwnPropertySymbols(a)) ;//[Symbol(key1)]
對(duì)于對(duì)象的屬性行為,目前有 configurable,writable,enumerable,value
這個(gè)屬性行為,其實(shí)說(shuō)白了,和c++成員私有公有差不多的感覺(jué),對(duì)于大家使用 Object.defineProperty的情況我不是很清楚,但是至少在我看到 '怎么在Es5中定義常量' 之前我是沒(méi)怎么使用的,都是用已有的一些類(lèi)呀什么直接拿過(guò)來(lái)用,或者直接把類(lèi)當(dāng)做hashMap來(lái)用...
定義常量
//瀏覽器下面可以用下述方法設(shè)置常量。
function setConst(name,value,log){
(log === undefined) && (log = true);
if(typeof name == 'string' && !name){
if( !window.hasOwnProperty(name)){
Object.defineProperty(window,name,{
configurable:false,//避免用defineProperty修改
writable:false,//不可寫(xiě)入
value:value
})
}else{
log && console.warn("const variable name",name,"already exists")
}
}else{
log && console.warn("name",name," is illegal")
}
}
//useage
setConst("Five",5);
console.log(Five);//5
setConst("Five",6);
console.log(Five);//5
Five = 7;
console.log(Five);//5
如上所示,js可以設(shè)置類(lèi)的可寫(xiě)屬性,枚舉屬性,是否可以修改對(duì)象屬性的屬性,以及值。
configurable
為false的時(shí)候,delete,defineProperty操作無(wú)效
writable
為false的時(shí)候 字面意思,不可更改,重新賦值無(wú)效
enumerable
為 false時(shí),不出現(xiàn)在枚舉列表,即Object.keys() 不能拿到對(duì)應(yīng)的key
value
默認(rèn) undefined ,如字面意思,值
對(duì)象創(chuàng)建方式
- new function
- Object的操作,如Object.assign ,Object.create
- 直接以JSON的形式創(chuàng)建 --如 var a = { h:xxx }
- new class --等價(jià)于new function
new function
function T(){
}
var t = new T();//new function的時(shí)候返回的是一個(gè)類(lèi)
var r = T();//這種情況就是執(zhí)行一個(gè)function,沒(méi)有new就是普通執(zhí)行
//----------------------------------------------------
function F(){
(typeof this != 'undefined') && (this.t = "hello");
//如果這里沒(méi)有返回或者返回不是對(duì)象,那么使用new的時(shí)候就返回this對(duì)象,
//如果這里返回了對(duì)象,那就不會(huì)返回this了
///////////////////////////////////////////////////
var t = {t:"test"};
return t;//這樣寫(xiě)就是在玩火。不管怎么new,都是返回{t:"test"}這個(gè)對(duì)象,雖然引用不一樣
///////////////////////////////////////////////////
}
var t = new F();//或者F()
console.log(t.t);//‘test’
//----------------------------------------------------
function G(){
if(new.target){ //我們可以這樣檢驗(yàn)調(diào)用的時(shí)候是否使用了new
//....
}
}
Object的操作
Object.creat方法創(chuàng)建一個(gè)新對(duì)象,使用現(xiàn)有的對(duì)象來(lái)提供新創(chuàng)建的對(duì)象的proto。 ;
Object.assign 方法用于將所有可枚舉屬性的值從一個(gè)或多個(gè)源對(duì)象復(fù)制到目標(biāo)對(duì)象。它將返回目標(biāo)對(duì)象。
//////////////////
var b = {k:1,k2:2};
var a = Object.create(b);//這里會(huì)創(chuàng)建對(duì)象a,把b作為a的原型,
console.log(a.k,a.k2,a.__proto__ == b)
b.k = 3,b.k2 = 4;
console.log(a.k,a.k2);// 3,4
var c = Object.create(a,{
key1:{
value: "this is a test case",
writable: true,
enumerable: false,
configurable: true
},
key2:{
value: "this is read-only value",
writable: false,
enumerable: true,
configurable: true
}
});//這里會(huì)把a(bǔ)作為c的原型,并且增加val屬性,該屬性的行為可以自行定義
console.log(c,c.key1 ) ;
console.log(c.k,c.k2);//3,4 這個(gè)就涉及到了原型鏈了
/////////////////////
var d = Object.assign(c,{k:6,k2:5},undefined,5,null,"hello",{});
console.log(d) ;// {k:6,k2:5,'0': 'h', '1': 'e', '2': 'l', '3': 'l', '4': 'o'}
//MDN上面說(shuō) 原始類(lèi)型會(huì)被包裝,null 和 undefined 會(huì)被忽略。只有字符串的包裝對(duì)象才可能有自身可枚舉屬性
//拷貝的是引用地址值來(lái)著。原型鏈中的和不可枚舉的都不能拷貝。返回值是目標(biāo)對(duì)象,也就是如下
console.log(c == d);//true
直接以JSON的形式創(chuàng)建
//////////////////
var a = {
key1:"1",
key2:2,
key3:false,
func4:function(){
return this.key1;
}
}
console.log(a.func4())
var b = JSON.parse('{ "t":1,"k":"hello","m":"world"} ')
console.log(b);//{ t: 1, k: 'hello', m: 'world' }
new class
//////////////////
class cls{
set key1(val){
this._key1 = val;
}
get key1(){
return this._key1;
}
constructor(){
this._key1 = "test";
}
}
var a = new cls();
//相當(dāng)于
//function cls(){ this._key1 = "test" };
//var a = new cls();
//Object.defineProperty(a,"key1",{
//set:function(v){ this._key1 = v},get:function(){ return this._key1}
//})
原型鏈與繼承
參照 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain
原型鏈
關(guān)于這個(gè)原型鏈我的理解有些不到位,歡迎大家指出我的錯(cuò)誤的理解,
我的理解大概就是原型鏈就是對(duì)象的一個(gè)查找表,類(lèi)似lua的原表,當(dāng)我們?cè)噲D obj['key1'] 時(shí),會(huì)先在obj下查找key1是否存在,沒(méi)找到的情況再去 obj.__proto__ 去查找,如果還沒(méi)找到則去 obj.__proto__.__proto__ 去查找,依次類(lèi)推,直到找到或者遍歷完原型鏈。
這個(gè)查找的概念就是在使用 obj['key'] 或者 obj.key 時(shí)執(zhí)行的查找。
var a = { b :1,c:"2" }
var b = Object.create(a);//創(chuàng)建對(duì)象,指定對(duì)象的原型是a,
console.log(b);//{}
console.log(b.b,b.c);//這里在b里面沒(méi)找到b和c屬性,所以去原型鏈找
console.log(b.__proto__ == a);//true
所以我對(duì)原型鏈的理解為:對(duì)象所具有的默認(rèn)值,修改原型鏈中的這個(gè)值(__proto__.xxx)會(huì)影響具有相同原型鏈的其他對(duì)象,但是在自身增加對(duì)象則會(huì)覆蓋這個(gè)值,如下
function T(){
}
T.prototype.test = 1;
var t1 = new T(),t2 = new T();;
console.log(t1.test,t2.test);//1,1
t1.__proto__.test = 2;
console.log(t1.test,t2.test);//2,2
t2.test = "hello";
console.log(t1.test,t2.test);//2,hello
繼承
這個(gè)是個(gè)大問(wèn)題,畢竟js不是面向?qū)ο蟮?/code>,所以感覺(jué)原型鏈很大一部分感覺(jué)是為了繼承而生的。
其操作大概就是 childCls.prototype = parent
我們用Object.create來(lái)創(chuàng)建對(duì)象的時(shí)候,實(shí)際上就是一個(gè)繼承了。只是有時(shí)候可能沒(méi)有那么明確,上面的原型鏈中的數(shù)據(jù),也就是說(shuō)繼承之后的初始值,我們可以在繼承之后去更改這些值。這個(gè)繼承給人的感覺(jué),很隱蔽。