想開一個車,你不須要本身去造一個車,只須要一把鑰匙,車對於你來講就是一個"對象"。
在JavaScript中的"對象", 具備屬性,當屬性的值是一個函數時,那麼此屬性就是這個對象的方法.訪問屬性的方式參考Object介紹瀏覽器
首先想到的是字面量建立對象,其次是建立一個對象實例,而後一次對對象屬性進行賦值.可是不管這兩種那個方法都有個缺點,當須要重複建立大量相同的對象時,產生大量代碼這是很不理想的,這時想到函數的一個功能就是講重複代碼進行簡化,以便屢次使用,那麼構造函數形式建立多個對象方式就是理想的選擇了.函數
function outPut() { console.log('hello') } function Person (name,age) { this.name2 = name; this.age2 = age; this.sayName = function () { console.log('this.name2') }; } var person2 = new person("Kangkang" , 20) // 分別調用
這裏有幾點須要注意,首先是這個this是誰? new操做符有什麼做用?this
person2
, 而new
操做符能夠建立一個對象實例.使用instanceof
操做符,返回布爾值.spa
p1 instanceof Person; p1 instanceof Object;
第二個檢測,不管是本身建立的構造函數對象仍是字面量對象,均爲true,由於他們均繼承自Object. 對於某個構造函數建立的實例當其構造函數的原型被改變後使用此操做符發現返回false ,緣由在於在實例的原型鏈上構造函數的原型是舊的對象,不是新的對象,天然也就不對了。instanceof-MDNprototype
思路是將這個方法提到實例的外面去,若是是全局對象不就能夠直接調用了嗎?但是全局函數對於封裝來講可沒好處,因此原型模式也就有了用處.code
這段話不容易理解.一點點分析,對象的原型屬性(prototype)指向的是一個對象,對象裏存的屬性和方法在對象實例後(即構造函數方法建立的新對象) 能夠被實例對象訪問使用.對象
function Person() { } Person.prototype.name = "Kangkang" Person.prototype.age = 20 Person.prototype.sayName = function () { console.log(this.name) } var person1 = new Person() person1.sayName() // "Kangkang" var person2 = new Person() person2.sayName() //"Kangkang" console.log(person1.sayName == person2.sayName) //true var person3 = new Person() person3.name = "Mary" person3.sayName() //"Mary"
在函數建立的時候,prototype屬性就被建立出來了,經過構造函數生成的實例在瀏覽器下支持一個屬性__proto__ 查看prototype(原型裏的對象)
繼承
如圖所示
顯示的是當一個實例在本身屬性中找不到相應的方法或者屬性時往上一層尋找的狀況。ip
檢測某個屬性屬於實例仍是原型:原型鏈
person1.hasOwnProperty("name")
當這個屬性是實例的返回true,是原型的返回false單獨操做的in操做符
__proto__
訪問,由上圖可知 "name" in Person1
能夠訪問返回true,不然返回falsehasOwnperty()
結合使用判斷某個屬性是否存在且存在於哪裏。由上面介紹可知,經過Person.prototype.name = "kangkang"
這種方法甚是繁瑣,多個屬性、方法將會致使反覆的輸入,因此對象字面量的書寫方式就能很好解決這個問題。
function Person () { } Person.prototype = { name : "Kangkang", age: 20, job: 'student', sayName = function() { console.log(name) } }
謹慎在初始化原型後再將其改變爲另一個對象
function Person () { } var friend = new Person() Person.prototype.sayHi = function() { console.log('hi') } friend.sayHI(); // 在建立對象後再對原型添加方法依然有效
下面這種狀況:
function Person () { } var friend = new Person() Person.prototype = { name : "Kangkang", age: 20, job: 'student', friends: ["xiaojun","xiaoming"], sayName : function() { console.log(name) } friend.sayName();// error
這種狀況至關於在原型初始化後又從新生成對象而且賦值,而原來的實例是指向初始化時的對象地址,故沒法訪問新的原型裏的屬性和方法.
以下程序:
function Person () { } Person.prototype = { name : "Kangkang", age: 20, job: 'student', friends: ["xiaojun","xiaoming"], sayName : function() { console.log(name) } } var person6 = new Person() var person7 = new Person() // person6.name = "Mary" // console.log(person6.name) // console.log(person7.name) // person6.sayName = function() { // console.log('hi') // } person6.friends.push('xiaohong') console.log(person6.friends) console.log(person7.friends) console.log(person6.sayName == person7.sayName)
由上面的代碼得出:
當對原型中基本類型值屬性和方法在實例中從新添加會阻止尋找到原型中的屬性和方法,當用delete 操做符刪除後依然能夠找到原型中的屬性和方法,也就是說在實例中重定義這兩種狀況不會影響原型中的屬性和方法,可是若是原型中的屬性對應的值是引用類型,因爲引用類型的特性,實例獲得了相同的這個屬性的地址,又因爲原型是實例公用的方法,因此當任一實例操做這個引用值屬性時都會影響到其餘這個對象的實例。因此組合使用構造函數和原型也就很好解決這個問題。
function Person (name, age, job) { this.name = name this.age = age this.job = job this.friends = ['kangkang','mary'] } Person.prototype = { constructor : Person, sayName : function () { console.log(this.name) } } var person1 = new Person('xiaojun',22,'student') var person2 = new Person('xiaowang', 21, 'student') person1.friends.push('xiaozhang') console.log(person1.friends) // ["kangkang", "mary", "xiaozhang"] console.log(person2.friends) // ["kangkang", "mary"] console.log(person1.friends === person2.friends) //false console.log(person1.sayName === person2.sayName) //true
初學筆記,我的記錄備忘,若有謬誤,歡迎指正。