理解構造函數與原型對象

前言

在Es6以前,因爲javascript沒有對類的支持,也就是說它並不具有如傳統後臺語言(好比java)擁有類的功能,所謂類就是用來描述事物中的屬性和行爲的,類的特徵是由成員組成的,而屬性對應的就是類中的成員變量,而方法對應的就是類中的成員方法,這是傳統oop語言的描述,然而在javascript中,雖沒有類的概念,可是它每每是經過構造函數和原型對象來給對象模擬與類類似的功能,可是這些類似的功能並不必定表現的與類徹底一致,其實建立構造函數的過程,就是建立模板的過程,類必定程度上與此類似,建立多個共享的特定的屬性和方法,用於生成對象的餅乾工具,主要目的是提升代碼的可複用性,也提升了代碼的性能,有時候,在咱們無心間就已經在使用了這些特性,什麼構造函數,原型,我的以爲,初次理解起來非常抽象,也稀裏糊塗的以爲實際開發中到底有什麼卵用,也許後者在不涉及複雜的功能需求時,平時用得很少,顯然Es6中已新增了類class的功能,愈來愈嚴格,愈來愈像後端語言,Es6,Es7,Es8新增的諸多方法也愈來愈強大,標準也愈來愈完善,可是我以爲理解構造函數與原型對象是必須的,是js面向對象編程的基礎,今天就個人學習和使用跟你們分享一下學習心得javascript

收聽音頻,可戳連接,好久沒開口了,嘴巴變笨了的css

正文從這裏開始~html

什麼是函數

先看下面一簡易代碼java

var funA = function(){
    console.log("我是匿名函數保存在變量funA中");
}
var funB = [function(){
    console.log("我是匿名函數保存在數組funB中");
}]
var funC = {
     method:function(){
        console.log("我是匿名函數保存在對象funC中");
    }
}
// 函數的調用
funA();     // 普通函數的調用
funB[0]();  // 函數存入數組中的調用
funC.method(); // 對象調用方法的使用

// 函數能夠做爲參數傳遞,也能夠做爲返回值返回
var funD = function(funParm){
    return funParm;
}
var runFunParmPassedToFunD = funD(function(){
    console.log("歡迎關注微信itclanCoder公衆號");
})
runFunParmPassedToFunD();

// 函數是對象,也就是說函數也擁有屬性
var FunE  =  function(){}
FunE.property = "隨筆川跡";
console.log(FunE.property);
// 證實函數式對象
console.log("funA的數據類型是",typeof funA);
console.log("funA具體所屬",Object.prototype.toString.call(funA));
console.log("funA是由Object的一個實例對象?",funA instanceof Object); 
console.log("funA函數下面的構造器是",funA.constructor);
console.log("funA函數是由Object構造出來的?",funA.constructor == Object); // false
console.log("funA下面的原型",funA.prototype);   // funA下面的原型
console.log("Object下的原型",Object.prototype); // Object對象下原型
console.log("funA原型下構造器",funA.prototype.constructor);//function fun(){}
console.log("對象原型下的構造器",Object.prototype.constructor);複製代碼

控制檯輸出結果以下:jquery

什麼是函數
什麼是函數

結論:

  • 函數也是功能代碼塊,一個封閉區間短小的腳本,若是屢次使用同一段代碼,就能夠把它封裝成一個函數,容許在代碼裏隨調隨用,利用函數封裝來避免重複鍵入大量相同的內容,不過函數的真正威力在於傳參的能力,能夠把不一樣的數據傳遞給它們,使用這些數據去完成預約的操做
  • 函數是一等公民,是對象,是值,能夠存儲在一個變量,數組或者對象中
  • 函數能夠傳遞給函數,並由函數返回,函數擁有屬性
  • 函數總有返回值(換句話說就是有return語句,固然構造器函數除外,由於它默認會返回構造器函數調用,當構造函數的調用執行時,會顯示的返回返回)

什麼是構造函數

