概述

函数的声明

JavaScript 有三种声明函数的方法

  • function 命令

    • function命令声明的代码区块,就是一个函数。function命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数。函数体放在大括号里面。
    • 这叫做函数的声明(Function Declaration)。
  1. function print(s) {
  2. console.log(s);
  3. }
  • 函数表达式

    • 除了用function命令声明函数,还可以采用变量赋值的写法。
  1. var print = function(s) {
  2. console.log(s);
  3. };

这种写法将一个匿名函数赋值给变量。这时,这个匿名函数又称函数表达式(Function Expression),因为赋值语句的等号右侧只能放表达式。

采用函数表达式声明函数时,function命令后面不带有函数名。如果加上函数名,该函数名只在函数体内部有效,在函数体外部无效。

  1. var print = function x(){
  2. console.log(typeof x);
  3. };
  4. // ReferenceError: x is not defined
  5. print()
  6. // function

上面代码在函数表达式中,加入了函数名x。这个x只在函数体内部可用,指代函数表达式本身,其他地方都不可用。这种写法的用处有两个,一是可以在函数体内部调用自身,二是方便除错(除错工具显示函数调用栈时,将显示函数名,而不再显示这里是一个匿名函数)。因此,下面的形式声明函数也非常常见。

  1. var f = function f() {};

需要注意的是,函数的表达式需要在语句的结尾加上分号,表示语句结束。而函数的声明在结尾的大括号后面不用加分号。总的来说,这两种声明函数的方式,差别很细微,可以近似认为是等价的。

  • Function 构造函数
  1. var add = new Function(
  2. 'x',
  3. 'y',
  4. 'return x + y'
  5. );
  6. // 等同于
  7. function add(x, y) {
  8. return x + y;
  9. }

上面代码中,Function构造函数接受三个参数,除了最后一个参数是add函数的“函数体”,其他参数都是add函数的参数。

你可以传递任意数量的参数给Function构造函数,只有最后一个参数会被当做函数体,如果只有一个参数,该参数就是函数体。

  1. var foo = new Function(
  2. 'return "hello world";'
  3. );
  4. // 等同于
  5. function foo() {
  6. return 'hello world';
  7. }

Function构造函数可以不使用new命令,返回结果完全一样。

总的来说,这种声明函数的方式非常不直观,几乎无人使用。

函数的重复声明

如果同一个函数被多次声明,后面的声明就会覆盖前面的声明

圆括号运算符,return 语句和递归

调用函数时,要使用圆括号运算符。圆括号之中,可以加入函数的参数

函数体内部的return语句,表示返回。JavaScript 引擎遇到return语句,就直接返回return后面的那个表达式的值,后面即使还有语句,也不会得到执行。也就是说,return语句所带的那个表达式,就是函数的返回值。return语句不是必需的,如果没有的话,该函数就不返回任何值,或者说返回undefined。

函数可以调用自身,这就是递归(recursion)

第一等公民

JavaScript 语言将函数看作一种值,与其它值(数值、字符串、布尔值等等)地位相同。凡是可以使用值的地方,就能使用函数。比如,可以把函数赋值给变量和对象的属性,也可以当作参数传入其他函数,或者作为函数的结果返回。函数只是一个可以执行的值,此外并无特殊之处。

由于函数与其他数据类型地位平等,所以在 JavaScript 语言中又称函数为第一等公民。

函数名的提升

JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。所以,下面的代码不会报错。

  1. f();
  2. function f() {}

表面上,上面代码好像在声明之前就调用了函数f。但是实际上,由于“变量提升”,函数f被提升到了代码头部,也就是在调用之前已经声明了。但是,如果采用赋值语句定义函数,JavaScript 就会报错。

  1. f();
  2. var f = function (){};
  3. // TypeError: undefined is not a function

上面的代码等同于下面的形式。

  1. var f;
  2. f();
  3. f = function () {};

