函数必须有返回值_函数

函数

4.1 函数基本概念

为什么要讲函数的概念呢?都说基础很重要,只有到功夫深的时候才能体会到铁杵会磨成针的,所以说基础很重要。

何况函数在 javascript 中可是一等公民啊,就像立了大功的的大将一样,必须要给他颁发一个奖项,这个奖项就是 “一等公民”。可想而知他的重要性。

函数是既可以是事件驱动性质的,例如我们的按钮点击,需要给其绑定一个触发的事件,还有鼠标移入移除事件等等,也可以是被调用者调用的可重复使用的代码块。这里体现了函数的可重复使用的性质。

javascript 函数语法,函数就是包裹在花括号中的代码块,前面使用了关键词 function: 当调用该函数时,会执行函数内的代码。可以在某事件发生时直接调用函数(比如当用户点击按钮时),并且可由 JavaScript 在任何位置进行调用。

4.2 函数结构

function 函数名(arg1, arg2, arg3, ... , argn){

// 函数体

// 各种语句

// return 返回值

}

定义一个函数一个函数,首先我们必须以 function 这个关键字开头,然后是函数名,函数名必须以英文字母开头,接着就是一个小括号(),里面包含着各种各样的参数,然后就是一对花括号,里面包含着函数体,各种语句,最后一个就是函数返回值。

4.3 函数的声明方式

第一种:普通函数的声明

function fn(a, b) {

return a + b

}

function fn() {

console.log("fn")

}

这种普通的不能再普通了,一看就跟函数的结构一样,没什么好讲的。

第二种:函数表达式声明

这种跟函数声明的区别有以下三点:

  1. 以函数声明的方法定义的函数,函数名是必须的,而函数表达式的函数名是可选的
  2. 以函数声明的方法定义的函数,函数可以在函数声明之前调用,而函数表达式的函数只能在声明之后调用
  3. 以函数声明的方法定义的函数并不是真正的声明,他们仅仅可以出现在全局中或者嵌套在其它函数中

让我们来见证各种各样的函数表达式吧。

var fn = function(a,b) { // 普通变量赋值,将一个函数赋值给一个变量

return a + b

}

var fn = function() {

console.log("fn")

}

(function fn3(){ // 用()包裹一个普通函数变成一个表达式

})

(function(){ // 用()包裹 一个匿名函数

})

!function() { // 利用 逻辑非 运算符

}

~function func4(){ // 利用求反 运算符

}

true,function func6(){ // 使用bool 值 true

}

false,function func7() {

}

false||function fn() {

}

5dc9bb4d8475cfd6410294182732ea23.png

第四种:函数构造器

在JavaScript函数中第一个类(class object)对象: 函数是一个普通的对象类型是function。

构造器声明结构如下:

var fn = new Function(参数1,参数2,参数3,... ,参数n,函数体)

首先是一个关键字 new 接着是一个 Function 后面接着一堆参数,最后一个参数是指函数体,包括返回值等。

实例代码:

var number1 = 10

var number2 = 20

var fn = new Function(number1, number2, "return number1 + number2")

7c9f280873a33039cc4f9675a299816c.png

4.4 函数的调用方式

1. 作为一个函数调用

在一般模式下,其中 this 对象指向 windows

在严格模式下,其中 this 指向 undefined

Js 中 this 关键字很常见,但是它似乎变换莫测,让人抓狂。接下来就来揭示其中奥妙。借助阮一峰老师的话,他代表函数运行时,自动生成一个内部对象,只能在函数内部使用,这句话似乎很平常,可是要非常注意三个字,“运行时”这说明 this 关键字只与函数的执行环境有关,而与函数声明环境无关,也就会这个 this 到底代表的是什么是对象要等到函数执行时才知道,有点类似函数定义时的参数列表只在函数调用时才传入真正的对象,理解了这一点对后面 this 关键字的掌握有很大的帮助

function fn(a, b){

console.log(a+b)

console.log(this)

}

fn(1,2)

18c3999b8d27f3b48f03bd59e0895c0b.png

function fn(a, b) {

"use strict"; // 严格模式下

console.log(this)

}

fn(3,4)

18c3999b8d27f3b48f03bd59e0895c0b.png
  1. 函数作为方法调用

其中 this 指向方法所拥有的对象

var obj = {

name: "ken",

fn: function() {

console.log(this)

}

}

obj.fn()