定義:構造函數就是你用new關鍵字建立對象時調用的函數
做用(優勢):建立多個共享特定屬性和行爲的對象,主要是用於生成對象的餅乾模具
缺點:當實例化多個對象時,會重複的建立對象,形成內存空間的浪費,增大CPU的開銷,並無消除代碼的冗餘,(如後面代碼所示,原型正好解決了此類問題)編程

// 聲明一構造函數,首字母大寫
function Animal(name,age){
    // this == new Animal();new會自動的建立this對象,且類型就是該構造安徽省農戶的類型,構造函數不須要返回值,由於new會顯示的返回,return的值就等於函數名+()的調用
    this.name = name;     // 自定義屬性
    this.age = age;       // 同上
    this.fun = function(){  // 自定義方法
        return this.name+" "+this.age+"歲了";
    }
}
// 實例化對象
var animal1 = new Animal("cat",2);
var animal2 = new Animal("dog",3);                   console.log(animal1.name,animal1.age,animal2.name,animal2.age); // cat 2 dog 3 
console.log(animal1.fun(),animal2.fun()); // cat 2歲了 dog 3歲了
console.log(animal1.hasOwnProperty("name"));
console.log(animal1.hasOwnProperty("age"));
console.log(animal1 instanceof Animal);  // true,證實animal1是Animal1是Animal構造函數建立出來的
console.log(animal2 instanceof Animal);
console.log(animal1.constructor === Animal); // true
console.log(animal2.constructor === Animal); // true
console.log(animal1.fun == animal2.fun);  // false複製代碼

示例代碼截圖以下
後端

什麼是構造函數
什麼是構造函數

問題:同一個構造函數建立出來不一樣的實例化對象,公用的方法不等同,也就是說,當你new一個構造器對象,上面的構造函數就執行一遍,每次都會新建一個function,會新開闢一個內存空間,每次都是指向一個新的堆的對象 ,這樣佔用內存消耗很是的大,怎麼解決這個問題
解決辦法1:將構造函數裏面自定義的方法拿出來,獨立放在構造函數外
以下示例代碼所示

// 聲明一構造函數,首字母大寫
function Animal(name,age){
    this.name = name;     // 自定義屬性
    this.age = age;       // 同上
    this.fun = fun;
}
// 把構造函數裏面自定義的方法拿出來
function fun(){
    return this.name+" "+this.age+"歲了";
}
// 實例化對象
var animal1 = new Animal("cat",2);
var animal2 = new Animal("dog",3);
console.log(animal1.fun === animal2.fun);  // true複製代碼

控制檯截圖以下所示
設計模式

將構造函數中的方法拿到外面來,解決實例化多個對象時,重複的建立函數
將構造函數中的方法拿到外面來,解決實例化多個對象時,重複的建立函數

解決辦法2利用原型正好解決實例化多個對象時,避免構造函數內的方法重複建立(如後面的示例代碼所示)

普通函數與構造函數的區別

  • 有new與無new的差異
  • 寫法上,構造函數首字母大寫(目的只是用於區分普通函數與構造函數,提醒你在建立實例化對象前加new操做符)
  • 當函數沒有被new調用時,構造函數中的this就能與全局this對象(即window)

示例代碼以下所示:api

// 聲明函數
function Animal(name,age){
   this.name = name;     
   this.age = age;      
   this.fun = function(){  
       return this.name+" "+this.age+"歲了";
   }
//console.log(this); window
}
// 無new的狀況
var animal1 = Animal("cat",2);
var animal2 = Animal("dog",3);
console.log(animal1 instanceof Animal); // false
console.log(animal2 instanceof Animal); // false
console.log(Object.prototype.toString.call(animal1));//[object Undefined]
console.log(Object.prototype.toString.call(animal2));
console.log(name,age);   // dog 3
console.log(animal1.name,animal1.age); //報錯複製代碼

控制檯輸出結果
數組

無new函數的調用
無new函數的調用