上面代码第二行,调用f的时候,f只是被声明了,还没有被赋值,等于undefined,所以会报错。因此,如果同时采用function命令和赋值语句声明同一个函数,最后总是采用赋值语句的定义。

  1. var f = function () {
  2. console.log('1');
  3. }
  4. function f() {
  5. console.log('2');
  6. }
  7. f() // 1

函数的属性和方法

name 属性

函数的name属性返回函数的名字

如果是通过变量赋值定义的函数,那么name属性返回变量名,但是如果变量的值是一个具名函数,那么name属性返回function关键字之后的那个函数名。

name属性的一个用处,就是获取参数函数的名字

  1. var myFunc = function () {};
  2. function test(f) {
  3. console.log(f.name);
  4. }
  5. test(myFunc) // myFunc

length 属性

函数的length属性返回函数预期传入的参数个数,即函数定义之中的参数个数

面代码定义了空函数f,它的length属性就是定义时的参数个数。不管调用时输入了多少个参数,length属性始终等于2。

length属性提供了一种机制,判断定义时和调用时参数的差异,以便实现面向对象编程的“方法重载”(overload)。

toString()

函数的toString方法返回一个字符串,内容是函数的源码。

对于那些原生的函数,toString()方法返回function (){[native code]}

函数内部的注释也可以返回

利用这一点,可以变相实现多行字符串

  1. var multiline = function (fn) {
  2. var arr = fn.toString().split('\n');
  3. return arr.slice(1, arr.length - 1).join('\n');
  4. };
  5. function f() {/*
  6. 这是一个
  7. 多行注释
  8. */}
  9. multiline(f);
  10. // " 这是一个
  11. // 多行注释"

函数作用域

定义

作用域(scope)指的是变量存在的范围。在 ES5 的规范中,JavaScript 只有两种作用域:一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;另一种是函数作用域,变量只在函数内部存在。ES6 又新增了块级作用域,本教程不涉及。

对于顶层函数来说,函数外部声明的变量就是全局变量(global variable),它可以在函数内部读取。

在函数内部定义的变量,外部无法读取,称为“局部变量”(local variable)。

函数内部定义的变量,会在该作用域内覆盖同名全局变量。

注意,对于var命令来说,局部变量只能在函数内部声明,在其他区块中声明,一律都是全局变量。

函数内部的变量提升

与全局作用域一样,函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部

函数本身的作用域

函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关

总之,函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域

同样的,函数体内部声明的函数,作用域绑定函数体内部

参数

概述

函数运行的时候,有时需要提供外部数据,不同的外部数据会得到不同的结果,这种外部数据就叫参数。

参数的省略

函数参数不是必需的,JavaScript 允许省略参数。

运行时无论提供多少个参数(或者不提供参数),JavaScript 都不会报错。省略的参数的值就变为undefined。需要注意的是,函数的length属性与实际传入的参数个数无关,只反映函数预期传入的参数个数。

但是,没有办法只省略靠前的参数,而保留靠后的参数。如果一定要省略靠前的参数,只有显式传入undefined。

传递方式

传递:

  • 原始类型:传递本身的值
  • 引用类型:传递引用的地址值

函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value)。这意味着,在函数体内修改参数值,不会影响到函数外部。

但是,如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。也就是说,传入函数的原始值的地址,因此在函数内部修改参数,将会影响到原始值。

同名参数

如果有同名的参数,则取最后出现的那个值

  1. function f(a, a) {
  2. console.log(a);
  3. }
  4. f(1, 2) // 2

上面代码中,函数f有两个参数,且参数名都是a。取值的时候,以后面的a为准,即使后面的a没有值或被省略,也是以其为准。

  1. function f(a, a) {
  2. console.log(a);
  3. }
  4. f(1) // undefined

调用函数f的时候,没有提供第二个参数,a的取值就变成了undefined。这时,如果要获得第一个a的值,可以使用arguments对象。

  1. function f(a, a) {
  2. console.log(arguments[0]);
  3. }
  4. f(1) // 1