dd1d7d60017bd59183076cbe4285710e.png
  1. 使用构造函数调用

function fn(arg1,arg2){

this.firstName=arg1;

this.lastName=arg2;

console.log(this)

}

var x = new fn("Ken","Li");

x.firstName;

d2d9a67e2d1781f2f1a8ff44f59b2467.png
  1. 使用 call,apply调用

var obj;

function fn(a,b){

console.log(this)

return a*b;

}

obj = fn.call(obj , 3 , 4); //返回 12

function fn(a,b){

return a*b;

}

var arr=[3,4];

var obj = fn.apply(obj , arr) //返回12

f816666613e90091c60217f384e96490.png
  1. 自执行函数

(function() {

console.log(this)

})()

(function() {

"use strict";

console.log(this)

})()

83bb543417ef59fcf6b4700522265380.png

4.5 函数返回值

一个函数的函数名即是该函数的代表,也是一个变量。由于函数名变量通常用来把函数的处理结果数据返回给调用函数,即递归调用,所以一般把函数名变量称为返回值,函数的返回值类型是在定义函数时指定的

1 每一个函数都有一个返回值

返回值结构:

//声明一个带返回值的函数

function 函数名(形参1, 形参2, 形参3...) {

//函数体

return 返回值;

}

//可以通过变量来接收这个返回值

var 变量 = 函数名(实参1, 实参2, 实参3...)

2 如果函数没有手动给其返回值,默认是返回 undefined

function fn() {

// 默认返回 undefined

}

3 如果显示给其返回值,则返回我们给的返回值

function fn(arg1, arg2) {

return arg1 + arg2

}

4 一旦函数返回,不管后面有多少条语句,都不会去执行了

function fn(arg1, arg2) {

return arg1 + arg2;

console.log(arg1+arg2)

}

5 函数返回值只能是单个值

// 错误实例

function fn(arg1, arg2){

return arg1, arg2 // 只返回 arg2

}

function fn(arg1, arg2) {

return (arg1, arg2) // 也是返回最后一个参数 arg2

}

6 如果实在要返回多个值,必须将多个参数转成对象,或者是数组

function fn(arg1, arg2) {

return [arg1, arg2]

}

function fn(arg1, arg2) {

return {

arg1: arg1,

arg2: arg2

}

}

4.6 函数中的 arguments

1 在非严格模式下,函数的参数都会储存在一个比较神奇的对象 arguments 中

2 在非严格模式下,在函数开始执行时,arguments的长度和实参传递的个数是一致的,假如实参少于形参,多出的形参并不会和arguments绑定,这些修改相互之间不影响。

function fn(arg1, arg2){

console.log(arguments.callee)

console.log(arguments.length)

console.log(arguments)

}

function fn(x, y, z) {

x = 100;

arguments[2] = 10; // 由于只传递两个实参,arguments[2]和z并无关联

z = 1; // 没有传递实参,和arguments无关联

console.log(arguments[0], arguments[1], arguments[2]);

console.log(arguments.length); // arguments 的长度取决于实参传递的个,后期修改无效

console.log(x, y, z);

}

f(3, 2);

// 我们可以对 arguments 进行遍历

function fn(arg1, arg2) {

for(var key in arguments){

console.log(arguments[key])

}

}

fn(1,2,3,4) // 1,2,3,4

3 在严格模式下,只有函数执行开始的相互映射,之后arguments和形参之间的修改互不影响。

function fn(arg1, arg2){

"use strict";

console.log(arguments)

}

function fn(x, y, z) {

'use strict'

x = 100;

z = 1;

arguments[1] = 10;

console.log(arguments[0], arguments[1], arguments[2]); // 3 10 undefined

console.log(x, y, z); // 100 2 1

}

f(3, 2);

4.7 函数中的length

1 与 arguments 的 length 不太一样,函数的 length 是指函数本身的参数,并非调用时实际传递的参数的个数

Function.length // 函数构造器 ==> 1

console.log((function fn() {}).length); /* 0 */

console.log((function fn(a) {}).length); /* 1 */

console.log((function fn(a, b) {}).length); /* 2 */

console.log((function fn(...args) {}).length); // 0

console.log((function fn(a, b = 1, c) {}).length); // 1

4.8 匿名函数

1 实际上就是把原有的函数名去掉,就变成了没有函数名的函数,简称匿名函数

function fn() {

console.log("普通函数")

}