從上面的代碼中能夠看出,當一個函數無new關鍵字的調用時,構造函數中的this對象指向的是全局對象window,因此構造函數式依靠new提供返回值,上面的類型檢測,值爲undefined,正是如此,沒有使用new,則爲普通函數,只不過是一個沒有返回值的語句函數,對this賦值屬性和方法,至關於在全局下添加屬性和方法,若是加了use strict,在嚴格模式下,還會報,嚴格模式下,並無全局對象設置this,返回的是undefined

針對以上問題,若是想普通函數也具備構造函數的功能,怎麼作?以下代碼所示

// 聲明構造函數
function Animal(name,age){
// 加一this條件判斷,用instanceof來檢查本身是否被new調用
if(this instanceof Animal){
   this.name = name;     
   this.age = age;      
   this.fun = function(){  
     return this.name+" "+this.age+"歲了"; }
}else{
// 以new遞歸調用本身來爲對象建立正確的實例,這樣作的目的是在不一樣的狀況下表現出一致的行爲,經常是爲了保護那些忘記了使用new的狀況
     return new Animal(name,age);
}
}
// 無new的狀況
var animal1 = new Animal("cat",2);
var animal2 = Animal("dog",3);
console.log(animal1 instanceof Animal); // true
console.log(animal2 instanceof Animal); // true                
console.log(Object.prototype.toString.call(animal1));//[object object]
console.log(Object.prototype.toString.call(animal2));//[object object]
console.log(animal1.name,animal1.age);
console.log(animal2.name,animal2.age);複製代碼

控制檯輸出結果以下

爲了使普通函數與構造函數結果一致,加一條件判斷,做用域安全函數
爲了使普通函數與構造函數結果一致,加一條件判斷,做用域安全函數

爲什麼內置構造函數無new也能工做

示例代碼以下所示

var arr = Array; // 當沒有參數時,構造函數後面的圓括號能夠省略
var obj = Object({
    name:"隨筆川跡",
    sex:"boy",
    fun:function(){
       return this.name+" "+this.sex+" "+Object.prototype.toString.call(this);
}});
console.log(obj.fun());複製代碼

截圖以下所示

內置構造函數無new也能工做
內置構造函數無new也能工做

緣由:由於那些內置系統構造函數(Array,Object,RegExp,Date,Error,String等)都被設計爲做用域安全的構造函數,也就是說在整個全局範圍內都是可見的,一個做用域安全的構造函數無new也能夠工做,並返回一樣類型的對象

原型對象

protype:

  • 做用1:去改寫對象下面公用的方法或者屬性,讓公用方法或者屬性在內存中存在一份(也就是更改構造器函數底下屬性和方法,解決了不會重複建立構造的過程,目的是提升性能),能夠看做是對象的基類
  • 做用二:在原有的對象基礎上上,經過prototype進行額外的,封裝,拓展(如後面示例代碼)
  • 原型是基於構造函數的(也就是說原型是掛載在構造函數下的,先有構造函數,纔會有原型)
    以下原型示例代碼
    function ProtoFun(width,height){
      this.width = width;
      this.height = height;
      this.method = function(){
          return "我是構造函數下自定義的方法"
       }
    }
    // 構造函數.原型下添加屬性
    ProtoFun.prototype.color = "red"; 
    // 構造函數.原型下添加方法
    ProtoFun.prototype.fun = function(){
    return this.width+" "+this.height+" "+this.color;
    }
    // 上面兩個一般能夠合併成下面一個
    ProtoFun.prototype.init = {
    color:"red",
    fun:function(){
       return this.width+" "+this.height+" "+this.color;
    }
    }
    var elemObj1 = new ProtoFun(100,100);
    var elemObj2 = new ProtoFun(200,200);
    console.log(elemObj1.width,elemObj1.height);  // 100 100
    console.log(elemObj2.width,elemObj2.height);  // 200 200                  
    console.log(elemObj1.color,elemObj1.fun(),elemObj1.init.color,elemObj1.init.fun());              
    console.log(elemObj2.color,elemObj2.fun(),elemObj2.init.color,elemObj2.init.fun());
    console.log(elemObj1.method===elemObj2.method); // false
    console.log(elemObj1.fun === elemObj2.fun);     // true複製代碼
    控制檯輸出結果以下

