您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

JavaScript 函数

在 JavaScript中,是头等 (first-class) 对象,因为它们可以像任何其他对象一样具有和。它们与其他对象的区别在于可以被。简而言之,它们是 Function 对象。(MDN)

就是一段片段,就是执行中的。

使用前通常与变量一样需要先进行声明,用 function 关键字定义。

// 常见的的定义方式
function (参数, 参数, ...) {
  片段;

  return 返回值;
}

//  (执行中的)
var 的返回值 = (参数, 参数, ...);

使用 名() 的方式即可

以下是最简单的:

function say() {
  console.log('hello');
}

say(); // :"hello"

这个就会在控制台 hello 字符串。

这个没有返回值,认会返回 undefined

在声明的时候,可以对参数也做上说明

假设有需求,需要计算三角形周长的

计算三角形周长则需要知道三角形三条边各自的长度,然后将他们求和。

定义的时候就可以将三条边作为参数进行声明。

function calcPerimeter(a, b, c) {
  // a, b, c 分别代表三条边
  var sum = a + b + c;

  return sum;
}

//  并将返回值赋值给perimeter
var perimeter = calcPerimeter(, , );

在的时可以过去,这些值可以在中被访问。

在以上 calcPerimeter 被的时,传递了 3, 4, 5 三个值。

三个值对应到声明时定义的三个参数 a, b, c

所以执行过程中 sum 的值为 3 + 4 + 5,即 12,随后 sum 被作为返回值进行返回。

最终变量 perimeter 也会被赋值为12。

可以对进行封装,让逻辑更加清晰。

比如如下块:

// 改写前
var num = ;

var flag = false;

var i;
var len;
for (i = , len = num - ; i <= len; i++) {
    if (num % i === ) {
        flag = true;
        break;
    }
}

console.log(flag);

以上第一眼可能无法看出具体在做什么,仅需一点,就能有所改善。

// 改写后
function isPrimeNumber(num) {
  var flag = false;
  
  var i;
  var len;
  for (i = , len = num - ; i <= len; i++) {
    if (num % i === ) {
      flag = true;
      break;
    }
  }

  return flag;
}


var num = ;

var result = isPrimeNumber(num);

console.log(result);

改写后的似乎多了几行,但是将其中核心部分包装成了。

通过 isPrimeNumber 名可以很容易的了解到这一段作用是用来判断数是否为质数

当然有个前提就是起 可以让大部分人看得懂 的名。

优秀的名可以帮助他人更容易理解,同时当自己一段时间后再回头看时,能更容易进入当时写时候的思维模式等。

这里提供几个命名的建议,具体的命名可以根据团队规范、个人成长等做调整。

准确的拼写十分重要,绝大多数情况下名都会是英文单词组成的。

当然许多时候手一快可能就少了字母,或者错将 wrap 进行乾坤大挪移拼写成了 warp

许多情况是无法避免的,经常需要自检。

当然可以借助一些单词的检查,如 Visual Stu Code 可以借助 Code Spell Checker 来检查单词的正确性。

再者碰到想起的名但是单词拼写不出来,尽可能翻词典,日积月累能有大量的词汇沉淀。

尽量不要使用拼音或者是首字母缩写。

以下名或许会造成困扰:

function jslsh() {}

function jsNumber() {}

以上是计算两数和的命名,可能只有天和地知道这个是什么意思。

当然,如果是自己写 demo 或者测试的时候,其实不需要考虑这么多。

如碰到是判断是否有没有可以的时候,可以带上一些前缀,比如:

// 是否登入
function isLogin() {}

同时可以合理的使用动词,比如打开就可以使用 openFile 名,具体的状态可以根据语境、作用、个人习惯等做调整使用。

使用词语的缩写尽量使用通用的缩写

如:

这些缩写大部分开发者是可以看的懂的缩写。

分析:根据圆面积公式 S=π·r·r,其中 S 就是要求的值,即的返回值,π 是常量(固定的值),半径r是未知数,所以r就可以设计成参数

function circleArea(r) {
    var pi = ;

    return pi * r * r;
}

// 计算半径为10的圆的面积
var area = circleArea();

分析:

某个DOM某个类名可以说明有两个未知量,可以设计成两个参数。

根据描述也可以确定 某个DOM 的类型是个 DOM 对象,某个类名是个字符串

只要拿到这个DOM的 class ,判断里面是不是含有这个类型即可得到结果

function hasClass(el, className) {
  // el 是 element的缩写,表示dom元素
  
  // 如果没有元素 则返回
  if (!el) {
      return false;
  }

  // 根据空格分割成数组
  // 可以不使用 split ,使用字符串也可以用indexOf匹配
  var classList = el.className.split(' ');

  // 判断是否存在
  if (classList.indexOf(className) >= ) {
      return true;
  }
  
  return false;
}

以下扩展可能需要一定的知识积累,遇到不懂的地方可以停下脚步,先学习下一章节

以上篇幅的其实都通过声明的方式来定义,还有一种方式就是使用表达式定义。

// 声明
function add(a, b) {
    return a + b;
}

// 表达式
var add = function(a, b) {
    return a + b;
};

