js 函數(shù)

前引

我們在了解函數(shù)之前,應(yīng)該先了解一下堆棧的定義
基本類型的值也就存放在棧內(nèi)存中:基本類型占有的內(nèi)存大小是固定的,比如Boolean String Number undefind null,都是存在棧內(nèi)存中
引用類型的值也就存放在堆內(nèi)存中:引用類型的占有的內(nèi)存大小不固定,比如Object Array 這些都是在堆內(nèi)存中的
我們訪問引用類型的時候,我們先是通過變量名去棧內(nèi)存中拿到該值在堆內(nèi)存中的地址,然后通過這個地址再去堆內(nèi)存訪問其值。
棧:存放基本類型(String,Number,Boolean,Null,Undefined),簡單的數(shù)據(jù)段,占據(jù)固定大小的空間。
堆:大小不定也不會自動釋放,存放引用類型(Function,Array,Object), 指那些可能由多個值構(gòu)成的對象,保存在堆內(nèi)存中,包含引用類型的變量,實際上保存的不是變量本身,而是指向該對象的指針。

注:

我們創(chuàng)建的所有對象和數(shù)組 都是在堆內(nèi)存中,
然后你調(diào)用數(shù)組或?qū)ο?,其實是調(diào)用的數(shù)組或?qū)ο蟮牡刂罚?這個地址就是新開辟的東西,放在棧里面的
當(dāng)結(jié)束時候,這個棧內(nèi)存,也就消失了。

1,創(chuàng)建函數(shù)的三種方式

1,函數(shù)聲明  function name(){}
2,函數(shù)表達式 var name=function(){}
3,創(chuàng)建實例函數(shù) var name=new function();
4,自執(zhí)行函數(shù)
    (function(){alert(1);})();
    (function fn1(){alert(1);})();

ES6 中,箭頭函數(shù)意義:箭頭功能沒有自己的this,不適合定義對象方法
函數(shù)的經(jīng)歷的歷程由:單例模式()=>工廠模式()=>構(gòu)造函數(shù)

2,單例模式

概念:把描述同一個對象的屬性和方法放在一個內(nèi)存空間下,起到了分組的作用,這樣不同事物之間的屬性記時屬性名相同,相互也不會發(fā)生沖突

//  單例模式下,我們把person1與person2叫做  命名空間
var jsPerson1={
     name:"王小波",
     age:48,
     writeJs:function(){
         console.log("my name is"+this.name+"i can write js~~");
     }
  };
jsPerson1.writeJs();

單例模式雖然解決了分組的作用,但是還不能實現(xiàn)批量的生產(chǎn),屬于手工作業(yè)模式 => 工廠模式產(chǎn)生了

3,工廠模式

1,概念:把實現(xiàn)同一件事情的相同代碼放到一個函數(shù)中,以后如果再想實現(xiàn)這個功能,不需要從新地編寫這些代碼,只需要執(zhí)行當(dāng)前的函數(shù)即可叫做函數(shù)的封裝
2,代碼封裝優(yōu)勢:低耦合高內(nèi)聚:減少頁面中的冗余代碼,提高代碼的重復(fù)利用率
3,所有的編程語言都是面向?qū)ο箝_發(fā)的 => 類的繼承、封裝、多態(tài)
4,繼承:子類繼承父類中的屬性和方法

function createJsPerson(name,age){
     var obj={};// 工廠模式要在里面定義一個變量
     obj.name=name;
     obj.age=age;
     obj.writeJs = function(){
       console.log("my name is"+this.name+"i can write js~~");
     };
     return obj;
};
var p1 = createJsPerson("王小波",12);

工廠模式雖然解決了創(chuàng)建多個相似對象問題,但是沒有解決對象識別問題,即不能知道一個對象的類型,所以構(gòu)造函數(shù)產(chǎn)生了

4,構(gòu)造函數(shù)