arguments 对象

由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。这就是arguments对象的由来。

arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。

  1. var f = function (one) {
  2. console.log(arguments[0]);
  3. console.log(arguments[1]);
  4. console.log(arguments[2]);
  5. }
  6. f(1, 2, 3)
  7. // 1
  8. // 2
  9. // 3

正常模式下,arguments对象可以在运行时修改。

  1. var f = function(a, b) {
  2. arguments[0] = 3;
  3. arguments[1] = 2;
  4. return a + b;
  5. }
  6. f(1, 1) // 5

上面代码中,函数f调用时传入的参数,在函数内部被修改成3和2。

严格模式下,arguments对象与函数参数不具有联动关系。也就是说,修改arguments对象不会影响到实际的函数参数。

  1. var f = function(a, b) {
  2. 'use strict'; // 开启严格模式
  3. arguments[0] = 3;
  4. arguments[1] = 2;
  5. return a + b;
  6. }
  7. f(1, 1) // 2

上面代码中,函数体内是严格模式,这时修改arguments对象,不会影响到真实参数a和b。

通过arguments对象的length属性,可以判断函数调用时到底带几个参数。

  1. function f() {
  2. return arguments.length;
  3. }
  4. f(1, 2, 3) // 3
  5. f(1) // 1
  6. f() // 0

与数组的关系

需要注意的是,虽然arguments很像数组,但它是一个对象。数组专有的方法(比如slice和forEach),不能在arguments对象上直接使用。

如果要让arguments对象使用数组方法,真正的解决方法是将arguments转为真正的数组。下面是两种常用的转换方法:slice方法和逐一填入新数组。

callee 属性

arguments对象带有一个callee属性,返回它所对应的原函数。

  1. var f = function () {
  2. console.log(arguments.callee === f);
  3. }
  4. f() // true

可以通过arguments.callee,达到调用函数自身的目的。这个属性在严格模式里面是禁用的,因此不建议使用。

闭包

闭包(closure)是 JavaScript 语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现。

理解闭包,首先必须理解变量作用域。前面提到,JavaScript 有两种作用域:全局作用域和函数作用域。函数内部可以直接读取全局变量。

  1. var n = 999;
  2. function f1() {
  3. console.log(n);
  4. }
  5. f1() // 999

上面代码中,函数f1可以读取全局变量n。

但是,函数外部无法读取函数内部声明的变量。

  1. function f1() {
  2. var n = 999;
  3. }
  4. console.log(n)
  5. // Uncaught ReferenceError: n is not defined(

上面代码中,函数f1内部声明的变量n,函数外是无法读取的。

如果出于种种原因,需要得到函数内的局部变量。正常情况下,这是办不到的,只有通过变通方法才能实现。那就是在函数的内部,再定义一个函数。

  1. function f1() {
  2. var n = 999;
  3. function f2() {
  4.   console.log(n); // 999
  5. }
  6. }

上面代码中,函数f2就在函数f1内部,这时f1内部的所有局部变量,对f2都是可见的。但是反过来就不行,f2内部的局部变量,对f1就是不可见的。这就是 JavaScript 语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。

既然f2可以读取f1的局部变量,那么只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了吗!

  1. function f1() {
  2. var n = 999;
  3. function f2() {
  4. console.log(n);
  5. }
  6. return f2;
  7. }
  8. var result = f1();
  9. result(); // 999

上面代码中,函数f1的返回值就是函数f2,由于f2可以读取f1的内部变量,所以就可以在外部获得f1的内部变量了。

闭包就是函数f2,即能够读取其他函数内部变量的函数。由于在 JavaScript 语言中,只有函数内部的子函数才能读取内部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。闭包最大的特点,就是它可以“记住”诞生的环境,比如f2记住了它诞生的环境f1,所以从f2可以得到f1的内部变量。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。

