首页 > 代码库 > JavaScript-函数和OOP-学习笔记

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();

//探测器终于结束了

JavaScript-函数和OOP-学习笔记