什麼是原型,改寫構造函數(對象)的屬性和方法,達到共享屬性和方法
什麼是原型,改寫構造函數(對象)的屬性和方法,達到共享屬性和方法

以下示例:

// 未用原型寫法,普通寫法求和
var arr1 = [1,2,3,4,5,6,7,8,9,10];
var arr2 = [2,4,6,8,10,12,14,16]
arr1.sum = function(){
    var result = 0;
    for(var i = 0;i<arr1.length;i++){ // 這裏也能夠換成this.length
    result += this[i];
}
    return result;   // 返回結果
}
arr2.sum = function(){
var result = 0;
for(var i = 0;i<arr2.length;i++){
    result += this[i];
}
return result;   // 返回結果
}
console.log("數組arr1和爲",arr1.sum()); // 55
console.log("數組arr2和爲",arr2.sum()); // 72複製代碼

控制檯截圖以下:

未使用原型下的方法
未使用原型下的方法

原型寫法

// 原型寫法
var arr1 = [1,2,3,4,5,6,7,8,9,10];
var arr2 = [2,4,6,8,10,12,14,16]
Array.prototype.sum = function(){
var result = 0;
 for(var i = 0;i<this.length;i++){
    result += this[i];
 }
    return result;
}
console.log("數組arr1的和爲",arr1.sum()); // 數組arr1的和爲55 
console.log("數組arr2的和爲",arr2.sum()); // 數組arr2的和爲72
console.log(arr1.sum === arr1.sum);       // true複製代碼
//普通函數封裝寫法,也就是閉包寫法
var arr1 = [1,2,3,4,5,6,7,8,9,10];
var arr2 = [2,4,6,8,10,12,14,16]
function AddResult(arr){
    arr.sum = function(){
    var result = 0;
    for(var i = 0;i<this.length;i++){ // 這裏也能夠換成this.length
        result += this[i];
    }
       return result;   // 返回結果
   }
 return arr.sum();
}
console.log("數組arr1和爲",AddResult(arr1)); // 數組arr1和爲55
console.log("數組arr2和爲",AddResult(arr2)); // 數組arr2和爲72複製代碼

區分構造函數自定義屬性與原型屬性

以下示例代碼所示:

function Person(name,publicNum){
  this.name = name;
  this.publicNum = publicNum;
  this.userDefined = function(){
     return "我是構造函數自定義方法unerDefined"
  }
}
Person.prototype.age = 25;
Person.prototype.init = {
    city:"beijing",
    job:"coder",
    method:function(){
        return "我是原型下的方法輸出"
    }
}
// 定義鑑別原型屬性方法
function hasPrototypeProperty(object,variable){
    return !object.hasOwnProperty(variable) && (variable in object);
}    
var person = new Person("隨筆川跡","itclancoder");
console.log(person.name,person.publicNum,person.userDefined(),person.init.city,person.init.job,person.init.method());
console.log(hasPrototypeProperty(person,"name"));
console.log(person.hasOwnProperty("name"));
console.log(person.hasOwnProperty("age")); // hasOwnProperty只能檢測自定義屬性,false
console.log(hasPrototypeProperty(person,"age"));
console.log("age" in person);  // true,in操做符既能檢測自定義屬性也能檢測出原型下的屬性複製代碼

控制檯輸出結果以下:

鑑別原型屬性仍是自定義屬性
鑑別原型屬性仍是自定義屬性

使用對象字面量形式改寫原型對象會改變構造函數的屬性,指向問題

function Person(name,job){
    this.name = name;
    this.job = job;
}
Person.prototype.init = {
    name:"小川",
    job:"碼男",
    outName:function(){
        return this.name;
    },
    outJob:function(){
        return this.job;
    }
}
var person = new Person("隨筆川跡","coder");
console.log(person.name,person.job);
console.log(person.init.outName(),person.init.outJob());
console.log(person.constructor === Person);  // true
console.log(person instanceof Person); // true複製代碼

控制檯輸出結果以下:

constructor指向問題
constructor指向問題