1,構(gòu)造函數(shù)模式的目的:是為了創(chuàng)建一個自定義類,并且創(chuàng)建這個類的實例

2,構(gòu)造函數(shù)的執(zhí)行過程:

使用new關(guān)鍵字創(chuàng)建對象
在內(nèi)存中創(chuàng)建一個空對象,把this指向剛創(chuàng)建的空對象
執(zhí)行構(gòu)造函數(shù)中的代碼
默認(rèn)返回新創(chuàng)建的對象;不管有沒有return,或者return 后面是字符串后者數(shù)字等,都不起作用;但是如果 return 都面返回的是一個object,那么就會返回這個object值

3,構(gòu)造函數(shù)的案例:

function CreateJsPerson(name,age) {
      this.name = name;
      this.age = age;
      this.writeJs = function(){
         console.log("my name is"+this.name+"i can write js~~");
      };
}

let p2 = new CreateJsPerson('kevin2',8);

注:在構(gòu)造函數(shù)模式中,new fn;執(zhí)行時,如果fn不需要傳遞參數(shù)的話,后面的小括號可以省略
js中所有的類都是函數(shù)數(shù)據(jù)類型的,它通過 new 執(zhí)行變成了類,但是他本身也是一個普通的函數(shù)
js中所有的實例都是對象數(shù)據(jù)類型的

4,判斷數(shù)據(jù)的類型方法

  • instanceof:判斷某個對象是否是某個構(gòu)造函數(shù)的實例
  • typeof:檢測數(shù)據(jù)類型作用,不能細分object下面的對象,數(shù)組,正則...
  • attr in object:私有公有,只要有都顯示true(檢測某一個屬性是否是屬于這個對象)
  • hasOwnProperty:用來檢查屬性是否為對象的私有屬性
  • hasPubProperty:用來檢查屬性是否為對象的公有屬性

5,構(gòu)造函數(shù)模式與工廠模式區(qū)別

  • 執(zhí)行時
普通函數(shù)執(zhí)行:var p1=createJsPerson("王小波",12);// createJsPerson是一個函數(shù)名

構(gòu)造函數(shù)模式:var p2 = new CreateJsPerson("王小波",12);// CreateJsPerson是一個類

注:而函數(shù)執(zhí)行返回值(p2)就是CreateJsPerson這個類的一個實例
如果類是我們自己創(chuàng)建的,那么首字母要大寫,這個是規(guī)范

  • 在函數(shù)代碼執(zhí)行的時候
相同:都是形成一個私有的作用域,然后 形參賦值—>預(yù)解釋—>代碼從上到下執(zhí)行,類和普通函數(shù)一樣,他也有普通的一面

不同:
`工廠模式`:手動創(chuàng)建一個對象
`構(gòu)造函數(shù)`:在代碼執(zhí)行之前,構(gòu)造函數(shù)不用手動的創(chuàng)建對象,瀏覽器會默認(rèn)創(chuàng)建一個對象數(shù)據(jù)類型的值(這個對象其實就是我們當(dāng)前類的一個實例)
接下來代碼從上到下執(zhí)行,以當(dāng)前的實例為執(zhí)行的主體(this代表的就是當(dāng)前的實例),然后分別把屬性名和屬性值賦值給當(dāng)前的實例,瀏覽器會默認(rèn)地把創(chuàng)建的實例返回

用 CreateJSPerson 這個類創(chuàng)建出來的實例,都擁有 writeJs 這個方法,但是不同實例之間的方法是不一樣的

注:

1,瀏覽器在構(gòu)造函數(shù)模式中,瀏覽器會默認(rèn)的把我們的實例返回(返回的是一個對象數(shù)據(jù)類型的值);
2,如果我們自己手動寫return返回:返回的是一個基本數(shù)據(jù)類型的值,當(dāng)前返回實例是不變的,返回是的一個引用數(shù)據(jù)類型的值,當(dāng)前的實例會被自己的值給替換掉

5,構(gòu)造函數(shù)原型

