`

JS 面向对象与闭包

 
阅读更多
函数类型

function 函数名称(参数表)
{
  函数执行部分;
}

注意:
1.参数列表直接写行参名即可,不用写var,不用指定类型
2.return 返回函数的返回值并结束函数运行。
3.函数可以当做参数进行传递。

//函数当做参数传递
<script type="text/javascript" charset="UTF-8">
function test(test1){
  test1();
}

function test1(){
  alert("调用方法TEST1");
}

//函数传递调用
test(test1);

//匿名函数传递 调用
test(function (){
  alert("调用方法TEST2");
});
</script>


function test3(){
  function test4(){
	alert("调用方法TEST4");				
  };
  test4();//方法内部嵌套定义方法,只能在方法内部调用	
}
test3();

三种函数定义的方式:

1.function语句形式 
  function test1(){alert("我是TEST1");}
  调用:test1();

2.函数直接量形式
//function语句形式与函数直接量形式在使用方面没有区别,除了解析机制。
  var test2 = function(){alert("我是TEST2");}
  调用:test2();

3.通过Function构造函数形式定义
  var test3 = new Function("a","b","return a+b;");
  调用:test3();




区别点:
1.构造函数方式的机制是动态的,其他两种是静态的。在大量循环创建的过程中,动态的创建方式耗时长。
2.解析机制,function语句方式是优先解析,而其他两种是顺序解析,指在执行到此语句时才解析,意味着调用语句不能放在function函数前面。
3.作用域,构造函数的方式是顶级作用域,意味着此function是全局的。

测试实例:
//创建方式1,2的性质是静态, 方式3的性质是动态
var d1 = new Date();
var t1 = d1.getTime();
for(var i=0; i<100000;i++){
	//function test4(){} //执行在10-20之间,编译一次放在内存中
	var test5 = new Function();//执行在 500-600之间,每次都需要编译,动态解析与静态解析的区别
}
var d2 = new Date();
var t2 = d2.getTime();
//alert(t2-t1);
		
		
//解析顺序,对于function语句式函数,javaScript解析器会优先解析
//而对于new Function方式,javaScript顺序解析
//test6();
function test6(){
	alert("test6");
}
//test7();//报错,提示缺少对象
var test7 = function(){
	alert("test7");
}

//顶级作用域测试
var k = 1;
function test8(){
	var k = 2;
	function test9(){alert(k)}
	var test10=function (){alert(k)}
	var test11= new Function ('return k'); //顶级作用域,相当于在方法外面定义
	alert(test11());
}
		
test8();


//匿名函数
格式:
(function(){//代码 })();
解释:,包围函数(function(){})的第一对括号向脚本返回未命名的函数,随后一对空括号立即执行返回的未命名函数,括号内为匿名函数的参数。
例子:(function(arg){ alert(arg+100); })(20); 这个例子返回120。

--------------------------------------------------------------------------------------------
//函数的参数

//形参列表
//传入的参数可以与定义的参数个数不统一,只是结果可能是NaN,比如test(1,2,3),那么d的值为undefined
//形参与实参 
function test(a,b,c,d){
	return a+b;
}
test();

示例1:
function test(a,b){
	alert(test.length);//查询形参个数
	alert(arguments.length);
	//arguments 查询传入参数的实际参数
	//arguments只能在函数内部访问
	alert("Frist argument: "+arguments[0]);
	if(test.length == arguments.length){
		return a+b;			
	}else{
		return "参数不正确!";
	}
}
	//arguments更多用于递归操作
	//arguments.callee 返回arguments所属函数对象引用,这相当于内部调用自己
	function fact(num){
		if(num <= 1) {
			return 1;
		}else{
			return num*arguments.callee(num-1);//等同于return num*fact(num-1); 解除耦合
		}
	}
	var f = fact;//将函数引用付给f
	alert(f(5));

--------------------------------------------------------------------------------------------
this对象
this对象是运行时基于函数的执行环境绑定的。在全局函数中,this等于window,
而函数被作为某个对象的方法调用时,this指的调用者。
也就是说this关键字总是指调用者。

<script type="text/javascript">
	var k = 10;
	function test(){
	   this.k = 20;//this总是指向调用者
	}
	test();//等同于window.test(),调用者是window
	alert(k);//20
</script>

--------------------------------------------------------------------------------------------
每一个函数都把包括两个非继承而来的方法:call,apply
这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。

call,apply的用途之一就是传递参数,但事实上,它们真正强大的地方是能够扩充函数赖以
运行的作用域。扩充作用域的最大好处是对象不需要与方法有任何耦合关系。
语法:call(thisObj,param1,param2...) //apply相同
定义:调用一个对象的一个方法,以另一个对象替换当前对象。 
说明: 
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象



function sum(x,y){
	return x+y;
}
function call1(num1,num2){
	return sum.call(this,num1,num2); //将sum函数绑定到call1方法上,将本方法接收的num1,num2传递给sum方法
}

function apply1(num1,num2){
	return sum.apply(this,[num1,num2]);
}
//alert(call1(10,20));
//alert(apply1(10,30));

//call方法扩充作用域
var color = 'red';
var obj = {color:'blue'};
function showColor(){
	return this.color;
} 
//alert(showColor.call());
//alert(showColor.call(obj));

//call方法的简单模拟
function test1(a,b){
	return a+b;
}

//自定义对象
function Obj(x,y){//方法名称大写代表对象
	this.x = x; //通过this给对象赋予属性
	this.y = y;
	return x*y;
}

var o = new Obj(10,20);
o.method = test1;//将test1方法赋予o对象
o.method(o.x,o.y);
//alert(test1.call(o,o.x,o.y));
//alert(test1(o.x,o.y));
delete o.method; //删除对象o的方法method

--------------------------------------------------------------------------------------------
执行环境是javascript重要的一个概念,它定义了函数或变量有权访问的其他数据,决定它们各自的行为。每个执行环境都有一个关联的对象,
环境中定义的变量和函数都保存在这个对象中。

一个需要注意的点:
javascript没有块级作用域的概念,高级语言比如java 在for,if语句中存在块级作用域概念,for,if块内定义的变量,外部无法访问。

function test(){
	for(var i=0;i<=5;i++){//此时定义代表在function test内部定义变量i
		alert(i);
	}
	alert(i); //弹出对话框,显示为6
}
test();

//作用域实例
var name = "xiao A";
var obj = {
	name : "xiao B",
	getName: function(){
		return function(){
			return name;
		}
	}
}
//alert(obj.name);
//alert(obj.getName()()); //等同于 var k = obj.getName(); k();
var k = obj.getName(); //全局作用域
//alert(k());


var obj1 = {
	name : "xiao B",
	getName: function(){
		var o = this;//将调用者对象付给o
		alert(o);
		return function(){
			return o.name;
		}
	}
}
alert(obj1.getName()());
--------------------------------------------------------------------------------------------
/*闭包
封装变量
//Javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、
参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包 
作用:
一个是可以读取函数体所在外部函数的局部变量,另一个就是让这些变量的值始终保持在内存中。 
*/


//闭包简单示例
var func = function (){
	var x =1 ;
	return function(){
		x++;
		alert(x);
	};
};
var f = func();  //f变量得的是function(){x++;alert(x);}的"对象"引用,里面仍然包含着x的值,因为执行作用域被付给了f,所以变量一直存在没有被摧毁
f();//2
f();//3

//如果采用下面的方式回执行,结果一直为2,理解为此function的返回没被变量引用,没有形成执行上下文,因此每次访问都为2
func()();//2
func()();//2 还是等于2,理解为每次访问都是一个新的对象

//闭包:一个函数可以访问另外一个函数作用域中的变量
//封闭性:private起到一个包括变量的作用
function f(x){
	var temp = x;
	return function(x){
		temp += x; //此function中引用到了上级中的temp变量
		alert(temp);
		}
}
var a = f(50);
alert(a);
a(5); //55
a(10);//66
a(20);//85

//闭包实例3
<html>
   <body>
      <div>1</div>
	  <div>2</div>
	  <div>3</div>
	  <div>4</div>
	  <div>5</div>
	  <script>
	      var divs = document.getElementsByTagName('div');
		  for(var i = 0,len = divs.length;i<len;i++){
			   divs[i].onclick = function(){
				   alert(i);
			   };
		  };
	  </script>
   </body>
 </html>

 //无论点击哪个DIV,弹出的结果是5,想想为什么?
 
//怎么样使得点击每个DIV都显示对应的数字0,1,2,3,4呢,再看如下例子
<script>
  var divs = document.getElementsByTagName('div');
  for(var i = 0,len = divs.length;i<len;i++){
	  (function(i){//绑定一个匿名函数(function())() 此时的i相当于是一个参数,相当于private参数,会保存下来i的值
		  divs[i].onclick = function(){
		             alert(i); //i调用的
                };
		  })(i); 
	};
</script>

//示例4
var mult = function (){
	var sum =1 ;
	for(var i=0;i<arguments.length;i++){
		sum =sum *arguments[i];
	};
	return sum ;
};
//这个函数接受一些number类型的参数,并返回这些参数的乘积
mult(3,4,5);//60
mult(3,4,5,6)//360

//如果每次传递同样的参数,都去计算一遍,是一种资源上的浪费,可以加入缓存机制来提高这个函数的性能

/*
  cache这个变量仅仅在mult函数中被使用,暴露在全局作用域下
  既然是mult函数专用,干脆将这个变量封闭在mult函数内部,避免这个变量在其它地方被调用或者修改,引起错误  
//还可以对代码进行重构,把比较独立的代码提炼出来*/
var mult = (function (){
	var cache = {};
	var calcute = function (){
		var sum =1 ;
		for(var i=0;i<arguments.length;i++){
				sum =sum *arguments[i];
		};
		return sum ;
	};
	return function(){
			var arrgs = Array.prototype.join.call(arguments,',');//利用call方法扩展作用域,实际上就是调用Array原型中的join方法,将参数数组作为作为this对象,','为参数
			if (cache[arrgs]){
				return cache[arrgs];
			};
			return cache[arrgs]=calcute.apply(null,arguments) ;
	};
})();
//如果这些独立小函数在其它地方没用用到,最好使用闭包把它们封闭起来

//闭包和面向对象设计

var person = function(name){
	return {
		getName:function(){
			return name ;
		}
	};
};

var man = person('bob');
man.getName();
//name变成了man这个对象的私有成员
--------------------------------------------------------------------------------------------
javascript面向对象
三种方式:
1.直接创建变量对象
2.通过function函数返回对象
3.通过构造函数new对象


//1.手工创建对象
var obj = {};//var obj = new Object();
obj.name = 'z3';
obj.sex = '男';
obj.sayName = function() {alert(obj.name)};
obj.sayName();

//2.工厂模式 创建对象
function createPerson(name,sex,age){
	var obj = {};
	obj.name = name;
	obj.sex = sex;
	obj.age = age;
	return obj;
}
var person1 = createPerson('l4','女',12);
alert(person1.name);
//3.构造函数创建对象

//函数的第一个字母大写,约定为类的模板
//3.1
function Person(name,age,sex){
	this.name = name; //this关键字指向new的对象
	this.age = age;
	this.sex = sex;
	this.say = function(){
		alert(this.name);
	}
}
//通过new构造一个对象 
var person2 =  new Person('w5',18,'男');
var person3 =  new Person('z6',20,'男');
person2.say();
alert(person2.constructor);//打印出person2的构造函数
alert(person1.constructor);//natvie code
alert(person2.constructor == person3.constructor);//判断person2的构造函数是否等于person3的构造函数
alert(person2 instanceof Person);//判断person2是否是Person的实例
alert(person3 instanceof Person);

//3.2
function Person(name,age,sex){
	return {
		name : name,
		age : age,
		sex : sex,
		say : function(){
		 alert(this.name);
		}
	}
}
//通过new构造一个对象
var abc = new Person('123',18,'男'); 
abc.say();
var abc1 = new Person('1234',18,'女');
abc1.say();
--------------------------------------------------------------------------------------------

//1.利用js对象模拟Map对象
<script type="text/javascript" charset="UTF-8">
    	
    	function Map(){//定义对象的"构造函数"(或者叫函数)
    		//private
    		var obj={};//空的对象容器,承载键值对
    		//map的put方法
    		this.put = function(key,value){//this代表当前对象
    			obj[key] = value;//将键值对绑定到obj对象上    		
    		}
    		this.size = function(){
    			var count = 0;
    			for(var attr in obj){
    				count++;
    			}
    			return count;
    		}
    		this.get = function(key){
    			if(obj[key] || obj[key] === 0 || obj[key] === false){//===代表先对比变量值,再对比变量类型(考虑隐形转换情况)
    				return obj[key];
    			}else{
    				return null;
    			}
    		}
    		this.remove = function(key){
    			if(obj[key] || obj[key] === 0 || obj[key] === false){
    				delete(obj[key]);//删除
    			}    		
    		}
    		this.eachMap = function(fn){
    			for(var attr in obj){
    				fn(attr,obj[attr]);
    			}
    		}
    	}    	
    	//模拟java里的Map
    	var m = new Map();
    	m.put('01','abc');
    	m.put('02',0);
    	m.put('03',true);
    	m.put('04',new Date());
    	alert(m.size());
    	alert(m.get('02'));
    	m.remove('02');
    	m.eachMap(function(key,value){//将function作为参数传递过去 称为回调函数
    		alert(key +" : "+ value);
    	});
    </script>


//2.利用对象的特性,去掉数组中的重复项
<script type="text/javascript" charset="UTF-8">
    	var arr = [1,2,3,4,5,1,3,5,2,10];
    	//js对象的特性:在js对象中key是永远不会重复的
    	//1.把一个数组转化为一个对象
    	//2.把数组中的值变为js对象中的key
    	//3.把这个对象再还原成数组
    	function toObject(arr){
    		var obj = {};//私有对象
    		for(var i = 0;i <arr.length;i++){
    			obj[arr[i]] = true;
    		}
    		return obj;
    	}
    	//对象变为数组
    	function keys(obj){
    		var arr = [];//私有对象
    		for(var attr in obj){
    			if(obj.hasOwnProperty(attr)){
    				arr.push(attr);
    			}
    		}
    		return arr;
    	}
    	
    	function uniq(newArr){
    		return (keys(toObject(newArr)));
    	
    	}
    	alert(uniq(arr));
</script>

 

分享到:
评论

相关推荐

    JS面向对象经典案例

    JS面向对象经典案例,JS面向对象过程中用到的一些技术,例如对象、类、JS继承Call、JS原型链Prototype、JS闭包等等

    JavaScript面向对象编程指南.pdf

    JavaScript作为一门浏览器语言的核心思想;面向对象编程的基础知识及其在... 《JavaScript面向对象编程指南》着重介绍JavaScript在面向对象方面的特性,展示如何构建强健的、可维护的、功能强大的应用程序及程序库

    JavaScript面向对象编程指南

    《JavaScript面向对象编程指南》内容包括:JavaScript作为一门浏览器语言的核心思想;面向对象编程的基础知识及其在JavaScript中的运用;数据类型、操作符以及流程控制语句;函数、闭包、对象和原型等概念,以代码...

    javascript面向对象编程

    JavaScript作为一门浏览器语言的核心思想;...如何实现JavaScript中缺失的面向对象特性,如对象的私有成员与私有方法;如何应用适当的编程模式,发挥JavaScript语言特有的优势;如何应用设计模式解决常见问题等。

    基于闭包的JavaScript面向对象编程框架.pdf

    基于闭包的JavaScript面向对象编程框架.pdf

    JavaScript面向对象程序设计

    JavaScript面向对象程序设计(1): 前言 JavaScript面向对象程序设计(2): 数组 JavaScript面向对象程序设计(3): 对象...JavaScript面向对象程序设计(7): 闭包 JavaScript面向对象程序设计(8): 优雅的封装还是执行的效率?

    JavaScript面向对象编程指南 英文版

    《JavaScript面向对象编程指南》内容包括:JavaScript作为一门浏览器语言的核心思想;面向对象编程的基础知识及其在JavaScript中的运用;数据类型、操作符以及流程控制语句;函数、闭包、对象和原型等概念,以代码...

    JavaScript面向对象编程指南 有书签

    《JavaScript面向对象编程指南》内容包括:JavaScript作为一门浏览器语言的核心思想;面向对象编程的基础知识及其在JavaScript中的运用;数据类型、操作符以及流程控制语句;函数、闭包、对象和原型等概念,以代码...

    JavaScript核心(对象、原型、继承、上下文、闭包、this).pdf

    面向对象概念(对象封装,各种继承,闭包原理,this作用域等)介绍清晰易懂

    JavaScript碎片—函数闭包(模拟面向对象)

    具体来说实现模拟面向对象主要是利用JavaScript函数闭包这个概念。由于JavaScript中的每一个function都会形成一个作用域,而如果变量声明在这个域中,那么外部是无法直接去访问,要想访问必须new出一个实例来,相当...

    JavaScript函数、闭包、原型、面向对象学习笔记

    给大家分享了一篇关于JavaScript函数、闭包、原型、面向对象的知识点学习笔记内容,有兴趣的朋友参考下。

    javascript面向对象技术基础 整理排版了一下

    javascript面向对象技术基础 整理排版了一下 外带了个闭包的文章,下了可以直接打印了

    js面向对象技术基础

    一个很好的学习javascript的资料,详细叙述了javascript面向对象的原理,并含有大量的程序例子说明。非常实用。

Global site tag (gtag.js) - Google Analytics