天天看點

JavaScript-函數和OOP-學習筆記

JavaScript權威指南學習筆記,禁止轉載!

6、函數

函數調用方式:

直接調用:foo();

作為對象的方法調用:obj.method();

new:new Foo();

call/apply/bind:func.call(obj);

函數對象中沒有return語句或者return的是基本類型時,如果有this傳回值為this,

(1)建立函數

~函數聲明:function foo(a,b){……}

~函數表達式:

1)var add= function(a,b){……};

2)立即執行函數表達式(function(){……})();、!function(){……} ();等

3)将函數作為傳回值return function(){……};

4)命名式函數表達式var add= function foo(){……};

如,var func=function nfe(){};

alert(func===nfe); //ie6-8傳回false,ie9報錯 nfe is not defined

var func=function nfe(){ nfe(); }; //遞歸調用。如果沒有nfe還是可以用func來遞歸調用,是以不常用。

~Function構造器:var func=Function(‘a’,’b’,’console.log(a+b);’);//不常見

差別:函數聲明會被前置,在定義該函數的作用域通過函數名調用;

函數表達式和函數構造器允許匿名,立即調用;

函數構造器沒有函數名。

(2)this

全局作用域的this:指向window

一般函數的this:在浏覽器裡指向window,在node.js裡指向global object

作為對象方法的函數的this:指向該對象

對象原型鍊上的this:對象原型鍊上的方法的函數的this指向該對象

對象get/set方法的函數的this:指向該對象

~~new與this:

function MyClass(){this.a=37; } //this指向一個空對象,該對象的原型是MyClass.prototype;

var o=new MyClass(); //this會作為MyClass函數的傳回值賦給o;

o; //MyClass {a: 37}

o.a; //37

~~call/apply方法與this:

函數名. call(對象,arg1,arg2,argN)

函數名. apply(對象,[arg1,arg2,argN])

使函數裡的this指向這個對象,并把之後的值指派給函數。差別在于傳參形式不一樣。

如,function add(b,c){return this.a+b+c;} var o={a:1}; add.call(o,2,3);

//6

function add(b,c){return this.a+b+c;} var o={a:1}; add.apply(o,[4,5]);

//10

如,function foo(x,y){console.log(x,y,this);}

foo.call(100,1,2);

//1 2 Number {[[PrimitiveValue]]: 100} (如果第一個參數不是對象,會被轉換為對象類型)

foo.call(null);

//undefined undefined Window

~~bind方法與this(ES5提供的方法,ie9+才支援)

函數名. bind(對象)使函數裡的this指向這個對象。

~~bind與new與this

如function foo(){this.a=100;return this.b;}

var func=foo.bind({b:1});

func;  //function foo(){this.a=100;return this.b;}

func();  //1

new func();  //foo {a: 100} (new調用函數時,this依舊指向一個空對象,該對象的原型是func.prototype,不會被bind所改變)

(3)arguments實參

foo.name:函數名,foo.length:函數形參的個數, arguments.length:實參的個數,

arguments.callee是一個指針,指向擁有這個arguments的函數。

~~當參數衆多時,可使用bind與currying:

如,function add(a,b,c){return a+b+c;}

var fun=add.bind(undefined,100);

fun(1,2);  //103(this指向無所謂,undefined/null都可以)

var fun2=fun.bind(undefined,200);

fun2(1);  //301

?(未看) bind方法模拟

(4)閉包

問題:垃圾回收機制?性能優化:循環引用?

如,function outer(){var a=10; return function(){return a;} }

var func=outer();// function(){return a;} 作為傳回值賦給了全局變量,是以a會一直在記憶體中,也可以在outer函數外部通路它内部的局部變量a了。

func(); //10

//javascript中函數内部可以讀取全局變量,而函數外部無法讀取函數内部的局部變量。

如何從函數外部讀取函數内部的局部變量?在函數内部再定義一個函數。

優點:封裝

缺點:父函數内的局部變量無法釋放,空間浪費,記憶體消耗

把一個函數當做對象去傳遞作為傳回值,類似有這樣特性的語言都有閉包的概念。

(5)作用域

全局作用域

函數作用域

eval作用域,如eval(“var a=1;”)

ES6開始才有塊級作用域

用途:利用函數作用域封裝。

?(未看) ES3執行上下文

7、OOP(面向對象程式設計)

問題:原型鍊上的Object.prototype有哪些屬性方法?

答:valueOf、toString、hasOwnProperty,

對象是類的執行個體,對象作為程式的基本單元,

特性:繼承、封裝、多态、抽象

(1)prototype

如,function Student(){……}

var bosn=new Student();