// 直接运行下面函数是会报错的

function() {

console.log("匿名函数")

}

2 把匿名函数变成自执行函数

(function() {

console.log("自执行函数")

})()

3 可以把匿名函数赋值给一个变量

var fn = function() {}

4 匿名函数在事件中大显身手

var oBox = doxument.getElementById("box")

oBox.onclick = function() {

console.log(this)

}

5 对象方法

var obj = {

name: "ken",

fn: function() {

console.log(this.name)

}

}

6 回调方法

setInterval(function(){

console.log(1)

}, 1000)

setTimeout(function() {

console.log(1)

}, 1000)

7 函数返回值

function fn() {

return function() {

return 1

}

}

4.9 自执行函数,简称 IIFE

1 建议在自执行函数后面加上英文分号 ';',避免打包的时候会被当成函数打包

2 我们常见的一个例子jquery

(function (jq) {

function init() {

console.log('do something');

}

jq.extend({

'myMethod': function () {

init();

}

})

})(jQuery);

5.0 箭头函数

1 箭头函数是没有自己的 this,arguments,super,new操作

2 由于没有 this 所以在使用 call, apply调用函数时,第一个参数通常会被忽略

3 由于没有 this 对象,所以不能进行 new,已经继承中的 super()

let sum = (a,b,c)=>{

return a + b + c

}

sum(1,2,3)

var arr = [1,2,3,4]

arr.forEach((item, index)=>{

console.log(item)

console.log(index)

})

arr.map((item, index)=>{

console.log(item)

console.log(index)

})

arr.filter((index)=>{

return index>2

})

5.1 高阶函数

其实高阶函数也没那么神奇,你可以跟数学类比,就像一个函数的参数可以是另一个函数。JavaScript的函数其实都指向某个变量。既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

1 一个最简单的高阶函数

function addFn(x, y, fn) {

return fn(x) + fn(y)

}

addFn(-5, 6, Math.abs)

2 map 遍历循环

map() 方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果

function pow(x){

return x * x

}

var arr = [11,22,33,44,55,66]

arr.map(pow); //[121, 484, 1089, 1936, 3025, 4356]

var arr = [1,2,3,4,6,7]

arr.map(String);// ["1", "2", "3", "4", "6", "7"]

3 reduce 累计叠加

reduce方法有两个参数,第一个参数是一个callback,用于针对数组项的操作;第二个参数则是传入的初始值,这个初始值用于单个数组项的操作。需要注意的是,reduce方法返回值并不是数组,而是形如初始值的经过叠加处理后的操作

var arr = [1,2,3,4,5,6]

arr.reduce(function(x,y) {

return x + y

})

// 或许我们可以自己模拟写一个 reduce 函数

// 我们自己来编写一个属于自己的reduce

function reduce(array,cb){

if(!cb){

return ;

}

var memo = 0;

for(i=0;i<array.length;i++){

memo = memo + array[i];

cb(memo,array[i]);

}

// 返回上一次相加的和 memo

return memo;

}

var sum = reduce(arr,function(memo,num){

console.log(memo,num);

})

console.log(sum);

4 filter 过滤数据

.filter是一个内置的数组迭代方法,它接受一个“谓词(译者注: 指代一个过滤条件的函数)”,该“谓词”针对每个值进行调用,并返回一个符合该条件(“truthy值”)的数组。

// 我们来看看原生的js中的filter

var arr = [1,2,4,5,6,7,8];

var res = arr.filter(function(num){

return num % 2 === 0;

})

console.log(res);

// 我们自己来实现一个

function filter(array,cb){

if(!array) return ;

var res = [];

for( let i=0;i<array.length;i++ ){

if(cb(array[i])){

res.push(array[i]);

}

}

return res;

}

var res = filter(arr,function(num){

return num % 2 === 0;

})

console.log(res);

5 forEach 遍历循环

var arr = [1,2,3,4,5,6]

arr.forEach((item, index)=>{

console.log(item, index)

})

// 首先我们先来自己实现以下一个each函数

function each(obj,fun){

if(!fun)

return;

if(obj instanceof Array){

// 遍历数组的

for(var i=0;i<obj.length;i++){

if(fun.call(obj[i],i)==false)//函数中的this指向obj[i] i为索引

break;

}

}else if(typeof obj === 'object'){

var j = null;

for(j in obj){

if(fun.call(obj[j],j))//函数中的this指向obj[j] j为属性名

break;

}

}

}

