對象是一組沒有特定屬性的值,對象的每個屬性或方法都有一個名字,而每個名字都映射到一個值,其中值能夠是數據或函數。每個對象都是基於一個引用類型建立的,這個引用類型能夠是原生類型,也能夠是開發人員自定義的類型。——高程
(好的,這裏說的比較不容易理解)javascript
(不急,接下來再看)java
JavaScript中,一切都是對象,函數也是對象,數組也是對象,可是數組是對象的子集,而對於函數來講,函數與對象之間有一種「雞生蛋蛋生雞」的關係。全部的對象都是由Object繼承而來,而Object對象倒是一個函數。對象都是由函數來建立的。數組
好比,在控制檯中
輸入 typeof Object 結果是"function",
輸入 typeof Function 結果仍是"function".瀏覽器
(好的,是否是更懵逼了,不急,如今先看一下怎麼建立對象以及各類方法的孰優孰劣)安全
var box=new Object(); //建立一個 Object 對象 box.name='Lee'; //建立一個 name 屬性並賦值 box.age= 100; //建立一個 age 屬性並賦值 box.run= function(){ //建立一個run()方法並返回值 return this.name + this.age; }; console.log(box.run()); //輸出屬性和方法的值
優缺點:app
fuction creatPerson(name,age,job){ var o = new Object(); //建立對象 o.name = name; //添加屬性 o.age = age; o.job = job; o.sayName = function(){ //添加方法 console.log(this.name); } return o; //返回對象引用 } var person1 = creatPerson("Nicholas",29,"engineer");//實例化 var person2 = creatPerson("Mike",28,"teacher");
優缺點:函數
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ console.log(this.name); } } //或 function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName;//注意這裏不要寫括號,要實現引用地址一致 } function sayName(){ console.log(this.name); }//這裏是在外面寫一個,但這種方法會有做用域問題,十分不推薦 var person1 = new Person("Nicholas",29,"Engineer");//通常這樣實例化 var o = new Object;; Person.call(o,"Kkresten",25,"Nurse");//對象冒充法實例化
區別:學習
規範this
優缺點spa
全局做用域中定義的函數只能被某個對象調用,這讓全局做用域有點名存實亡,並且,若是對象須要定義不少方法,那麼就要定義不少個全局函數,因而,這個自定義的引用類型就絲毫沒有封可言了(函數定義在外部時)。(因此函數在內部和外部都有缺點)
(好的,學到這裏,你已經大致掌握了怎麼建立一個對象,接下來將開始學習建立對象高大上的方法和概念)
咱們建立的每一個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,(屬性值是對象)而這個對象的用途是包含能夠由特定類型的全部實例共享的屬性和方法。:prototype 經過 調用構造函數而建立的那個對象的原型對象。使用原型的好處可讓全部對象實例共享它所包含的屬性和方法。也就是說,沒必要在構造函數中定義對象信息,而是能夠直接將這些信息 添加到原型中。———高程
(好的,又回到了懵逼的狀態了,不急,先經過例子和圖來了解一下先)
function Person(){//構造函數 } Person.prototype.name = "Nicholas";//添加原型屬性 Person.prototype.age = 29; Person.prototype.job = "software Engineer"; Person.prototype.sayName = function() {//添加原型方法 console.log(this.name); } var person1 = new Person(); //實例化 person1.sayName(); //「Nicholas」 var person2 = new Person(); //實例化 person2.sayName();//"Nicholas"
以下圖:
而我本身畫了個圖來加深一下認識(結合高程裏的那段話)
(是否是有點懂了,接下來再逐個仔細分析)
1.對於[[Prototype]]
注意:函數也是對象,天然它也有__proto__。
在控制檯中,咱們發現:
即函數的__proto__是函數類型。(也就說函數的原型對象是函數,而函數也是對象,因此函數的原型仍是對象)(這裏聽着有點繞,可是能夠先跳過)
還要注意一個特例,以下圖:
這裏,一切對象繼承自Object,而咱們又知道Object.prototype是它的原型對象,是一個對象,可是這個對象的__proto__卻爲null,是否說明構建Object對象的函數沒有原型對象,由於對象都是由函數建立的
(對於函數與對象的關係和涉及到的原型鏈的相關知識,還挺大挺深的,將單獨做爲一個話題來討論。若是這裏有點看得暈,能夠先只是知道prototype是什麼就能夠了)
注意: __proto__這個指針沒有標準的方法訪問,IE 瀏覽器在腳本訪問[[Prototype]]會不能識別,火狐和谷歌瀏覽器及其餘某些瀏覽器均能識別。雖然能夠輸出,但沒法獲取內部信息。([[Prototype]] 也可寫爲__proto__)雖然沒法訪問到,可是能夠經過: Object.isPrototypeOf(person1)判斷這個實例對象是否指向它的原型對象 ;而咱們也知道Person.prototype就是Object類型,即一個原型對象
//承接上面的代碼 Person.prototype.isPrototypeOf(person1);//true Person.prototype.isPrototypeOf(person2);//true
2.對於原型模式的執行流程:
①先檢查這個對象自身有無這個屬性;若是有,直接使用它。
②若是沒法在對象自身找到須要的屬性,就會繼續訪問對象的[[Prototype]]鏈,找到則直接使用,再也不查找下去;若是一直找不到,最後就會返回undefined
3.能夠經過 hasOwnProperty()方法檢測屬性是否存在實例中,也能夠經過 in 來判斷 實例或原型中是否存在屬性;能夠經過Object.keys()方法或Object.getOwnPropertyNames()來獲得實例屬性,具體見高程。
4.優缺點:每添加一個屬性和方法就要敲一遍Person.prototype,並且視覺上說封裝性不夠好。固然優勢就是解決了上面構造函數的問題。
5.更簡單的原型模式
function Person(){ } Person.prototype = { //將 Person.prototype 設置爲等於一個以對象字面量形式建立的新對象 name : "Nicholas", age: 29, job: "software Engineer", sayName : function() { console.log(this.name); } } //(但constructor屬性再也不指向Person了,而是指向Object構造函數) //但能夠這樣手動設置: function Person(){ } Person.prototype = { constructor : Person,//手動設置 name : "Nicholas", age: 29, job: "software Engineer", sayName : function() { console.log(this.name); } } //由於按上面的方式會致使它的[[Enumerable]]特性被設置爲true,因此還能夠像下面這樣 function Person(){ } Person.prototype = { name : "Nicholas", age: 29, job: "software Engineer", sayName : function() { console.log(this.name); } } Object.definePrototype(Person.prototype,"constructor"),{ enumerable : false; value : Person } }
6.原型的動態性:
//承接上面的Person構造函數 var friend = new Person(); Person.prototype.sayhi = function(){ alert("hi"); }; friend.sayhi(); //"hi"沒有問題,雖然是在實例以後添加的屬性,可是根據原型模式的搜索機制,會找到原型中的這個方法,緣由:實例與原型是鬆散鏈接的
//可是:若是是這樣: function Person(){ } var friend = new Person(); Person.prototype = { name : "Nicholas", age: 29, job: "software Engineer", sayName : function() { console.log(this.name); } } friend.sayName();//Uncaught TypeError: friend.sayName is not a function,雖然有將重寫的原型的指針指向Person原型對象,可是很實際上卻以下圖:
6.優缺點:
function Person(){ } Person.prototype = { constructor : Person, name : "Nicholas", age: 29, job: "software Engineer", friend:["Mike","Jeny"], sayName : function() { console.log(this.name); } } var person1 = new Person(); var person2 = new Person(); person1.friend.push("Van"); console.log(person1.friend);//"Mike,Jeny,Van" console.log(person2.friend);//"Mike,Jeny,Van"
function Perosn(name,age,job){ this.name = name; this.age = age; this.job = job; this.friends = ["Shelby","Court']; } Person.prototype = { constructor : Person, sayName : function(){ console.log(this.name); } } var person1 = new Person("Nicholas",29," Engineer");
優缺點:
## 5.動態原型模式 ##
function Person(name,age,job){ //屬性 this.name = name; this.age = age; this.job = job; //方法 if(typeof this.sayname != "function"){ Person.prototype.sayname = function(){ console.log(this.name);//只有在sayName方法不存在的狀況下才會被添加到原型中 } } //這段代碼在初次調用構造函數時纔會執行,此後,原型已經初始化 var friend = new Person("Nicholas",29,"Engineer");
優缺點:
(好了,學到這裏,大概經常使用的建立對象的方法就已經掌握了,接下來還有兩種不經常使用的方法能夠了解一下)
function Person(name,age,job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ console.log(this.name); } return o; } var friend = new Person("Nicholas",29,"Software Engineer"); function SpecialArray(){ //建立數組 var values = new Array(); //用push方法初始化數組的值 values.push.apply(values,arguments); //添加方法 values.toPipedString = function(){ return this.join("|"); } //返回數組 return values; } var colors = new SpecialArray("red","blue","green"); console.log(colors.toPipedString()); //"red|blue|green"
優缺點:
console.log(friend instanceof Person) // false
所以,可使用其餘模式的狀況下不使用此類型
function Person(name,age,job){ //建立要返回的對象 var o = new Object(); //能夠在這裏定義私有變量和函數 //添加方法 o.sayName = function(){ console.log(name); } //返回對象 return o; } var friend = Person("Nicholas",29,"Software Engineer"); friend.sayName();
區別:
優勢:安全
(好了,js對象的建立就大概有這幾種方法,其實最經常使用的貌似仍是構造函數的模式,可是原型相關的東西也是必需要掌握的)
最後,歡迎你們圍觀指正!