console.log(p1.writeJs === p2.writeJs) // false

問題:當(dāng)我們創(chuàng)建構(gòu)造函數(shù)時,里面的方法通過創(chuàng)建會存儲多份

  • 每個構(gòu)造函數(shù)都有一個屬性 => 原型 (prototype)
  • 通過原型添加方法,它的成員都可以訪問到,此時存儲的方法只有一個
console.log(p1.writeJs === p2.writeJs) // true

6,對象原型

5,原型鏈模式

1,實例識別:構(gòu)造函數(shù)模式中擁有了類和實例的概念,并且實例和實例之間是相互獨立開的

2,原型鏈模式:

1,通過 對象名.屬性名(鍵值對) 的方式獲取屬性值的時候,
2,首先在對象的私有屬性上進行查找,
3,如果私有中存在這個屬性,則獲取的是私有的屬性值;
4,當(dāng)調(diào)用對象屬性/方法時,先找對象私有屬性/方法,如果沒有,就調(diào)用原型中的屬性/方法
5,如果元素上沒有找到,則繼續(xù)通過原型上__proto__繼續(xù)向上查找,一直找到 Object.prototype 為止,沒找到會報錯

3,基于構(gòu)造函數(shù)模式的原型模式解決了方法或者屬性公有的問題;
把實例的相同的屬性/方法,提取成公有的屬性/方法,只要是它的實例對象,都可以獲取

function CreateJsPerson(name,age){//自己創(chuàng)建的類,首字母要大寫
    this.name=name;
    this.age=age;
};
CreateJsPerson.prototype.writeJs=function(){ // 公有的屬性和方法
    console.log("我是prototype的公有屬性writeJs");
};

4,原型鏈接式
必須保證中間連接每一個返回的結(jié)果都是一個數(shù)組,才能使用鏈接式,不是數(shù)組,完成不了下面的鏈接,會報錯;只有數(shù)組才能使用我們Array原型上定義的屬性和方法

ary.sort(function(a,b){
    return a-b;
}).reverse().pop();

5,批量設(shè)置原型上的公有屬性和方法

  • 起一個別名,把原來原型指向的地址賦值給我們的pro,現(xiàn)在他們操作的是同一個空間內(nèi)存
  • 重構(gòu)原型對象的方式
    只有瀏覽器天生給Fn.prototype開辟的堆內(nèi)存里面才有constructor,而我們自己開辟的這個堆內(nèi)存,沒有這個屬性,所有console.log(f.constructor) 指向就不是Fn而是object
function Fn(){
    this.x=100;
};
Fn.prototype={//----這里給他直接創(chuàng)建一個新的堆內(nèi)存空間
    constructor:Fn// 這個添加指向,保持和原來一致
    a:function(){},
    b:function(){},
    c:function(){},
    d:function(){},
};
var f = new Fn;
f.a();
f.b();
console.log(f.constructor); // 沒有處理之前,指向object,所以為了和原來保持一致,我們需要手動的增加constructor的指向

6,函數(shù)的三角關(guān)系(構(gòu)造函數(shù),對象,原型對象)

萬物皆對象; 例外:Function.prototype是函數(shù)數(shù)據(jù)類型的值,但是相關(guān)操作和之前的一模一樣;-----輸出的結(jié)果是Empty/anonymous(空函數(shù)/匿名函數(shù))
object是Function的兒子;Function的原型是object原型的兒子

1,函數(shù)的三角戀

  • 對象:是通過構(gòu)造函數(shù)創(chuàng)建的
  • 對象的 __proto__屬性 = 對象原型
  • 對象.prototyped.constructor = 該構(gòu)造函數(shù)
  • 構(gòu)造函數(shù).prototype = 該對象原型
    image.png

    所有原型對象的proto都是Object原型對象,proto的最巔峰值是 null,上圖中,表示出來了