通过上述例子可以看出写法上的区别就是表达式是将赋值给了变量。

这两种方式创建的最大的区别在于,不能提前使用表达式创建的

光看句子有点抽象,举个例子?:

var num1 = add1(, );

var num2 = add2(, );

// 声明
function add1(a, b) {
    return a + b;
}

// 表达式
var add2 = function(a, b) {
    return a + b;
};

上面一段在执行的时候会报 add2 is not a function 的,表示 add2 不是,也就是说 add2 不能被提前使用,而 add1 可以。

具体原因可以查看执行上下文章节。

有他自己的作用域,内声明的变量等通常情况下不能被外部访问,但是可以访问到外部的变量或者其他等

var a = ;

function fn() {
    var b = ;

    console.log(a); // :1
    console.log(b); // :2
}

fn();

console.log(b); // ReferenceError: b is not defined

执行以上会报 b is not defined

没有名字的就是匿名

var fn = function() {
    console.log('我是匿名');
};

除了在表达式中会出现匿名,还有许多场景。

相对常见的就是自执行匿名,MDN官方翻译为立即表达式

自执行就是这个声明后就会立即执行,自执行的匿名通常会被用来形成独立的作用域

如:

(function() {
    var num = ;

    alert(num);
})();

这是自执行的匿名,这个匿名是被包裹了一段括号后才被的。

以下这段会报错:

// 报错
function() {
    var num = ;

    alert(num);
}();

浏览器会告诉你必须给名字。

通过括号包裹一段,让js引擎识别成他是表达式,再对他进行执行,就不会报错,这是加括号的原因。

同理,可以使用 +! 等运算符代替括号,让匿名成为表达式即可。

大部分第三方框架都会通过自执行的匿名包裹,与浏览器全局环境隔离,避免污染到全局环境。

表达式进行声明的时候也可以使用具名

var count = function fn(num) {
    console.log('我是');
};

以上这段是不会报错的,但是不能通过 fn 访问到,这里的 fn 只能在内部进行访问,通常在使用递归的形式做计算的时候会用到这种写法。

var count = function fn(num) {
    if (num < ) {
        return num;
    }

    return fn(num - ) + num;
}

count();

上面这个例子,就是在内部访问 fn 自己,使用递归的形式求和。

注:递归相关的知识可以参考相关文献进行学习

arguments 是对应于传递给的参数的类数组对象。(MDN)

通常情况下都具有 arguments 对象,可以在内部直接访问到。

他是类数组,即长得很像数组,成员都是用数字编号,同时具有 length 。

arguments 中存放着当前被时,传递过来的所有参数,即便不声明参数,也可以通过 arguments 取到传递过来的参数。

function sum() {
    console.log(arguments);
}

sum(, , , );

执行上述,可以看到在控制台了对象,存放的就是所有传递过去的参数,利用这一特性,就可以不限制参数个数,或者让做中转站(),利用 arguments 将参数传递给另。

如,不确定输入的参数个数的:

function sum() {
  var total = ;

  var i;
  var len;
  for (i = , len = arguments.length; i < len; i++) {
    total += arguments[i];
  }

  return total;
}

var total = sum(, , , , );
console.log(total); // :25

通过循环遍历 arguments 对象,就可以得到所有参数,然后做累加就可以达到求和的目的。

在本质上是个。

通常都能听到“一下某个”,“取到某个的返回值”,这里的其实就是。

一般是用来描述对象的某个行为的,但是平时我们会混用,口头交流的时候会经常把直接称作。

只要自己理解,不需要去纠结和到底是什么,也不用特意纠正别人的说法,大家都能听得懂就行。

使用 JS DOC 描述是非常良好的习惯,良好的 JS DOC 书写还可以使用工具文档。

JS DOC 对的描述大体如下:

/**
 * 这是这个求幂 计算 x 的 y 次方
 * @param {Number} x - 底数
 * @param {String} y - 指数
 */
function pow(x, y) {
    // ...
}

除此之外还可以描述返回值等。

所谓纯,就是没有副作用的

从执行开始到结束,没有对外部环境做任何操作,即对外部环境没有任何影响(没有副作用),这样的就是纯。

纯只负责输入,对于一种输入只有一种返回值。

如果中存在 Math.random 这种影响返回值的,也不能算是纯。

// 纯
function add(a, b) {
  return a + b;
}

// 非纯
var person = { name: '小明' };
function changeName {
  person.name = '小红'; // 影响了外的,产生了副作用
}

当与 new 关键字一起被的时候,就会作为构造。

function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.say = function() {
    console.log('我是' + this.name);
};

var person = new Person('阿梅', );

person.say();

console.log(person);

可以看到当作为构造的时候,认返回的是对象。

细心的读者仔细观察就能发现,构造的认返回值是体内的 this。

事实上构造的执行有一定流程:

理解这个流程,就能理解构造的返回值。

具体的的 prototype 等可以参阅原型章节。

特性相对较多,也是 JavaScript 的核心之一。

可以用于,提供的复用率和可读性,在大部分情况下,当两段具有超高相似度时,应当设计成,不同的部分使用参数进行区分。


联系我
置顶