// Student.prototype是函數對象Student上預設的對象屬性,它的作用是當使用new來構造Student的執行個體bosn時,Student.prototype會作為bosn的原型。

// Student.prototype.constructor指向Student本身(constructor:構造函數的意思)

//增加或删除Student.prototype上的屬性會影響它所建立的執行個體bosn;

如果直接修改Student.prototype不會影響修改之前已經建立的執行個體bosn,

但會影響之後新建立的執行個體。

(2)instanceof

對象 instanceof 函數構造器:

判斷函數構造器.prototype是否出現在對象的原型鍊上。右側如果不是函數對象,會報錯;左邊如果不是對象而是基本類型時,會傳回false,

如,new Object() instanceof Array;

 //false 因為new Object()——>Object.prototype——>null,是以左側對象的原型鍊上沒有Array.prototype

(3)實作繼承的方式

function Student(){……}

function Person(){……}

Student.prototype=new Person();  //不推薦

Student.prototype=Object.create(Person.prototype);  //推薦(但ES5之後才支援)

(4)模拟重載

例,function Person(){

var args=arguments;//将實參賦給變量

if(typeof args[0]===’object’&& args[0]) {

 //&& args[0] 是為了過濾null的參數(因為typeof args[0]也是object)

if(args[0]){

this.name= args[0].name;  }

if(args[1]){

this.age= args[1].name;  }

}

else{

if(args[0]){

this.name= args[0];  }

if(args[1]){

this.age= args[1];  }

}

}

var bosn=new Person(‘bosn’,27);

var bosn2=new Person( {name:‘bosn2’,age:27} );

(5)鍊式調用

如,function addclass(){}

addclass.prototype.add=function(str){

console.log(str+'is added');

return this;

}//作為對象方法的函數的this指向該對象addclass.prototype

var myman=new addclass();  // myman的原型指向addclass.prototype

myman.add('A').add('B').add('C'); 

// Ais added

//Bis added

//Cis added

?(未看)9-1 抽象類

(6)例:探測器

子類,基類,detect(),analyze()目前的環境,實作兩種探測器container和link

!function(global){

  // DetectorBase基類

function DetectorBase(configs){

if(!this intanceof DetectorBase){

 throw new Error(‘Do not invoke without new’);  } //必須使用new調用DetectorBase,this指向該對象,該對象的原型指向DetectorBase.prptotype,是以this intanceof DetectorBase為true

this.configs= configs;

this.analyze();

DetectorBase.prototype.detect=function(){throw new Error(‘Not implemented’)};

DetectorBase.prototype.analyze=function(){ …… };

//具體類LinkDetector

function LinkDetector(links){

  if(!this intanceof LinkDetector){

      throw new Error(‘Do not invoke without new’);  }//必須使用new調用

   this.links=links;

  DetectorBase.apply(this,arguments);  //調用基類

}

// 具體類ContainerDetector

function ContainerDetector(containers){

  if(!this intanceof ContainerDetector){

      throw new Error(‘Do not invoke without new’);  }//必須使用new調用

   this.containers=containers;

  DetectorBase.apply(this,arguments);  //調用基類

}

//先繼承

function inherit(subClass, superClass){

  subClass.prototype =Object.create(superClass. prototype) ;

  subClass.prototype.constructor= subClass;

}

inherit(LinkDetector, DetectorBase);

inherit(ContainerDetector, DetectorBase);

//再擴充,防止覆寫

LinkDetector. prototype. detect=function(){ …… };

ContainerDetector. prototype. detect=function(){ …… };

//當機(使得extensible、configurable、writable:false,ES5方法)

Object.freeze(DetectorBase );

Object.freeze(DetectorBase. prototype );

Object.freeze(LinkDetector);

Object.freeze(LinkDetector. prototype );

Object.freeze(ContainerDetector);

Object.freeze(ContainerDetector. prototype );

//暴露到全局對象(在全局對象上添加了LinkDetector等三個屬性,并且enumerable、configurable、writable:false)

Object.defineProperties(global,{

  LinkDetector:{value: LinkDetector },

  ContainerDetector:{value: ContainerDetector },

DetectorBase:{value: DetectorBase }

}); 

}(this); //立即執行函數至此結束,好長啊

原型鍊:LinkDetector——> LinkDetector. prototype(detect方法)——> DetectorBase. prototype(detect、analyze方法)

//調用

var cd=new ContainerDetector(‘abcdefg’);

var ld=new LinkDetector(‘http://www.imooc.com/’);

cd. detect();

ld. Detect();

//探測器終于結束了

轉載于:https://www.cnblogs.com/xuxuemin/p/6888803.html

繼續閱讀