闭包的最大用处有两个,一个是可以读取函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。请看下面的例子,闭包使得内部变量记住上一次调用时的运算结果。

  1. function createIncrementor(start) {
  2. return function () {
  3. return start++;
  4. };
  5. }
  6. var inc = createIncrementor(5);
  7. inc() // 5
  8. inc() // 6
  9. inc() // 7

上面代码中,start是函数createIncrementor的内部变量。通过闭包,start的状态被保留了,每一次调用都是在上一次调用的基础上进行计算。从中可以看到,闭包inc使得函数createIncrementor的内部环境,一直存在。所以,闭包可以看作是函数内部作用域的一个接口。

为什么会这样呢?原因就在于inc始终在内存中,而inc的存在依赖于createIncrementor,因此也始终在内存中,不会在调用结束后,被垃圾回收机制回收。

闭包的另一个用处,是封装对象的私有属性和私有方法。

  1. function Person(name) {
  2. var _age;
  3. function setAge(n) {
  4. _age = n;
  5. }
  6. function getAge() {
  7. return _age;
  8. }
  9. return {
  10. name: name,
  11. getAge: getAge,
  12. setAge: setAge
  13. };
  14. }
  15. var p1 = Person('张三');
  16. p1.setAge(25);
  17. p1.getAge() // 25

上面代码中,函数Person的内部变量_age,通过闭包getAge和setAge,变成了返回对象p1的私有变量。

注意,外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。

立即调用的函数表达式(IIFE)

在 JavaScript 中,圆括号()是一种运算符,跟在函数名之后,表示调用该函数。比如,print()就表示调用print函数。

有时,我们需要在定义函数之后,立即调用该函数。这时,你不能在函数的定义之后加上圆括号,这会产生语法错误。

  1. function(){ /* code */ }();
  2. // SyntaxError: Unexpected token (

产生这个错误的原因是,function这个关键字即可以当作语句,也可以当作表达式。

  1. // 语句
  2. function f() {}
  3. // 表达式
  4. var f = function f() {}

为了避免解析上的歧义,JavaScript 引擎规定,如果function关键字出现在行首,一律解释成语句。因此,JavaScript 引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。

解决方法就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。

  1. (function(){ /* code */ }());
  2. // 或者
  3. (function(){ /* code */ })();

上面两种写法都是以圆括号开头,引擎就会认为后面跟的是一个表示式,而不是函数定义语句,所以就避免了错误。这就叫做“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称 IIFE。

注意,上面两种写法最后的分号都是必须的。如果省略分号,遇到连着两个 IIFE,可能就会报错。

  1. // 报错
  2. (function(){ /* code */ }())
  3. (function(){ /* code */ }())

上面代码的两行之间没有分号,JavaScript 会将它们连在一起解释,将第二行解释为第一行的参数。

推而广之,任何让解释器以表达式来处理函数定义的方法,都能产生同样的效果,比如下面三种写法。

  1. var i = function(){ return 10; }();
  2. true && function(){ /* code */ }();
  3. 0, function(){ /* code */ }();

甚至像下面这样写,也是可以的。

  1. !function () { /* code */ }();
  2. ~function () { /* code */ }();
  3. -function () { /* code */ }();
  4. +function () { /* code */ }();

通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

  1. // 写法一
  2. var tmp = newData;
  3. processData(tmp);
  4. storeData(tmp);
  5. // 写法二
  6. (function () {
  7. var tmp = newData;
  8. processData(tmp);
  9. storeData(tmp);
  10. }());

上面代码中,写法二比写法一更好,因为完全避免了污染全局变量。

eval 命令

基本用法

eval命令接受一个字符串作为参数,并将这个字符串当作语句执行。

  1. eval('var a = 1;');
  2. a // 1

上面代码将字符串当作语句运行,生成了变量a。

如果参数字符串无法当作语句运行,那么就会报错。

  1. eval('3x') // Uncaught SyntaxError: Invalid or unexpected token