若將上面的代碼更改以下:

function Person(name,job){
    this.name = name;
    this.job = job;
}
// 使用對象字面量形式改寫原型對象
 Person.prototype ={
    name:"小川",
    job:"碼男",
    outName:function(){
        return this.name;
},
outJob:function(){
       return this.job;
 }
}
var person = new Person("隨筆川跡","coder");
console.log(person.name,person.job);
console.log(person.outName(),person.outJob());
console.log(person.constructor === Person);  // false
console.log(person.constructor === Object);  // true
console.log(person instanceof Person);      // true複製代碼

控制檯輸出結果以下

對象字面量改寫原型對象constructor指向會發生問題
對象字面量改寫原型對象constructor指向會發生問題

正確寫法:當一個函數被建立時,它的prototype屬性也被建立,且該原型對象的constructor屬性指向該函數,當使用對象字面量形式改寫原型對象Person.prototype時,則該constructor指向指向的是Object,爲了不這一點,須要手動的改寫原型對象手動設置constructor屬性,更改以下:

function Person(name,job){
   this.name = name;
   this.job = job;
}
// 使用對象字面量形式改寫原型獨享
Person.prototype ={
    constructor:Person,  // 手動指定這裏的指向該構造函數
    outName:function(){
        return this.name;
    },
    outJob:function(){
        return this.job;
    }
}
var person = new Person("隨筆川跡","coder");
console.log(person.name,person.job);
console.log(person.outName(),person.outJob());
console.log(person.constructor === Person);  // true
console.log(person.constructor === Object);  // false
console.log(person instanceof Person);      // true複製代碼

在原有的對象基礎上上,經過prototype進行額外的,封裝,拓展

實例代碼以下:

// 經過原型prototype對現有的內容進行額外的拓展,給數組Array添加方法
Array.prototype.sum = function(){
   return this.reduce(function(m,n){
        return m+n;
    })
}
var arrNums = [1,2,3,4,5,6,7,8,9,10];
var result = arrNums.sum();
console.log("arrNums的和爲",result);  // arrNums的和爲 55
// 給String添加額外的方法
String.prototype.capitalize = function(){
    return this.charAt(0).toUpperCase()+this.substring(1);
}
var message = "suibichuanji hello";
console.log(message.capitalize());   // Suibichuanji hello複製代碼

控制檯輸出以下:

經過原型prototype進行額外拓展
經過原型prototype進行額外拓展

以上例子中,咱們是能夠經過對系統提供的內置對象進行額外拓展的,也就是說系統對象(Date,String,Object,Array,RegExp等)是構造函數,當現有提供的功能無法知足時,就能夠根據prototype進行拓展,所以都有原型對象給你去改變,在該新增的方法前面添加構造函數.prototype就能夠了,上面的例子中是給Array.prototype添加了一個sum()求和的方法,該方法對數組全部元素進行求和並返回,arrNums數組經過原型對象自動就有了這個sum()方法,在sum()方法內部,this指向數組對象實例arrNums,因此該方法也可使用數組的其餘方法,什麼reduce(),substring(),等均可以

原型中的屬性優先級

示例代碼以下所示

var arr = [];
arr.name = "隨筆川跡";
Array.prototype.name = "川流不息";
console.log(arr.name);  // 隨筆川跡複製代碼

控制檯輸出以下

原型屬性的優先級
原型屬性的優先級

從上結果中能夠得出:當構造函數自定義的屬性名與該構造函數下原型屬性名相同時, 構造函數的自定義屬性優先於原型屬性(能夠把構造函數理解爲內聯樣式),而原型屬性或者原型方法能夠看作是class)
小結:構造函數就是用new關鍵字調用的普通函數,能夠隨時定義本身的構造函數來建立多個具備一樣的屬性的對象,能夠用instanceof操做符(建議用這個)者直接訪問constructor屬性來鑑別對象是被哪一個構造函數建立的,每個函數都具備prototype屬性,它定義了構造函數全部對象共享屬性

  • 自定義的屬性和方法放在構造函數裏面
  • 凡是共享的屬性和方法掛載在該構造函數原型下面
  • javascript的查找變量的機制,是沿着做用域鏈逐級向上查找的,在原型裏,是原型鏈,構造函數與原型之間的鏈接就是原型鏈,當訪問對象的某個屬性時,js首先在自定義的屬性的做用域內查找該變量是否存在,若是不存在,則會沿着原型鏈向原型下的查找該屬性,直至頂層Object的原型對象,如有則返回,若無,則返回undefined

