有趣的函数——function类型

函数实际上是对象,每个函数都是function类型的实例,具有属性和方法。

1、函数的定义方法

1)函数声明语法

function sum(num1,num2){//和函数表达式相比,它还有一个很好玩的特性,下面会讲到哦
return num1+num2;
}

2)函数表达式

var sum=function(sum1,sum2){return sum1+sum2;};//注意,后面有分号哦

3)函数构造函数

var sum=new Function("num1","num2","return num1+num2");//不推荐

不建议使用构造函数方法定义函数,这种方法会导致解析两次代码:第一次是解析常规ECMAscript代码,第二次是解析传入构造函数中的字符串,从而影响性能。

2、函数名

由于函数是对象,函数名实际上是一个指向函数对象的指针,不会和某个函数绑定。也就是说一个函数对象可能有多个名字。

function sum(num1,num2){
return num1+num2;
}
var sum1=sum;
alert(sum1(10,10));//
sum=null;
alert(sum1(10,10));//

如上面的代码所示,将sum置为null后,sum1依然可以调用该函数对象。

3、没有重载

声明两个同名函数时,后面的函数会覆盖前面的函数。

function sum(num1,num2){
return num1+num2;
}
function sum(num1,num2){
return (num1+num2-1);
}
alert(sum(10,10))//

实际上,上面的代码和下面的代码没什么区别。

function sum(num1,num2){
return num1+num2;
}
sum=function(num1,num2){
return (num1+num2-1);
}
alert(sum(10,10))//

4、函数声明与函数表达式

首先观察以下这两种代码

alert(sum(1));//
function sum(num1){
return num1+1;
}
alert(sum(1));//unexpected identifier在这一行发生错误
var sum=function(num1){
return num1+1;
};

发现了吧,解析器在向执行环境加载数据时,对函数 声明和函数表达式的处理并不相同,解析器会率先读取函数声明,并使其在执行任何代码之前可用,而函数表达式则必须等到解释器执行到它所在的代码行,才会真正被解释执行。

那,这又是为什么呢?

解释:在代码开始执行前,解析器就已经通过一个名叫函数声明提升的过程,读取并将函数声明添加到执行环境中。对代码求值时,js引擎会在第一遍声明函数并将其放在源代码树的顶部,这样,即使声明函数的代码在调用它的代码之后,JS引擎也能将函数声明提升到顶部。

5、作为值的函数

因为ECMAscript中的函数名本身就是变量,所以函数也可以作为值来使用。

比如下面

function callsomeFunction(someFunction,someArgument){
return someFunction(someFUnction,someArgument);
}

注意:上面的例子传给callcomeFunction的是someFunction和someArgument而不是执行后得结果

应用:

从一个函数中返回另一个函数,可以分情况在本函数中设置参数,有技巧的执行被嵌套的函数

function createCompareFuc(propertyName){
return function(obj1,obj2){
var value1=obj[propertyName];
var value2=obj[propertyName];
if(value1<value2){return -1;}
else if(value1>value2){return 1;}
else {return 0;}
};
}

如上面的代码,可以很方便的在一个函数中调用比较函数

6、函数内部属性

1)、callee

函数内部有两个特殊的对象:arguments和this。其中arguments有一个有趣的属性:callee,该属性是一个指针,指向拥有这个argumenets对象的函数。

callee属性主要用于消除函数名和函数的耦合。毕竟函数名只是函数对象的一个指针,如果在函数中直接用函数名的话,一旦函数名改变,这个函数对象的调用会产生错误

如下面这个阶乘函数

function fac(num){
if(num<=1){return 1;}
else {return num*fac(num-1);}
}

函数的执行与函数紧紧耦合,一旦函数名发生改变,则函数不可用。

这样改比较好

function fac(num){
if(num<=1){return 1;}
else {return num*argumenets.callee(num-1);}
}

2)、this

this,函数内部的另一个特殊对象,this引用的是函数据以执行的环境对象——也可以说是this值(全局环境下是window)

看看下面的例子:

window.color="red";
var o={color:"blue"};
function sayColor(){
alert(this.color);
}
sayColor();//"red"
var o.sayColor=sayColor;
o.sayColor();//"blue"

如上所示,sayColor()是在全局环境中定义并引用了this,由于this指向函数据以执行的环境对象,故在这个函数执行前,无法确定this的值。

当在全局环境下调用sayColor时,this引用的是全局对象window,换句话说,对this的求值会转变为对window.color的求值。而把这个函数赋给了对象o之后,该函数中this.color变成了o.color;

关于this:阮一峰大神有一篇博客讲的很透彻,链接看这里:http://www.ruanyifeng.com/blog/2018/06/javascript-this.html

3)、caller

ECMAscript5规范化的另一个函数对象的属性,除了Opera的早期版本不支持,其他浏览器都支持这个函数属性。这个属性中保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为null。例如:

function outer(){
inner();
}
function inner(){
alert(arguments.callee.caller);
}
outer();//alert的是outer

7、函数属性和方法

ECMAscript的prototype属性,就ECMAscript的引用类型来说,prototype是保存他们所有实例方法的真正所在,换句话说,诸如toString()、和valueOf()都保存在prototype名下,只不过是通过各自对象的实例访问罢了。在ECMAscript5中,prototype的属性不可枚举,因此使用for-in无法发现。

每个函数都包含两个非继承而来的方法:apply()和call()

这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值。

1)、apply()

apply()接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是Array的实例,也可以是Arguments对象。

function sum(num1,num2){
return num1+num2;
}
function callSum1(num1,num2){
return sum.apply(this,arguments);//传入arguments
}
funtion callSum2(num1,num2){
return sum.apply(this,[num1,num2]);//传入数组
}
alert(callSum1(10,10));//
alert(callSUm2(10,10));//

2)、call()

call()和apply()方法的作用相同,区别仅在于接收参数的方式不同,对于call()方法而言,接收的第一个参数是this值没有变化,有变化的是:其他参数必须直接传递给函数。

如下所示I:

funtion callSum2(num1,num2){
return sum.call(this,num1,num2);//传入数组
}

注意:传递参数其实并非call()和apply()的真正用武之地,这两种方法的真正强大的地方在于能够扩充函数赖以生存的作用域。

window.color="red";
var o={color:"blue"};
function sayColor(){
alert(this.color);
}
sayColor();//red
sayColor.call(this);//函数是在全局环境下调用的,故this指向window
sayColor.call(window);
sayColor.call(o);//用call改变了函数的执行环境,使其指向o。

使用call()和apply()来扩充作用域的最大好处就是,对象不用与方法有任何耦合关系,讲到this时引用的这个例子的第一个版本中,我们是将sayColor()函数放到对象o中,然后再通过对象o来调用它,现在有了call()和apply()就不用这么麻烦啦。

3)、bind()

ECMAscript定义的方法,这个方法创建一个函数的实例,其this值会被绑定到传给bind()函数的值。例如:

window.color="red";
var o={color:"blue"};
function sayColor(){
alert(this.color);
}
var objectSayColor=sayColor.bind(o);
objectSayColor();//blue

