關於原型的一些理解,盡量寫的詳細一點。
學了前端一段時間了,對js當時花了很多時間但是隨著後面學習框架有些就忘了。現在從新開始記錄下重要的知識點。有很多知識也是查閱js高程和別人的博客,所用的一些例子也是引用那些覺得很有代表意義的,在文章最後貼出有關的博客。有錯的地方也請大家指出。有些知識深究的話我能力有限,也不知道;所以很多作為一個結論記住就行。
1.首先什麽是對象,什麽是函數對象。有些地方也叫函數,我查了下函數和函數對象應該是指代的同一個東西,沒有區別。首先
var a={"name":"hello"}; 這是一個普通的對象。 function f1(){}; var f2 = function(){}; 這是函數對象。那麽函數對象和對象又有什麽不同了。函數有個叫原型的東西是個對象,但是對象沒有。這裏引入了 prototype
2,那麽對象和函數對象又有什麽聯系了,首先創建一個普通的對象var person = {}或者var 0=new object()。這是個普通的對象,通過這種字面量可以創造很多單個對象。但是會產生大量重復代碼,所以有了工廠模式的出現。
function creatPerson (name, age) { var person = new Object(); person.name= name; person.age = age; person.sayName = function () { alert(this.name); }; return person;
}
var person1= creatPerson ("tom",29)
他能創建一個包含一些信息的person對象,可以多次調用這個函數。但是卻沒有解決對象的識別問題(不知道這個對象的類型)。所以之後重頭戲來了,有了構造函數,這個知識點就涉及原型了。
function CreatePerson(name, age, say){ this.name = name;this.age = age; this.say = say; this.should = function(){ console(this.say); } } var person1 = new CreatePerson("","","");
這個函數也很簡單,但是和之前的工廠模式有了些區別。這個函數有個很重要的 new 操作符。看一個實例:
function Animal(name){ this.name = name; } Animal.color = "black"; Animal.prototype.say = function(){ console.log("I‘m " + this.name); }; var cat = new Animal("cat"); console.log( cat.color, //undefine cat.name //cat ); cat.say(); //I‘m cat console.log( Animal.name, //Animal Animal.color //back ); Animal.say(); //Animal.say is not a function
這個函數沒看答案之前有可能你是不太清楚,但是看了答案你是應該是能得出一些結論的。雖然你可能不知道發生了什麽。首先 console.log( Animal.name, //Animal Animal.color //back ); 這個比較簡單沒什麽說的,不懂的函數的name屬性可以看下。 cat.color, //undefine 這個是重點,這裏看的出來構造出來的實例並沒有繼承到color這個屬性,那麽就要引入構造函數的工作的模式了。關鍵的new字符,js高程是這麽解釋的:
1‘創建一個新的對象;
2‘將構造函數作用域賦給新的對象(即this指向新對象);
3‘執行構造函數裏面的代碼;
4‘返回新的對象。
new Animal("cat") = { var obj = {}; obj.__proto__ = Animal.prototype; var result = Animal.call(obj,"cat"); return typeof result === ‘object‘? result : obj; }
這是一個模仿new運行機制的偽代碼,這裏我們看到一個新的東西出現了 __proto__ ,先給這個過程看完:obj的__proto__ 指向Animal的原型對象prototype然後你大概懂了
cat.say(); //I‘m cat 之後,在obj對象的執行環境調用Animal函數並傳遞參數“cat”。 相當於var result = obj.Animal("cat")。 當這句執行完之後,obj便產生了屬性name並賦值為"cat"。可能第二個你看的不太明白那你就可以看看call屬性,以及this了。這裏先不提,後面可以在仔細做下筆記。引入了__proto__ 那麽就相當於引入了原型鏈了,當你實例化一個對象,就會形成一個原型鏈,他會去找構造函數的prototype,然後逐級向上尋找,其實原型的重點是__proto__ ,我這裏將引入一兩道例題幫助自己記憶,以及自己的理解。
var animal = function(){}; var dog = function(){}; animal.price = 2000; dog.prototype = animal; var tidy = new dog(); //tidy.constructor=dog;實例tidy可以通過授權找到它並用以檢測自己的構造函數 console.log(dog.price); //undefined console.log(tidy.price); // 2000
1‘首先 dog.prototype = animal;這裏沒有問題的, 我們可以賦值任何類型的對象到原型上,但是不能賦值原子類型的值, 比如如下代碼是無效的: Foo.prototype = 1;
2‘將 animal的值賦給dog的原型對象。 console.log(dog.price);針對這句代碼。首先是dog自己的本身的函數是沒price這個屬性的,然後原型上有,但是兩者是沒有關系的。
3’ 它先通過查找自生,然後再循著__proto__去原型鏈中尋找,全局中也沒有,都沒有所以讀取不到price這個屬性。
var Animal = function(){}; Animal.prototype.say = function(){ alert("a"); }; Animal.say() //Animal.say s not a function
這個簡短的例子也是能說明問題的,然後在來看下面這個例子:
var animal = function(){}; var dog = function(){}; animal.price = 2000; dog.__proto__ = animal; var tidy = new dog(); console.log(dog.price) //2000 console.log(tidy.price) // undefined
1. dog.__proto__ = animal;直接找到 animal,獲取值dog.price==2000;
2. tidy.__proto__= dog.prototype;
3. tidy.__proto__.__proto__ === dog.prototype.__proto__=== Object.prototype;通過這個原型鏈確實找不到。這裏要區別prototype和__proto__
今天寫的很淺,還有很多問題都沒有涉及,睡了還是寫了很久。明天繼續寫原型這部分的,然後遇到的this,call這些也會寫,慢慢來每天寫點。
關於原型的一些理解,盡量寫的詳細一點。