面向對象小實例

效果圖:

簡單選項卡示例
簡單選項卡示例

css層疊樣式代碼

*{
    padding:0;
    margin:0;
}
#wrap{
   width:300px;
   height:260px;
   border:1px solid #ccc;
   margin:0 auto;
}
#wrap:after{
   content:"";
   height:0;
   display:block;
   clear:both;
   zoom:1;
}
#wrap div{
  height:100%;
  display:none;
  text-indent:10px;
  background:#2263A3;
  color:#fff;
}
#wrap div:nth-of-type(1){
  display:block;
}
#wrap input.active{
  background:#2263A3;
  color:#fff;
}
#wrap input{
    width:100px;
    height:30px;
    background:#abcdef;
    text-align:center;
    line-height:30px;
    outline:none;
    border:none;
    float:left;
    cursor:pointer;
    margin-bottom:30px;
 }複製代碼

html結構

<div id="wrap">
  <input type="button" class="active" value="公告" name="">
  <input type="button" value="規則" name="">
  <input type="button" value="論壇" name="">
  <div>歡迎關注微信itclancoder公衆號</div>
  <div>點擊右上方藍字便可關注</div>
  <div>什麼都沒有留下</div>
</div>複製代碼

js代碼

// 普通寫法
// 獲取元素
var oWrap = document.querySelector("#wrap");
var aBtns = oWrap.getElementsByTagName("input");
var aDivs = oWrap.getElementsByTagName("div"); 
// 循環
for(var i = 0;i<aBtns.length;i++){
    aBtns[i].index = i;  //添加索引
    aBtns[i].onclick = function(){  // 添加事件
    for(var j = 0;j<aBtns.length;j++){
    aBtns[j].className = "";       // 先去除掉全部的className
    aDivs[j].style.display = "none"; // 先隱藏
}
   // 添加class
   this.className = "active";
   aDivs[this.index].style.display = "block"; // 內容顯示
}
}複製代碼

jquery寫法

$(function(){
    $(" #wrap input").click(function(){
       var $index = $(this).index(); // 獲取索引
       $(this).addClass("active").siblings().removeClass("active");
       $("#wrap div").eq($index).show().siblings("div").hide();
   })
})複製代碼

面向對象寫法

function 構造函數(){
    this.屬性  // 對象.屬性
 }
構造函數.原型.方法 = function(){}
var 對象1 = new 構造函數();
對象1.方法();複製代碼

面向對象選項卡代碼示例以下所示

window.onload = function(){
    var t = new TabSelect();   // 實例化對象
    t.init();                  // 實例化對象調用方法
}
// 聲明構造函數
function TabSelect(){
   // this == TabSelect,添加自定義屬性,獲取對象
    this.oWrap =  document.querySelector("#wrap");
    this.aBtns =  this.oWrap.getElementsByTagName("input");
    this.aDivs =  this.oWrap.getElementsByTagName("div");
}
// 構造函數的原型下添加方法(初始化)
TabSelect.prototype.init = function(){
  var that = this; // 注意這裏的this指向,是TabSelect,用一個局部變量將this給存儲起來,其實這種方式是根據詞法做用域,閉包的方式來解決的
  for(var i = 0;i<this.aBtns.length;i++){
      this.aBtns[i].index = i;  //添加索引
      this.aBtns[i].onclick = function(){
          that.change(this);
          //console.log(this);匿名函數裏面的this指向的是input按鈕元素
      };
   }
}
// 構造器函數原型對象下添加方法
TabSelect.prototype.change = function(obj){
  //console.log(obj); // input點擊按鈕元素
  for(var j = 0;j<this.aBtns.length;j++){
    this.aBtns[j].className = "";       // 先去除掉全部的className
    this.aDivs[j].style.display = "none"; // 先隱藏
}
  // 添加class
  obj.className = "active";
  this.aDivs[obj.index].style.display = "block"; // 內容顯示
}複製代碼