// 调用

var arr = ['a','b','c'];

each(arr,function(index){

console.log(index +"=" +this);

});

var obj = {name:'liu',age:12,salary:8000,address:'广州'};

each(obj,function(index){

console.log(index +"=" +this);

});

6 find 查找

find方法对数组中的每一项元素执行一次callback 函数,直至有一个callback返回true。当找到了这样一个元素后,该方法会立即返回这个元素的值,否则返回undefined。注意callback函数只会在分配了值的数组索引上调用,而不会在已删除或未分配值的索引上调用。

调用callback函数带有3个参数:当前元素的值、当前元素的索引,以及数组本身。

如果提供了thisArg参数,那么它将作为每次callback函数执行时的上下文对象,否则上下文对象为undefined。

find方法不会改变数组。

在第一次调用callback函数时会确定元素的索引范围,因此在find方法开始执行之后添加到数组的新元素将不会被callback函数访问到。如果数组中一个尚未被callback函数访问到的元素的值被callback函数所改变,那么当callback函数访问到它时,它的值是将是根据它在数组中的索引所访问到的当前值。被删除的元素不会被访问到。

var arr = [1,2,3,4,5,6]

arr.find((item, index)=>{

return item>2

})

// 当然我们需要一个函数

var arr = [1,2,4,5,6]

function find(array,cb){

if(!array) return ;

for(let [i,k] of array.entries()){

if(cb(k)===true){

return k;

brerak;

}

}

}

var num = find(arr,function(num){

return num % 2 === 0;

})

console.log(num);//2

7 sort 排序

sort() 方法用于对数组的元素进行排序,并返回数组。默认排序顺序是根据字符串UniCode码。因为排序是按照字符串UniCode码的顺序进行排序的,所以首先应该把数组元素都转化成字符串(如有必要),以便进行比较。

语法:arrayObject.sort(sortby);参数sortby 可选,用来规定排序的顺序,但必须是函数。

//要按数字大小排序,我们可以这么写:

var arr = [10, 20, 1, 2];

arr.sort(function (x, y) {

if (x < y) {

return -1;

}

if (x > y) {

return 1;

}

return 0;

}); // [1, 2, 10, 20]

//如果要倒序排序,我们可以把大的数放前面:

var arr = [10, 20, 1, 2];

arr.sort(function (x, y) {

if (x < y) {

return 1;

}

if (x > y) {

return -1;

}

return 0;

}); // [20, 10, 2, 1]

//默认情况下,对字符串排序,是按照ASCII的大小比较的,现在,排序应该忽略大小写,按照字母序排序。

//要实现这个算法,不必对现有代码大加改动,只要我们能定义出忽略大小写的比较算法就可以:

var arr = ['Google', 'apple', 'Microsoft'];

arr.sort(function (s1, s2) {

x1 = s1.toUpperCase();

x2 = s2.toUpperCase();

if (x1 < x2) {

return -1;

}

if (x1 > x2) {

return 1;

}

return 0;

}); // ['apple', 'Google', 'Microsoft']

//忽略大小写来比较两个字符串,实际上就是先把字符串都变成大写(或者都变成小写),再比较。

//sort()方法会直接对Array进行修改,它返回的结果仍是当前Array:

var a1 = ['B', 'A', 'C'];

var a2 = a1.sort();

a1; // ['A', 'B', 'C']

a2; // ['A', 'B', 'C']

a1 === a2; // true, a1和a2是同一对象

5.2 闭包

1 概念

闭包是一种特殊的对象。 它由两部分组成:执行上下文(代号A),已经在该执行上下文中创建的函数(代码B)。 当B执行时,如果访问了A中变量对象中值,那么闭包就会产生。 我们只需要知道,一个闭包对象,由A,B共同组成,在以后的文章中,都会将以chrome的标准来称呼。

function foo() {

var a = 20;

var b = 30;

function bar() {

return a + b;

}

return bar;

}

var bar = foo();

bar();

在上面的例子中,首先执行上下文 foo,在foo中定义了函数bar,而后通过对外返回bar的方式让bar得以执行。当时执行时,访问了 foo 内部变量a和b。因此这个时候闭包产生, 在chrome中通过断点调试的方式可以逐步分析该过程,从图中可以看出,此时闭包产生,用foo代替