放在eval中的字符串,应该有独自存在的意义,不能用来与eval以外的命令配合使用。举例来说,下面的代码将会报错。

  1. eval('return;'); // Uncaught SyntaxError: Illegal return statement

上面代码会报错,因为return不能单独使用,必须在函数中使用。

如果eval的参数不是字符串,那么会原样返回。

  1. eval(123) // 123

eval没有自己的作用域,都在当前作用域内执行,因此可能会修改当前作用域的变量的值,造成安全问题。

  1. var a = 1;
  2. eval('a = 2');
  3. a // 2

上面代码中,eval命令修改了外部变量a的值。由于这个原因,eval有安全风险。

为了防止这种风险,JavaScript 规定,如果使用严格模式,eval内部声明的变量,不会影响到外部作用域。

  1. (function f() {
  2. 'use strict';
  3. eval('var foo = 123');
  4. console.log(foo); // ReferenceError: foo is not defined
  5. })()

上面代码中,函数f内部是严格模式,这时eval内部声明的foo变量,就不会影响到外部。

不过,即使在严格模式下,eval依然可以读写当前作用域的变量。

  1. (function f() {
  2. 'use strict';
  3. var foo = 1;
  4. eval('foo = 2');
  5. console.log(foo); // 2
  6. })()

上面代码中,严格模式下,eval内部还是改写了外部变量,可见安全风险依然存在。

总之,eval的本质是在当前作用域之中,注入代码。由于安全风险和不利于 JavaScript 引擎优化执行速度,所以一般不推荐使用。通常情况下,eval最常见的场合是解析 JSON 数据的字符串,不过正确的做法应该是使用原生的JSON.parse方法。

eval 的别名调用

前面说过eval不利于引擎优化执行速度。更麻烦的是,还有下面这种情况,引擎在静态代码分析的阶段,根本无法分辨执行的是eval。

  1. var m = eval;
  2. m('var x = 1');
  3. x // 1

上面代码中,变量m是eval的别名。静态代码分析阶段,引擎分辨不出m('var x = 1')执行的是eval命令。

为了保证eval的别名不影响代码优化,JavaScript 的标准规定,凡是使用别名执行eval,eval内部一律是全局作用域。

  1. var a = 1;
  2. function f() {
  3. var a = 2;
  4. var e = eval;
  5. e('console.log(a)');
  6. }
  7. f() // 1

上面代码中,eval是别名调用,所以即使它是在函数中,它的作用域还是全局作用域,因此输出的a为全局变量。这样的话,引擎就能确认e()不会对当前的函数作用域产生影响,优化的时候就可以把这一行排除掉。

eval的别名调用的形式五花八门,只要不是直接调用,都属于别名调用,因为引擎只能分辨eval()这一种形式是直接调用。

  1. eval.call(null, '...')
  2. window.eval('...')
  3. (1, eval)('...')
  4. (eval, eval)('...')

上面这些形式都是eval的别名调用,作用域都是全局作用域。

~~~~~ END ~~~~~