2,函數(shù)本身一些自己的屬性
length:0-----形參的個數(shù)
name:“Fn”-----函數(shù)名
prototype:類的原型, 在原型上定義都是當(dāng)前Fn這個實例的公有方法
__proto__:把函數(shù)當(dāng)做一個普通的對象,指向Function這個類的原型

3,函數(shù)在整個js中,一個函數(shù)存在多面性
本身就是一個普通的函數(shù):執(zhí)行的時候形成私有的作用域(閉包),形參賦值,預(yù)解釋,代碼執(zhí)行,執(zhí)行完成后棧內(nèi)存銷毀/不銷毀
:他有自己的實例,也有一個叫做prototype屬性是自己的原型,他的實例都可以指向自己的原型
普通類型:和 var obj=Fn; 中的 obj 一樣,就是一個普通的對象,他作為對象可以有一些自己的私有屬性,也可以通過__proto__找到Function.prototype;當(dāng)然這里如果this指向是window,沒有return,那么是undefined

7,函數(shù)中更改this的指向

這里是介紹三種方法,詳情可見http://www.itdecent.cn/p/c59b45c519f5

  • apply()
  • call()
  • bind()

8,面向?qū)ο笕筇卣鳎悍庋b,繼承,多態(tài)(抽象)

1,封裝:復(fù)制對象的成員給另一個對象

function  extend(parent,child){
 for(var key in parent){
 if(child[key]){
 continue;}
 child[key]=parent[key]}
}

2,繼承是類型和類型之間的關(guān)系
繼承目的:把子類型中共同的成員提取在父類型中,代碼重用
案例:

<!--都是人,都有name,age,sex這些屬性,把這些屬性提取出來作為公共的部分  -->
function  Person(name,age,sex){
   this.name=name
   this.age=age
   this.sex=sex;
}

<!--這里調(diào)用Person()構(gòu)造函數(shù),但是在Parent中,this指向與Child中的this指向不同,在這里要改變this指向,用call方法改變,不管是Parent與Child都可以用到公共屬性 -->
function  Parent(name,age,sex,salary){
    this.name=name;
    this.age=age;
    this.sex=sex;
}
function  Child(name,age,sex,salary){
    Person.call(this,name,age,sex);
    this.salary=salary;
}

組合繼承:借用構(gòu)造函數(shù) + 原型繼承
//通過原型讓子類型繼承父類型中的方法

Teacher.prototype = new Person();//Person是指一個構(gòu)造函數(shù)
//因為這個是手動設(shè)置的,不是瀏覽器自動賦值的,所以這邊constructor指向不是構(gòu)造函數(shù)本身,這邊要手動改變
Teacher.prototype.constructor=Teacher; 

3,多態(tài)(這里我還沒有整理,整理好,會自動更新)

9,函數(shù)的其他參數(shù)

函數(shù)本質(zhì)上的對象,call,bind都是對象上的方法

  • arguments: 是一個偽數(shù)組,獲取到的是函數(shù)的實參
function fn(){
    console.log(fn.arguments);// 2,3,4
}

fn(2,3,4)
  • caller:函數(shù)的調(diào)用者
function fn(){
    console.log(fn.caller) // test(因為是在test下面調(diào)用的)
}

function test(){
  fn()
}
  • name:函數(shù)的名稱
function fn(){
    console.log(fn.name) // fn
}

 fn()
  • length:函數(shù)的形參個數(shù)
    注意這個不是實參個數(shù)
function fn(x, y){
    console.log(fn.length) // 2
}

 fn(3,7,9)
arguments 這里單獨介紹一下

當(dāng)函數(shù)參數(shù)個數(shù)不固定時候
在函數(shù)內(nèi)部,我們可以通過arguments來獲取實際傳過來的參數(shù)

function fn(){
    console.log(arguments);// 2,3,4
}

fn(2,3,4)

補充:
this 的指向:http://www.itdecent.cn/p/bf8d22a67134
改變 this 的指向方法:http://www.itdecent.cn/p/c59b45c519f5

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容