摘要:中創建對象是如何實現的其實通過上面方式,使用構造函數聲明實例的專屬變量和方法,使用原型聲明公用的實例和方法,已經是創建對象的完美解決方案了。
var cat = { name: "tom", info: this.name + ": 1212", getName: function() { return this.name; } };
注意上例屬性info中,使用了this.name,這里的this指向window對象,請盡量避免在定義對象屬性時使用表達式,而將有表達式的內容寫入到函數中。
var dog = new Object(); dog.name = "tim"; dog.getName = function() { return dog.name; }
可以使用delete刪除對象的屬性和方法
delete dog.name;
在window作用域中,不能使用delete刪除var, function定義的屬性和方法,可以刪除沒有使用var, function定義的屬性和方法
在實際使用當中,字面量創建對象雖然很有用,但是它并不能滿足我們的所有需求,我們希望能夠能夠和其他后臺語言一樣創建一個類,然后聲明類的實例就能夠多次使用,而不用每次使用的時候都要重新創建它,于是,便有了工廠模式的出現。
function person(name) { var o = new Object(); o.name = name; o.getName = function() { return this.name; } return o; } var person1 = person("rose"); var person2 = person("jake");
這種模式在函數的內部創建了一個空對象,然后逐一添加屬性和方法,最后返回,實現了對象得以復用的目的。但是存在2個很大的問題
無法識別對象的類型
console.log(person1 instanceof person); // false
每個對象調用的同名方法其實并不同一個方法
console.log(person1.getName == person2.getName); // false
其實就相當于每次聲明對象都被重新創建,只不過寫法上簡單了一點而已。
var Person = function(name) { this.name = name; this.getName = function() { return this.name; } } var person1 = new Person("tom"); var person2 = new Person("tim");
使用var或者function聲明函數都可以,只是我寫例子的時候想到什么就寫了什么,這個區別在這里不是重點
和工廠模式相比,自定義構造函數沒有在函數內部顯示的創建和返回對象,而是使用this,當然,看上去簡潔了許多,那么它解決了工廠模式的什么問題呢?
console.log(person1 instanceof Person); // ture console.log(person1.getName == person2.getName); //false
從上面代碼可以看出,對象的類別可以判斷了,person1就是Person的對象,可是2個同名方法任然不是同一個方法,而是重新創建,其實構造函數內部的實現,可以將上面的代碼寫成這樣來理解
var Person = function(name) { var this = {}; this.name = name; this.getName = function() { return this.name; } return this; }
看上去和工廠模式就有點像,只是this的聲明和返回都是隱式的。下一步,我們將要介紹關鍵先生,原型
原型并沒有那么神秘,因為在javascript中,它無處不在。為了了解原型,我們可以在chrome瀏覽器的console中,隨意創建一個函數
function a(){}
然后繼續輸入
a.prototype
得到的結果如下
a { constructor: function a(), _proto_: Object }
沒錯,得到的這個a,就是關鍵先生原型了。每一個函數都有一個prototype屬性,他就像一個指針一樣指向它的原型,而每一個原型,都有一個constructor屬性,指向他的構造函數。
那么原型在創建對象中有什么用呢?
一個例子,千錘百煉,如下
function Person(name) { this.name = name; } Person.prototype.getName = function() { return this.name; } var person1 = new Person("rose"); var person2 = new Person("Jake");
在這里,我們將屬性寫在了構造函數里,將令人頭疼的方法寫在原型里,看看上面的問題得到解決沒有
console.log(person1 instanceof Person); // true console.log(person1.getName === person2.getName); // true
OK,問題完美解決。
當然也可以將屬性寫入原型中,但是如果那樣的話,屬性就會如同方法一樣被公用了,因此一般來說,屬性會寫入構造函數之中,方法寫入原型之中。當然,這視情況而定。
如果你想進一步了解原型,可以看下圖。
當我們使用new Person時便會創建一個實例,比如這里的person1與person2,這里的實例中,會有一個_proto_屬性指向原型。
原型中的查找機制
當我們使用實例person1調用方法person.getName()時,我們首先找的,是看看構造函數里面有沒有這個方法,如果構造函數中存在,就直接調用構造函數的方法,如果構造函數不存在,才回去查找原型中是否存在該方法
function Cat(name) { this.name = name; this.age = 12; this.getName = function() { return "constructor"; } } Cat.prototype.name = "proto name"; Cat.prototype.getName = function() { return this.name; } var tim = new Cat("Tim"); console.log(tim.name); // tim console.log(tim.getName()); // constructor
可以看到上例中,當原型和構造函數中擁有同樣的方法和屬性的時候,構造函數中的被執行。
于是,這里便會有一個十分重要的概念需要理解,那就是this的指向問題。
在整個創建對象的過程當中,this到底指向誰?
function Person(name) { this.name = name; // this.getName = function() { // return "constructor"; // } } Person.prototype.getName = function() { return this.name; } Person.prototype.showName = function() { return this.getName(); } var rose = new Person("rose"); console.log(rose.showName()); //rose
其實在new執行時,構造函數中的this與原型中的this都被強行指向了new創建的實例對象。
如果需要寫在原型上的方法很多的話,還可以這樣來寫,讓寫法看上去更加簡潔
Person.prototype = { constructor: Person, getName: function(){}, showName: function(){}, ... }
constructor:Person這一句必不可少,因為{}也是一個對象,當使用Person.prototype = {}時,相當于重新定義了prototype的指向,因此手動修正{}的constructor屬性,讓他成為Person的原型。
其實通過上面方式,使用構造函數聲明實例的專屬變量和方法,使用原型聲明公用的實例和方法,已經是創建對象的完美解決方案了??墒俏ㄒ坏牟蛔阍谟?,每次創建實例都要使用new來聲明。這樣未免太過麻煩,如果jquery對象也這樣創建,那么你就會看到一段代碼中有無數個new,可是jQuery僅僅只是使用了$("xxxx")便完成了實例的創建,這是如何做到的呢?
還是按照慣例,先貼代碼。
(function(window, undefined) { var Person = function(name) { return new Person.fn.init(name); } Person.prototype = Person.fn = { constructor: Person, init: function(name) { this.name = name; return this; }, getName: function() { return this.name; } } Person.fn.init.prototype = Person.fn; window.Person = window.$ = Person; })(window); console.log($("tom").getName());
一步一步來分析
首先為了避免變量污染,使用了函數自執行的方式。這種方式讓javascript代碼具備了模塊的特性,因此大多數js庫都會這樣做
(function(){ ... })()
傳入window參數,是為了讓jquery對象在外window中可以被訪問,因此有如下一句代碼
window.Person = window.$ = Person;
這樣我們就可以直接使用$來調用Person構造函數
關鍵問題在于,真正的構造函數并不是Person,而是Person原型中的init方法。其中的復雜關系,我們借助下圖來分析了解,表達能力實在有限,也不知道如何才能表達的更加簡潔易懂。
當外部調用$().getName()時,函數內部的執行順序如下
new Person.fn.init() // 而init的原型,通過下面一句指向了Person的原型 Person.fn.init.prototype = Person.fn; // 于是就可以調用原型中的getName方法了
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/86189.html
摘要:字面量方式這是最簡單最基本的一種方法。簡單的構造函數方式通過這樣的形式創建對象。結合上面的簡單構造函數和原型,一個完整的構造函數應該是這樣的還有一種方法就是提供的簡單實現下中的,,創建一個對象談談對象的理解。避免使用表達式又稱動態屬性。 要點:數據類型、面向對象、繼承、閉包、插件、作用域、跨域、原型鏈、模塊化、自定義事件、異步裝載回調、模板引擎、Nodejs等。 JS基本類型有什么?引...
摘要:接下來該填表了生成行和單元格為了填充表格可以遵循同樣的方法,但這次我們需要迭代數組中的每個對象。對于每個對象,我們可以使用生成單元格。 翻譯:瘋狂的技術宅原文:https://www.valentinog.com/bl... 本文首發微信公眾號:jingchengyideng歡迎關注,每天都給你推送新鮮的前端技術文章 怎樣用原生 JavaScript 生成表格需?本文告訴你答案!...
摘要:在中函數是一等對象,它們不被聲明為任何東西的一部分,而所引用的對象稱為函數上下文并不是由聲明函數的方式決定的,而是由調用函數的方式決定的。更為準確的表述應該為當對象充當函數的調用函數上下文時,函數就充當了對象的方法。 引言:當理解了對象和函數的基本概念,你可能會發現,在JavaScript中有很多原以為理所當然(或盲目接受)的事情開始變得更有意義了。 1.JavaScript...
摘要:點擊直達前文譯一個小時搭建一個全棧應用框架上如果沒有,但還是要繼續學習本教程,可以到我的頁面下載代碼。從服務器返回隨機語言的每當我們與服務器上的端點進行通話時,為了能夠請求一個隨機的歐洲語言,必須更改文件中的功能。 翻譯:瘋狂的技術宅原文標題:Creating a full-stack web application with Python, NPM, Webpack and Reac...
摘要:點擊直達前文譯一個小時搭建一個全棧應用框架上如果沒有,但還是要繼續學習本教程,可以到我的頁面下載代碼。從服務器返回隨機語言的每當我們與服務器上的端點進行通話時,為了能夠請求一個隨機的歐洲語言,必須更改文件中的功能。 翻譯:瘋狂的技術宅原文標題:Creating a full-stack web application with Python, NPM, Webpack and Reac...
閱讀 2013·2021-09-29 09:35
閱讀 1949·2019-08-30 14:15
閱讀 2973·2019-08-30 10:56
閱讀 955·2019-08-29 16:59
閱讀 571·2019-08-29 14:04
閱讀 1301·2019-08-29 12:30
閱讀 1020·2019-08-28 18:19
閱讀 510·2019-08-26 11:51