js学习:函数的更多相关文章

  1. js学习——函数

    函数声明 function funName(parameter){} 函数表达式,并把函数存储在变量x中 //不用给函数名,后续并不能直接用给定的函数名调用 var x = function(a){r ...

  2. JS学习 函数的理解

    ECMAScript 的函数实际上是功能完整的对象. 函数的理解 用 Function 类直接创建函数,格式如下.可理解为Function构造器. var function_name = new Fu ...

  3. 学习js回调函数

    <!DOCTYPE HTML> <html> <head> <meta charset="GBK" /> <title> ...

  4. JS学习笔记(三)函数

    js中的方法名一般都是首字母小写,其余单词首字母大写的规范. 声明 function 函数名(参数列表) { // 函数体 return 返回值; } 调用 函数名(); (js中花括号喜欢用这种方式 ...

  5. js学习之函数

    1/.js中函数就是对象. 2/以表达式方式定义的函数一般不要函数名以使代码紧凑. 3/js中函数声明的方式会被默认提到外部脚本或最前面,所以在其定义前的代码也可调用. 然而以表达式方式的则不行. 4 ...

  6. js学习(4) 函数

    JavaScript有三种声明函数的方法 (1)function命令 function print(s) { console.log(s); } (2)函数表达式 1.var print = func ...

  7. js学习之变量、作用域和内存问题

    js学习之变量.作用域和内存问题 标签(空格分隔): javascript 变量 1.基本类型和引用类型: 基本类型值:Undefined, Null, Boolean, Number, String ...

  8. 【Knockout.js 学习体验之旅】(3)模板绑定

    本文是[Knockout.js 学习体验之旅]系列文章的第3篇,所有demo均基于目前knockout.js的最新版本(3.4.0).小茄才识有限,文中若有不当之处,还望大家指出. 目录: [Knoc ...

  9. 【Knockout.js 学习体验之旅】(2)花式捆绑

    本文是[Knockout.js 学习体验之旅]系列文章的第2篇,所有demo均基于目前knockout.js的最新版本(3.4.0).小茄才识有限,文中若有不当之处,还望大家指出. 目录: [Knoc ...

  10. 【Knockout.js 学习体验之旅】(1)ko初体验

    前言 什么,你现在还在看knockout.js?这货都已经落后主流一千年了!赶紧去学Angular.React啊,再不赶紧的话,他们也要变out了哦.身旁的90后小伙伴,嘴里还塞着山东的狗不理大蒜包, ...

随机推荐

  1. 1.3 eclipse快捷键

    来源:http://blog.csdn.net/dashuxiaoai/article/details/8737928 另:Eclipse快捷键 10个最有用的快捷键  http://www.cnbl ...

  2. vue环境搭建及单页面标签切换实例

    复习 """ 1.指令: v-once: <p v-once>{{ msg }}</p> v-cloak: 防止页面加载抖动 v-show:绑定的 ...

  3. js + jquery 实现分页区翻页

    简单来说,情况是这样的,假如做好了对动漫每一集进行分页,如下图: 但当分页太多就会变得不能看,而且前后箭头也不能只是摆设. 想要得到类似这样效果: 网上搜了一会翻页相关的库没什么效果,也不太合适自己的 ...

  4. 空指针异常与Optional类

    一.什么是空指针异常 当程序需要对象实例的时候返回null就会抛出空指针异常(NullPointerException,简称NPE).包括以下情况: 调用一个null对象实例的方法 访问或修饰null ...

  5. JS高级---利用原型共享数据

    什么样子的数据是需要写在原型中? 需要共享的数据就可以写原型中 原型的作用之一: 数据共享 //属性需要共享, 方法也需要共享 //不需要共享的数据写在构造函数中,需要共享的数据写在原型中 //构造函 ...

  6. 普及C组第二题(8.1)

    2000. [2015.8.6普及组模拟赛]Leo搭积木(brick) 题目: Leo是一个快乐的火星人,总是能和地球上的OIers玩得很high.         2012到了,Leo又被召回火星了 ...

  7. HBuilder笔记

    官网: https://uniapp.dcloud.io/quickstart HBuilderX - 高效极客技巧 https://ask.dcloud.net.cn/article/13191 插 ...

  8. Cosmetic Airless Bottles To Meet Practical Requirements

    Today, people use cosmetic bottles, many of which are in cosmetic airless bottles. We can use them, ...

  9. WordPress 安装教程

    1.要安装WordPress,先看他的环境要求 2.环境符合后,直接去官网下载 WordPress(点击去官网) 下载最新的安装包 3.下载解压后,直接在浏览器中访问 会自动跳转到安装界面 http: ...

  10. FYF的煎饼果子

    利用等差数列公式就行了,可以考虑特判一下m >= n($ m, n \neq 1 $),这时一定输出“AIYAMAYA”. #include <iostream> using nam ...