js原生之函数
1.函数作为参数传给其他函数:
data.sort(function(a,b){return a-b})
//关于数组的sort函数,其回调函数返回负值,a在b之前
//正值,b在a之前
2.函数定义好后立即调用
var temp=(function(x){return x*x})(10);
function foo(){};//函数声明,可以提前
var foo=function(){};//表达式定义函数,不能提前
3.JAVASCRIPT的函数可以嵌套在其他函数里面
function hy(a,b){
function square(x){return x*x;}
return Math.sqrt(square(a)+square(b));
}
4.函数声明语句并非真正的语句,他们可以出现在全局代码里,或者内嵌在其他函数内,
但是它们并不能出现在循环,条件判断或者try/catch语句中。
但函数定义表达式可以出现在javascript的任何地方
5.jquery的方法链式调用原理
$(":header").map(function(){return this.id;}).get().set();
当方法不需要返回值时,建议将其返回值定为return this;
这样就可以实现方法的链式调用。
6.嵌套函数中this的指向问题
var o={
m:function(){
var This=this;
f();
function f(){
console.log(this);
console.log(This);
}
}
};
o.m();
以上示例中,对象o内定义了函数m(),在函数m()内定义函数f()并调用
在f内的this并不指向调用外层函数的上下文,而是指向全局对象
其返回值:
Window Html001.html//严格模式下返回undefined
Object { m=function()}
7.构造函数的调用
如果在函数或者方法调用前带有关键字new,就形成了构造函数调用
var o=new Object();
var o=new Object;//没有形参时可以省略掉Object后面的括号
一旦使用了new关键字调用构造函数,构造函数内的this就会指向new出来的新对象
var o={
m:function(){
var This=this;
f();
function f(){
//console.log(this);
console.log(This===o);
}
}
};
new o.m();//函数内部this不指向上下文,也就是不指向o
8.间接调用,call()与aplly()
允许函数显示的指定函数运行的域,也就是规定this的指向
foo.call(obj1,args1...);
foo.apply(obj2,arg[...]);
9.函数调用的形参与实参
function foo(arg1,arg2,arg3....){}
foo(arg1);
如果函数调用时传入的实参比函数定义时的形参数要少,则多的形参被定义为undefined
这个特性可用来实现类似函数重载的功能
function getPropertyName(o,/*可选参数,数组a*/arr) {
// body...
var arr=arr||[];//undefined在逻辑运算中返回false,若调用时a不存在,则将arr赋予新的空数组[]
for(var p in o) arr.push(p);
return arr;
}
getPropertyName(o);
getPropertyName(o,myArray);
设计原则:
当使用这种可选参数来创建函数时,满足原则1.可选参数放在参数列表最后。2./**/用注释说明可选参数
3.调用函数时,可选参数位置最好显式的传入null作为占位符。
function foo(arg1,arg2,arg3....){}
foo(arg1);
再回到这个函数调用例子,当实参列表超过形参列表时,函数内部无法显式获得超过部分的引用
此时可用arguments类数组来调用,事实上arguments[]数组内存储着传进来的所有实参
arguments也包含着length属性;
实参对象的应用实例:
(function (x,y,z){
if(arguments.length!=3){
throw new Error(
"该函数必须传入3个参数"
);
}
console.log(x+y+z);
}(1,2));
运行结果:Error: 该函数必须传入3个参数
用于验证实参列表个数,只有在实参数目为3时,才执行函数。
/**
复习:类数组对象
js的数组有四大特性:
1.有新元素加入数组时,自动更新length
2.设置length为一个较小值时将截断数组
3.从Array.prototype继承一些方法
4.其类属性为“Array”
这四个特性让数组与类数组对象区分开来
而像arguments这样的类数组对象,可以理解为其属性名刚好为从0开始的非负整数序列
且有个length属性记录它的属性长度
而区别在于length没有数组的特性1,2.
且没有从Array.prototype继承方法
但是可以利用call临时继承调用
var a={"0":"a","1":"b","2":"c"};
Array.prototype.join.call(a,"+") //"a+b+c"
Array.map(function(x){return x*x}) //ecma5,不修改原数组,返回一个数组副本,其中的每一项都是
参数内函数的返回值。
*/
细说实参对象arguments://该对象的可枚举属性仅有实参
属性callee与caller
callee:指代当前正在执行的函数
caller:调用当前正在执行的函数的函数//!--暂时无法理解这句话--!
callee可用在匿名函数中实现递归
function (x) {
// body...
if(x<1)return 1;
return x*arguments.callee(x-1);//此处的arguments.callee()就是在调用函数本身
}
10.将对象属性用作实参,减少记忆参数列表顺序,在参数列表巨大的情况下
function arrayCopy(a,a_start,b,b_start,length) {//该函数将a数组从a_start处复制length个元素至b数组中起始位置b_start位置
// 要记忆这些形参的顺序实在不容易
}
function easyCopy(argument) {
// body...
arrayCopy(arguments.from,
arguments.from_start||0,
arguments.to,
arguments.to_start||0,
arguments.length
)
}
//在调用easyCopy时,只需传入一个匿名对象就可以了
a=[1,2,3,4];
b=[];
easyCopy(
{from:a,to:b,length:4}//传入匿名对象
);
11.作为值的函数
在js中,函数也可以作为--实参,传入别的函数参数列表;
看如下一个函数的定义
function square(x) {return x*x}
这个定义创建一个新的函数对象,并将其值赋给square;
var s=square;//现在s和square指代同一个函数
类似数组的sort()方法,接受一个函数
写法Array.sort(function (a,b) {return a-b;
// body...
})
或者Array.sort(bj);//bj指代一个函数
12.自定义函数属性
js中函数是对象,所以可以定义函数的属性,用于计数之类的工作
比如要计算一个函数的调用次数,又不想定义一个全局变量
则可以:
foo.times=0;
function foo(argument) {
// body...
foo.times++;
}//还有更多用途,
//定义缓存
foo.times=0;//判断if语句执行次数的标记
function foo(x){
if(x<1&&x!=Math.round(x)) throw new Error("foo()函数参数为大于1的正整数");
if( !(x in foo)){
foo.times++;
console.log(foo.times);
foo[x]=x*foo(x-1);//将已经计算出来的值存储进foo[]类数组之中
}
return foo[x];
}
foo[1]=1;
foo(11);
foo(10);//从返回结果可以看到,此处并没进入if判断中,减少了很多次运算
foo(12);
foo(0.6);//验证数值输入的正确性
代码运行返回结果:
1
Html001.html (第 23 行)
2
Html001.html (第 23 行)
3
Html001.html (第 23 行)
4
Html001.html (第 23 行)
5
Html001.html (第 23 行)
6
Html001.html (第 23 行)
7
Html001.html (第 23 行)
8
Html001.html (第 23 行)
9
Html001.html (第 23 行)
10
Html001.html (第 23 行)
11
Html001.html (第 23 行)
Error: foo()函数参数为大于1的正整数
13.作为命名空间的函数
类似jquery这样的库的做法
a.(function (argument) {
// body...
}())
b.(function (argument) {
// body...
})();
定义一个匿名函数并立即调用,在匿名函数内的变量就不会污染全局命名空间
对于包裹function的圆括号的解释:
function前面没有圆括号时,js会将function解释为函数声明语句,这样就无法立即执行
而加上圆括号,或是其他运算符,则会被解释为函数定义表达式。
14.闭包
js中,函数的执行依赖于变量作用域,这个作用域是在函数定义时创建的,而不是在函数执行时。
例子1:
var scope="global scope";
function checkscope() {
// body...
var scope="local scope";
function f() {
// body...
return scope;
}
return f();//f在checkscope内部执行时很容易理解,它寻找f的作用域,在checkscope函数内找到scope就返回了
}
checkscope();
例子2:
var scope="global scope";
function checkscope() {
// body...
var scope="local scope";
function f() {
// body...
return scope;
}
return f;
}
checkscope()(); //在全局执行chechscope内部的函数f;因为闭包的存在,f()也是在其作用域链内寻找scope
//这个作用域链在函数定义之初就开始存在
例子3:
foo.times=0;
function foo(argument) {
// body...
foo.times++;
}//这是12小结的一个例子,foo.times来记录函数foo的调用次数
下面用闭包来改写它。
var times=(function () {
var count=0;
return function(){
return count++;
}
}())//当外层作为命名空间的函数返回之后,除了timer(),任何函数或语句都访问不到其内部的count
//而又因为times在外部使用其作用域链上的count,所以count会作为一个变量一直存在内存
//times()每次调用都访问的是内存中已经存在的count;故可以充当计数器
function foo(argument) {
// body...
times();
}
例子4:
function counter(){
var count=0;
return {
count:function(){return ++count;},
reset:function(){return count=0;}
}//返回一个包含两个方法的匿名对象
}
var obj1=counter();
var obj2=counter();//obj1和obj2接受到的是不同的Object。所以他们的count互不干涉
console.log(obj1.count());
console.log(obj1.count());
console.log(obj1.count());
例子5://ECMA5中的变体
function counter(n){
return {
get count(){
return ++n;
},
set count(m){
if (m<=n) {throw Error("您设置的n太小了")}
return n=m;
}
}
}
var obj=counter(100);
console.log(obj.count);
console.log(obj.count);
console.log(obj.count);
console.log(obj.count=200);
console.log(obj.count);
console.log(obj.count);
利用setter和getter来定义计数器count,给予计数器设置初值和临时更改的方法
而count则是obj的私有属性,且通过赋值修改必须遵循get方法设置的条件
例子6://闭包实现私有属性的经典做法
function addPrivateProperty(o,name,predicate) {
// body...
var value;
o["get"+name]=function () {
return value;
};
o["set"+name]=function(v){
if (predicate&&!predicate(v)) {throw new Error("数据未通过predicate函数合法性验证")}
value=v;
}
}
var o={};
addPrivateProperty(o,"Name",function(v){return typeof v=="string";});
addPrivateProperty(o,"Age");//未进行合法性验证
o.setName("wangjue");
o.setAge(18);
console.log(o.getName());
console.log(o.getAge());
为何能够不断添加属性,是因为每个属性的set和get方法组--存在于不同的作用域链,
可以利用如下例子进行例证:
function constfunc(v){
var value;
return function(){
value=v;
return value;};
}
var fun1=constfunc("arr1");
var fun2=constfunc();//发现只要传递的参数不一样,就会创建新的闭包
console.log(fun1());//=>arr1
console.log(fun2());//=>undefine value并未共享
例子7:
function constfunc(v) {
// body...
return function(){return v;};
}//一个总是返回v的函数
for(var i=0;i<10;i++) fun[i]=constfunc(i);
fun[5]();//=》返回值为5
上述代码循环创建了很多闭包
总结性语言:多个嵌套函数并不会将作用域链上的私有成员复制一份,他们是共享的。
例子8:
嵌套函数内,也就是闭包,无法访问外部函数的arguments和this
function foo(arg1,arg2) {
// body...
var self=this;
var outArguments=arguments;
return function () {
return self+outArguments.toString(" ");
}
}
前文已经提过,嵌套函数内部使用this,指代的是全局环境window,或者undefined
//闭包 end
15.函数的属性,方法和构造方法
在js中,函数是特殊的对象,故其也有对象的一些性质
所以其也拥有属性和方法,能够用Function()构造函数创建。
(1)length:函数对象也拥有一个length属性,其值为函数声明时的形参列表的表长。
//一个检测实参与形参是否数量相等的函数
function check(argument) {
// body...
if(argument.length!=argument.callee.length) throw new Error("传入参数数量不对")
}
function test(arg1,arg2) {
// body...
check(arguments);
return arg1+arg2;
}
test(1,2);
(2)prototype每一个函数都有一个原型属性
(3)call(),与aplly()方法
(4)bind(); //ECMA5中新增的方法,f.bind(obj);将函数f绑定至obj上
兼容性解决:
function bind(f,o) {
// body...
if(f.bind) return f.bind(o);
else{
return f.apply(o,arguments);
}
}//这里的自定义bind()函数就是将f绑定至o下,且立即执行
function f(argument) {
// body...
}
f.bind(o,agr1,arg2);//bind除第一个参数外,后面的几个参数都将传入f,参与函数调用
(5)toString()//返回函数的完整源码
(6)Function()构造函数;
16.函数式编程
类似数组的reduce(),map()之类的方法就是函数式编程的例子
17.高阶函数,所谓高阶函数就是操作函数的函数,其传入函数作为参数,返回值也是函数
18.记忆函数
//闭包的实例
function memorize(foo){
var cache={};
return function () {
// body...
var key=arguments.length+Array.prototype.join.call(arguments,",");//作为缓存的键
if(key in cache) return cache[key];//若在cache中找到了key,则直接返回内存中的值
else {
cache[key]=foo.apply(this,arguments);//内存中没有,则赋值。
return counter[key];//
}
}
}
//当我们使用一个递归函数时,往往要使用记忆功能
var factorial=memorize(function (n) {
// body...
return n<=1?1:n*factorial(n-1);
})
factorial(5);
js原生之函数的更多相关文章
- js原生的url操作函数,及使用方法。(附:下边还有jquery对url里的中文解码函数)
js原生的url操作函数,完善的. /*****************************/ /* 动态修改url */ /*****************************/ var ...
- js原生函数一些封装
这是一些js原生封装的函数,主要是为了兼容IE浏览器,如下 获取css样式 function getStyle(ele, prop) { if(window.getComputedStyle) { r ...
- js原生代码实现轮播图案例
一.轮播图是现在网站网页上最常见的效果之一,对于轮播图的功能,要求不同,效果也不同! 我们见过很多通过不同的方式,实现这一效果,但是有很多比较麻烦,而且不容易理解,兼容性也不好. 在这里分享一下,用j ...
- JS原生效果瀑布流布局的实现(一)
JS原生效果 实现: HTML页面布局: <!DOCTYPE html> <html> <head> <meta charset="utf-8&qu ...
- js产生随机数函数
函数: //产生随机数函数 function RndNum(n){ var rnd=""; for(var i=0;i<n;i++) rnd+=Math.floor(Math ...
- 图片轮播(左右切换)--JS原生和jQuery实现
图片轮播(左右切换)--js原生和jquery实现 左右切换的做法基本步骤跟 上一篇文章 淡入淡出 类似,只不过修改了一些特定的部分 (1)首先是页面的结构部分 对于我这种左右切换式 1.首先是个外 ...
- 图片轮播(淡入淡出)--JS原生和jQuery实现
图片轮播(淡入淡出)--js原生和jquery实现 图片轮播有很多种方式,这里采用其中的 淡入淡出形式 js原生和jQuery都可以实现,jquery因为封装了很多用法,所以用起来就简单许多,转换成j ...
- js原生 + jQuery实现页面滚动字幕
js原生/jQuery实现页面滚动字幕效果 17:45:49 在新闻列表或者文章列表信息等页面中很容易要求实现字幕滚动的效果,以下为简单的实现页面中滚动字幕的效果 1.jQuery实现页面滚动字幕效果 ...
- js中getByClass()函数
js中getByClass()函数进化史 对于js来说,我想每一个刚接触它的人都应该会抱怨:为什么没有一个通过class来获取元素的方法.尽管现在高版本的浏览器已经支持getElementsByCla ...
随机推荐
- Gerald and Giant Chess
Gerald and Giant Chess time limit per test 2 seconds memory limit per test 256 megabytes input stand ...
- The Wall (medium)
The Wall (medium) Heidi the Cow is aghast: cracks in the northern Wall? Zombies gathering outside, f ...
- 开心的金明<0-1背包>
题意:0-1背包经典题: 不多述,直接上代码: 1.二维数组表示法: #include<cstdio> #include<iostream> #include<algor ...
- 使用Three.js渲染Sketchup导出的dae
打算做个轮盘游戏,直接上3D吧. 第一步:制作模型 3DMax和Maya下载和破解比较麻烦, 就用之前的Sketchup来试试吧. 最后效果图: 俯视图 仰视图 制作步骤: 1 先画一个圆 2 从圆心 ...
- .NET反射应用
.Net中,在编写框架时,反射是最长用的一个知识点,在这举个小例子,旨在说明反射如何应用:本文只程序中只涉及到System.Type的应用,通过这个类可以访问关于任何数据类型的信息,注释部分涉及到Sy ...
- svn版本库通过svn://127.0.0.1/不能导出的问题解决了!!
svn:本地file:///E:/SvnServerHome没问题,但是换为svn://192.168.1.100/SvnServerHome 报异常. 配置http协议访问svn 原文:http:/ ...
- 小米1S iptables禁止443端口
shell@android:/system/bin # ./iptables -A INPUT -p tcp --dport 443 -j DROP./iptables -A INPUT -p tcp ...
- andorid之摄像头驱动流程--MTK平台
原文地址:andorid之摄像头驱动流程--MTK平台 作者:守候心田 camera成像原理: 景物通过镜头生产光学图像投射到sensor表面上,然后转为模拟电信号,经过数模变成数字图像信号,在经过D ...
- dependency injection(2)
https://segmentfault.com/a/1190000002424023
- Openlayers实现第一张地图
<html><head><title>OpenLayers Hello World</title> <style type="text/ ...