小红书第五章——引用类型之function类型的更多相关文章

  1. 读JS高级——第五章-引用类型 _记录

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. Javascript高级程序设计复习——第五章引用类型 【原创】

    5.1  Object类型 1:创建Object实例的两种方式 ①new构造法 var obj1 = new Object(); 注意大写!不传递参数时可以省略圆括号 obj1.hehe = &quo ...

  3. JavaScript高级程序设计学习笔记第五章--引用类型(函数部分)

    四.Function类型: 1.函数定义的方法: 函数声明:function sum (num1, num2) {return num1 + num2;} 函数表达式:var sum = functi ...

  4. JAVASCRIPT高程笔记-------第五章 引用类型

    一.Object类型 1.1创建方式 ①new关键字 : var person = new Oject(); ②给定直接量: var person = { name : "zhangsan& ...

  5. 引用类型之Function类型

    Function类型 ECMAScript中最有意思的就是函数了,有意思的根源,在于函数实际上是对象.每个函数都是Function的实例,具有属性和方法.而重要的一点是,函数名,不过是指向函数的指针, ...

  6. JavaScript高级程序设计学习笔记第五章--引用类型

    一.object类型 1.创建object类型的两种方式: 第一种,使用构造函数 var person = new Object();或者是var person={};/与new Object()等价 ...

  7. 读书笔记 - js高级程序设计 - 第五章 引用类型

      引用类型 和 类 不是一个概念 用typeof来检测属性是否存在 typeof args.name == "string"  需要实验 访问属性的方法 .号和[] 一般情况下要 ...

  8. JavaScript高级程序设计(第三版)第五章 引用类型

    5.2 Array类型 var colors = new Array(3); //创建一个包含3项的数组 var names = new Array("Greg"); //创建一个 ...

  9. OpenGL蓝宝书第五章代码勘误以及惯性坐标系去解释模型变换:Pyramid.cpp

    假设你也发现依照教程代码完毕贴图时,你会底面的坐标和寻常顶点坐标正负相反,比方-1.0f, -1.0f, -1.0f这个顶点相应的却是世界坐标中1.0f,-1.0f,1.0f 问题到底出如今哪里? 原 ...

随机推荐

  1. Nginx + fastcgi + php 的原理与关系

    CGI:Common Gateway Interface 公共网关接口,web服务器和脚本语言通信的一个标准.接口.协议[协议] FastCGI:CGI协议的升级版[协议] PHP-CGI: 实现了C ...

  2. 【转】Python实现智能五子棋

    前言 棋需要一步一步下,人生需要一步一步走.千里之行,始于足下,九层之台,起于累土. 用Python五子棋小游戏. 基本环境配置 版本:Python3 相关模块: 本文所做工作如下: (1) 五子棋界 ...

  3. Python之读取用户指令和格式化打印

    Python之读取用户指令和格式化打印 一.读取用户指令 当你的程序要接收用户输入的指令时,可以用input函数: name = input("请输入你的名字:") print(& ...

  4. 变量声明关键字var ,let,const

    今天带大家了解的是比较有趣的几个变量声明关键字var,let,const. 我们在最初接触JS的时候,变量是我们重要的一个组成部分,在使用时规定必须要先进行声明,否则网页将会报错: console.l ...

  5. Python——面向对象编程

    面向对象编程是一种程序设计思想,把对象作为程序的基本单元,一个对象里面包含了数据以及操作数据的方法,称为类的属性和方法. 基础-定义.实例化.实例属性 用class来定义对象,类名首字母大写,如果这个 ...

  6. 第一篇 特征提取以及openvslam中的相关实现详解

    参考尺度空间理论 金字塔 当用一个机器视觉系统分析未知场景时,计算机没有办法预先知道图像中物体尺度,因此,我们需要同时考虑图像在多尺度下的描述,获知感兴趣物体的最佳尺度.所以在很多时候,我们会在将图像 ...

  7. 在.net core wep项目中使用Session

    第1步:添加包引用 Install-Package Microsoft.AspNetCore.Session 第2步:添加代码启用Session 在项目Startup.cs文件的ConfigureSe ...

  8. CodeForces 620D Professor GukiZ and Two Arrays 双指针

    Professor GukiZ and Two Arrays 题解: 将a数组都sort一遍之后, b数组也sort一遍之后. 可以观察得到 对于每一个ai来说, 整个数组bi是一个V型的. 并且对于 ...

  9. JDBC编程之预编译SQL与防注入

    在JDBC编程中,常用Statement.PreparedStatement 和 CallableStatement三种方式来执行查询语句,其中 Statement 用于通用查询, PreparedS ...

  10. 2、pytest中文文档--使用和调用

    目录 使用和调用 通过python -m pytest调用pytest *pytest执行结束时返回的状态码 pytest命令执行结束,可能会返回以下六种状态码: *获取帮助信息 最多允许失败的测试用 ...