423a97eca36793451421e690e42fd4b3.png

在图中,箭头所指的正是闭包,其中call stack 为当前的函数调用栈,scope 为当前正在被执行函数的作用域链,Local 为当前活动对象。 现在我们来思考一个小小的问题,把上面的代码调整成这样后,是否形成闭包?

function foo() {

var a = 20;

var b = 30;

function bar() {

return a + b;

}

bar();

}

foo();

10338a5d242c3b42dbf18a98a523853c.png

还是形成了闭包。 再来看一个例子,非常有意思的例子

function add(x) {

return function _add(y){

return x+y;

}

}

add(2)(3); //5

这个例子当然是产生闭包的,内部函数_add(y)被调用执行的时候,访问了add函数变量对象的中x的值,这个时候,闭包就会产生,如图所示,一定要记住,函数参数中的变量传递给函数之后也会加到变量对象中

58d7bfbe31e38159dbc2d938255baa4e.png

还有一个例子可以验证大家对于闭包的理解。 看看下面这个例子是否产生闭包

var name = "window";

var p = {

name: 'Perter',

getName: function() {

return function () {

return this.name;

}

}

}

var getName = p.getName();

var _name = getName();

console.log(_name);

getName在执行时,他的this其实是指向的是window对象,而这个时候并没有形成闭包的环境,因此并没有产生闭包。

那么这个例子改成如下这样呢?

var name = "window";

var p = {

name: 'Perter',

getName: function() {

return function () {

return this.name;

}

}

}

var getName = p.getName();

var _name = getName.call(p);

console.log(_name);

没有产生闭包, 如果再改成这样呢?

var name = "window";

var p = {

name: 'Perter',

getName: function() {

var self = this;

return function () {

return self.name;

}

}

}

var getName = p.getName();

var _name = getName();

console.log(_name);

这样就会产生闭包了

b6fe327b54e3d8037d3e5221883df3f3.png

5.3 垃圾回收机制

垃圾回收机制,知道当一个值失去引用之后就会被标记,然后被垃圾回收机制回收并释放空间。 我们知道,当一个函数的执行上下文运行完毕之后,内部的所有内容都会失去引用而被垃圾回收机制回收。 我们还知道,闭包的本质就是在函数外面保持了内部变量的引用,因此闭包会阻止垃圾回收机制进行回收。 我们用一个例子来证明这一点

function f1() {

var n = 999;

nAdd = function() {

n += 1;

}

return function f2(){

console.log(n);

}

}

var result = f1();

result();

nAdd();

result();

从上面的例子可以看出,因为 nAdd ,f2 都可以访问f1中的n,因此他们都会与f1形成了闭包。这个时候变量n都被保留下来了,因为f2(result)与nAdd执行时间都访问了n,而nAdd每运行一次就会将n加1,所以上例的执行结果非常符合我们的认知。

2c1fea8ec584d8c6a76921c63b53c6c7.png

5.4 作用域与作用域链

先花几秒钟时间来思考一个小问题,闭包会导致函数的作用域链的变化呢?

var fn=null

function foo() {

var a = 2;

function innerFoo() {

console.log(a);

}

fn = innerFoo; // 将innerFoo 的引用赋值给全局变量中的fn;

function bar() {

fn(); //此处保留innerFoo的引用

}

foo();

bar();

}

在这个例子中,foo内部的innerFoo访问了foo的变量a。因此当innerFoo执行时会有闭包产生,这是一个比较简单的例子,不一样的地方是全局变量fn。fn在foo内部获取了innerFoo的引用,并在bar中执行。

9f1ee1a4f4f19e2248528d360924ebd0.png

那么innerFoo的作用域链会怎么样呢? 在这里需要特别注意的地方是函数调用栈与作用域链的区别。 因为函数调用栈其实是在代码执行时才确定的,而作用域规则在代码编译阶段就已经确定了,虽然作用域链是在代码执行时才生出的,但是他的规则不会在执行期间发生变化。所以闭包的存在不会影响作用域链的变化

5.5 声明周期

我们知道,当一个函数被调用时,一个新的执行上下文就会被创建,一个执行上下文的声明周期大致分为两个阶段:创建阶段和执行阶段。 创建阶段 在这个阶段,执行上下文会分别创建变量对象,确认作用域链,以及确定 this 指向问题 执行阶段 创建阶段之后,就会开始执行代码,这个时候就会完成变量赋值,函数引用,以及执行其他可执行代码

