一、對象的特點
對象,就是類。類,就是具有相同的屬性和方法。但是,js里面沒有類的概念。
ヾ(=・ω・=)o 孔乙己曾經說過,茴香豆的“茴”字有4種寫法,那么作為‘迂腐’的程序員,也得知道js創建對象的常用4種方法吧! ヾ(=・ω・=)o
二、js創建對象的方法
js創建對象常用的有4種方法,Object構造函數、對象字面量和工廠函數、自定義構造函數模式。
前兩個一次只能創造一個對象,后兩個可以大批量創造對象。
工廠函數:沒有辦法檢驗你創建的對象類型。
自定義構造函數模式:可創建特定類型的對象。
1、Object構造函數
//1-Object構造函數 var person1=new Object(); person1.name='Alice'; person1.age=18; person1.sayName=function(){ console.log(this.name); } person1.sayName(); //Alice
構造函數可以用來創建特定類型的對象。也可以創建自定義的構造函數,從而定義自定義對象類型的屬性和方法。按照慣例,構造函數始終是以一個大寫字母開始,非構造函數以小寫字母開頭。
構造函數模式創建的對象會有一個constructor(構造函數)屬性,該屬性指向構造函數。
function Person(name,age,job){ this.name=name; this.job=job; this.age=age; } var p1= new Person("Jin",24,'singer'); var p2 = new Person("NamJoon",23,'artist'); console.log(p1.constructor==Person) //true
instanceof操作符既可以判斷Object類型,又可以判斷Person類型。
console.log(p1 instanceof Object) //true console.log(p2 instanceof Person) //true
2、對象字面量
//2-對象字面量,注意隔開用的是逗號,表示用的是冒號 var person2={ name:'Tony', age:19, sayName:function(){ console.log(this.name); } } person2.sayName();//Tony
3、工廠函數,不是用new操作符,沒有辦法檢查他是什么類型的,只能檢查到他是Object
function person3(name,age,sayName){ var obj=new Object(); obj.name=name; obj.age=age; obj.sayName=function (){ console.log(this.name); } return obj; } var person3_1=person3('NamJoon',24); person3_1.sayName();//NamJoon console.log(person3_1 instanceof Object);//true
4、自定義構造函數,可以檢查到他的函數名稱,這也是他比工廠函數高級的地方
//4-構造函數模式,注意,一定要大寫,與其他方法區分開。方法一般是小寫 function Person4(name,age,sayName){ this.name=name; this.age=age; this.sayName=function(){ console.log(this.name); } } var person4_1=new Person4('Jin',25); var person4_2=new Person4('suga',27); person4_2.sayName();//suga var cons=person4_1.constructor===person4_2.constructor;//注意這個屬性,他們都指向Person4。 console.log(cons);//true console.log(person4_1.constructor);//Person4 //注意,這兩個person的類型既是Person4,也是Object console.log(person4_1 instanceof Object);//true
擴展問題:當你使用new的時候,到底經歷了什么?
(1)創建一個新對象
(2)將構造函數的作用域賦給新對象,因此,this指向這個新對象
(3)執行構造函數中的代碼
(4)返回新對象
//在某個對象的作用域內調用構造函數 var obj=new Object(); Person4.call(obj,'BTS',100); obj.sayName();//BTS
三、構造函數模式本身存在的缺陷——原型模式出現,拯救無法封裝的缺陷
在上面,Person4創建的對象中,有個sayName的屬性,該屬性是個方法。為了簡便,把這個方法拿到全局里,讓sayName這個屬性存儲的只是一個指針,指向全局里的sayName方法。
function Person4(name,age,sayName){ this.name=name; this.age=age; this.sayName=sayName(); } function sayName(){ console.log(this.name); }
如果這個對象有很多方法的話,那不就是要在全局里面寫很多方法了嗎?誰都能調用這些全局方法,那么這個所謂的自定義函數,就違背了封裝性的概念了。所以,原型模式出現了。
function Person(){ } Person.prototype.name='Alice'; Person.prototype.age=18; Person.prototype.sayName=function(){ console.log(this.name); } var person1=new Person(); person1.sayName();//Alice var person2=new Person(); person2.name='王花花'; person2.sayName();//王花花
在上面這段代碼中,構造函數變成了空函數,但是照樣可以用它來生產對象。這是因為,
任何函數,都會有一個prototype屬性。這個屬性,指向函數的原型對象。在js中,函數與對象的關系,可以理解為相等,函數就是對象,對象就是函數。
原型對象是天然美女,沒有加工過的。通過實例化后,不動他的屬性,他就不變。而實例化后,如果又改變了他的屬性,就有點像整容了,他的屬性就變成了他整容之后的樣子。也就是下面的那個‘王花花’。
四、獲取對象里的屬性和方法
兩個:for in 和Object.keys(對象名)
for in返回的是能夠通過對象訪問的、可枚舉的屬性
function Person4(name,age,sayName){ this.name=name; this.age=age; this.sayName=sayName; } function sayName(){ console.log(this.name); } for (var item in Person4){ console.log(item);//Array(3) ["name", "age", "sayName"] } var keys=Object.keys(Person4); console.log(keys);//Array[0],這是為什么呢?就因為沒有給他添加值嗎? var p1=new Person4(); p1.name='alice'; p1.age=19; var p1Keys=Object.keys(p1); console.log(p1Keys);//Array(3) ["name", "age", "sayName"] for(var item in p1){ console.log('item-->'+item);//name,age,sayName console.log(typeof item);//3個string,不是數組 }
-
要取得對象上所有可枚舉的實例屬性,可以使用ES5的Object.keys()方法。該方法會接受一個對象作為參數,返回一個字符串數組。
var person={ name:"NamJoon", age:"24" } var keys = Object.keys(person); console.log("keys-->>",keys) //Array(2) ["name","age"]
補充:單獨使用in操作符時,如果屬性存在,會返回true。
function Person(){ } var p1=new Person(); p1.name="Alice"; console.log("name" in p1) //true