小結
本例從普通寫法,jquery寫法,在到最後面向對象選項卡寫法,完成一簡易的選項卡,其中jquery寫法最爲簡單,容易懂,可是這裏我只是爲了嘗試用面向對象的思想去寫應用,實際開發中,不管哪一種方式,只要能實現出來就行,從普通的寫法,也就是原生js寫法,到面向對象寫法,能夠看出首先經過變形,把局部的功能給拎出來,封裝成一個函數,這個過程當中儘可能不要出現函數嵌套函數,由於this是指向是個使人頭疼的問題,能夠有全局變量,window.onload裏面儘可能是實例化對象,與對象的調用的方式,把不是賦值的語句單獨放到一個函數當中(好比上文中的獲取元素,給TabSelect添加自定義屬性),最後就是改變this指向問題,事件或者定時器,讓面向對象中的this指向該對象

總結:

本篇主要是本人對構造器函數與原型對象的一點點理解,new操做符調用的函數爲構造函,功能上與內置的函數並無多大的區別,構造函數首字母大寫用來區分普通函數仍是構造函數,構造函數中的this指向該實例化的構造函數,主要是建立多個共享特定屬性和行爲的對象,用於建立模板,做爲餅乾工具,而原型對象主要是改寫構造函數(對象)下面的方法和屬性,讓公用方法或者屬性在內存中存在一份,解決了當建立多個實例化對象時,重複的建立構造函數的過程,目的是減小內存開銷,提升性能,還有就是原型在原有的對象基礎上,經過prototype進行額外的,封裝,拓展,原型是掛載在構造函數下面的,以及最後用面向對象寫法實現了一個小實例,其實設計模式中的原型模式就是面向對象的寫法,殺雞焉用牛刀,適合本身的纔是好方法,面向對象的寫法,對於簡單的實例,面向過程就能夠了,對於複雜的實例,什麼組件,插件,我以爲都是面向對象的應用,關於面向對象,我也只是略知皮毛,在不斷的學習當中...

如下是本篇提點概要

  • 什麼是函數:function關鍵字聲明,一獨立封閉功能的代碼塊,也是對象
  • 什麼是構造函數:new關鍵字建立對象時調用的函數,用於建立模板,生成餅乾工具
  • 普通函數與構造函數的區別,有new無new區別,this的指向,普通函數,this指向全局window,而構造器函數this,指向該new 構造器函數調用
  • 爲什麼內置構造函數無new也能工做,由於那些內置系統構造函數,都被設計爲做用域安全的構造函數,一個做用域安全的構造函數無new也能夠工做,並返回一樣類型的對象
  • 原型對象,prototype,函數一旦聲明,就有該屬性,做用1:去改寫對象下面公用的方法或者屬性,讓公用方法或者屬性在內存中存在一份,能夠看做是對象的基類
    做用2:在原有的對象基礎上上,經過prototype進行額外的,封裝,拓展
  • 區分構造函數自定義屬性與原型屬性,用in操做符,hasOwnProperty組合使用進行判斷(見上示例代碼)
  • 使用對象字面量形式改寫原型對象會改變構造函數的屬性,指向問題,需手動的改寫原型對象手動設置constructor屬性
  • 在原有的對象基礎上,經過prototype進行額外的,封裝,拓展
  • 原型中的屬性優先級,構造函數自定義的屬性優先級優先於原型屬性,查找變量的方式是沿着原型鏈逐級查找的,直至頂層Object,有則返回,無則返回undeinfed
  • 面向對象小實例,普通寫法,JQuery寫法與面向對象選項卡寫法

更多內容盡在微信itclancode公衆號
更多內容盡在微信itclancode公衆號
相關文章
相關標籤/搜索