d8b476d422e18fd295e3997d7996c0b8.png

从执行上下文的生命周期可以看到它的重要性,其中涉及变量对象,作用域链,this等许多重要知识点,但是并不是那么容易搞懂的,,这些概念有助于我们真正的理解javascript代码运行的机制。

JavaScript变量的生命周期 最近看国外经典教材的时候发现JavaScript与熟知的Java,C,C++都不同的特性,其中一个就是变量的生命周期

1 在JavaScript中,对于for循环中定义的i变量,其生命周期在循环结束后仍然是有效的。

for (var i=0; i < 10; i++){

doSomething(i);

}

alert(i); //10

这样的特性对于我们传统的习惯来说是不可理解的,这是因为JavaScript变量作用范围没有语句块的概念,他并不像JAVA一样在for循环内部声明的变量,在for循环外部就不能使用。

2.对于全局变量和局部变量的区分,要对var的使用特别注意。

<html>

<head></head>

<body>

<script type="text/javascript">

var global_one = "I am global";

function fun(){

global_two = "I am global too";

var local_one = "I am local";

}

alert(global_one); // "I am global"

//alert(global_two);// error

//alert(local_one);//error

fun();

alert(global_one); // "I am global"

alert(global_two);// "I am global"

//alert(local_one);//error

</script>

</body>

</html>

从上面的实例可以看到两点: 第一,JavaScript中的方法内部定义变量的时候如果没有加var,就是全局变量;否则为局部变量; 第二,当fun()没有执行的时候,方法内部的全局变量是不会声明并且定义的。

5.6 函数颗粒化

我们还是从一道面试题说起吧,如下要求

我们想要创建一个函数,在连续调用时将数字加在一起。

add(1)(2);

// returns 3

我们还希望能够继续为函数添加数字。

add(1)(2)(3); // 6

add(1)(2)(3)(4); // 10

add(1)(2)(3)(4)(5); // 15

等等。

单个调用应该返回传入的数字。

add(1); // 1

我们应该能够存储返回的值并重用它们。

var addTwo = add(2);

addTwo; // 2

addTwo + 5; // 7

addTwo(3); // 5

addTwo(3)(5); // 10

我们可以假设传入的任何数字都是有效的整数。

其实如果仔细研究我们就会发现这道题实际上应用的是不定参数,还有一个就是改造 valueOf()和toString()这两个方法。

当函数直接参与常量计算的时候,函数会默认调用toString(),函数会被转换为字符串参与计算,我们来看个例子

function fn() { return 50 }

console.log(fn + 60);

但是实际上我们可以覆写toString()方法,来改变上面这道题的答案

除此之外,当我们重写函数的 valueOf方法时也能改变函数的隐式转换效果。

当我们同时重写函数的toString和valueOf方法时,最终的结果会取 valueOf方法的返回结果。

补充了上面之后就可以来尝试之前的题目了,add方法的实现仍然是一个参数的收集过程,当add函数执行到最后时,返回的仍然是一个函数,但是我们可以通过定义toString/valueOf的方式,让这两个函数可以直接参与计算,并且转换的结果是我们想要的结果,而且他本身也仍然可以继续收集新的参数,实现方式如下

function add() {

// 第一次执行时,定义一个数组专门yo拿过来存储所有参数

var _args = [].slice.call(arguments);

// 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值

var adder = function() {

var _adder = function() {

// [].push.apply(_args, [].slice.call(arguments));

_args.push(...arguments);

return _adder;

}

// 利用隐式转换的特性,当最后执行时隐式转换,计算最终的值并返回

_adder.toString = function() {

return _args.reduce(function(a,b){

return a + b;

})

}

return _adder;

}

return adder(..._args);

// return adder.apply(null, _args);

}

var a = add(1)(2)(3)(4);

var b = add(1,2 ,3, 4);

var c = add(1,2)(3,4);

var d = add(1,2,3)(4);

console.log(a+10);

console.log(b+20);

console.log(c+30);

console.log(d+40);

console.log(a(10) + 100);

console.log(b(10) + 100);

console.log(c(10) + 100);

console.log(d(10) + 100);

function fn() { return 20 }

fn.valueOf = function() { return 60 };

console.log(fn + 10); // 70

function fn(){ return 20 };

fn.toString = function() { return 30 };

console.log(fn + 10);

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值