Skip to content

函数的基本用法

arguments

arguments是在函数作用域内存在的一个类数组对象,存储函数的参数等属性。

javascript
function foo() {
    console.log(arguments)
    for (var i = 0; i < arguments.length + 2; i++) {
        console.log(arguments[i])
    }
}
foo(1, 2, "哈哈哈", {}, [1, 2]) //

arguments参数只有在函数作用域里面才生效,它是一个对象,但是和数组一样可以通过[0][1]的方式依顺序访问函数的参数,并且具有一个length属性,访问的是函数的参数的个数。
arguments里面还有属性callee,指的是函数本身,可以在函数内部调用函数自己(不推荐使用)

javascript
var sum = function(num) {
    if (num > 0) {
        return arguments.callee(num - 1) + num
    }
    return num
}
sum(100) //5050

这里不知道函数名字(匿名函数),但是还是依旧可以调用自身。
箭头函数没有arguments,用剩余参数...rest代替

剩余参数

现在有一个需求:需要一个函数,传入不定长参数,第一个参数是名字,第二个以后都是数字,函数返回名字和第二个以后参数的总和

javascript
function add(name, ...rest) {
    let sum = 0
    for (var i = 0; i < rest.length; i++) {
        sum += rest[i]
    }
    return name + sum
}
add("蛤", -1, -1, -1, -1, -1, -1, -1) //"蛤-7"

将多余的实参传入rest数组中,如果没有多余的则rest数组为空

默认参数

javascript
function Person(name = "未知", sex = "未知", age = 18) {
    var o = {
        name: name,
        age: age,
        sex: sex,
    }
    return o
}

Person("紫", "妈") //{ name: '紫', age: 18, sex: '妈' }

用于应对不定参数或者参数残缺的接口。

arguments.callee

callee属性可以引用该函数的函数体内当前正在执行的函数

javascript
function foo() {
    console.log(arguments.callee.name)
}
foo() //foo

this

this是"这个"的意思,this 指向调用函数的主体对象。

javascript
console.log(this) //window,浏览器对象
//这意味着他和window.console.log等价
window.console.log === console.log //true,浏览器对象调用console.log

在全局中this指向window

javascript
var name = "window name"
//全局的name是当window存在都不会消失,跳转也不会
var o = {
    name: "this object",
    getThis: function() {
        console.log(this === o, this.name)
    },
}
o.getThis() //true "this object"

此时getThis函数是o调用的,所以函数内部的this指向o
但是

javascript
var o = {
    name: "this object",
    getThis: function() {
        console.log(this === o, this.name)
    },
}
var name = "window name"
var fn = o.getThis
fn() //false "window name"

为什么此时就变成了false了呢。因为fn获得是一个函数。现在调用 fn()则变成了window.fn(),此时的this指向了window,调用函数的主体是 window,this.name===window.name,变成了"window name"。

在箭头函数里的this

javascript
var name = "window name"
var o = {
    name: "this object",
    fn: function() {
        console.log(this === o)
        //let that = this;
        return () => {
            console.log(this === that, this.name)
        }
    },
}
o.fn() //true
let foo = o.fn()
foo() //true "this object"
//此时o.fn()是箭头函数()=>{},this指向声明阶段的上下文,也就是o

箭头函数中使用 this

箭头函数没有 this,this 指向是外部上下文的 this(无法改变)
在普通函数中 this 的绑定是在执行位置绑定
在箭头函数里面的 this 在声明阶段硬绑定到上下文中。

javascript
var name = "window name"
var o = {
    name: "this object",
    fn: function() {
        console.log(this === o)
        let that = this
        return function() {
            console.log(this === that, this.name)
        }
    },
}
o.fn()() //true false "window name"
//此时o.fn()是function,执行时this指向window
  • 作用

绑定事件

javascript
let leftBtn = document.querySelector(".left")
leftBtn.onclick = function() {
    this.style.backgroundColor = "red" //点击事件触发的主体是leftBtn
}

循环绑定

javascript
let lilist = document.querySelectorAll(".list li")
for (var i = 0; i < lilist.length; i++) {
    lilist[i].onclick = function() {
        this.innerHTML = "666"
    }
}

call apply bind

函数的 this 的指向是可以修改的。我们需要用到某些特殊的原型的方法的时候会用到 call,apply 还有 bind 强行修改。

  • call/apply
javascript
var name = "window name"
var o1 = {
    name: "object name",
    getThis: function() {
        console.log(this.name)
    },
}
var o2 = {
    name: "another name",
}
o1.getThis() //"object name"
var fn = o1.getThis
fn() //"window name"
fn.call(o2) //"another name"
fn.apply(o2) //"another name"
fn.call(o1) //"object name"

此时call/apply都会使函数执行,相当于强行修改了调用函数的主体对象,在你想要的对象上借用了别的方法。方法的一处书写,到处使用。

javascript
var o = {
    "0": "123",
    "1": "456",
    "2": "789",
    "length": 3,
}
o.forEach(function(item) {
    console.log(item);
}); //此处会报错,因为对象o没有forEach方法,这是数组的方法
//于是
[].forEach.call(o, function(i) {
    console.log(i)
}) //打印"123" "456" "789"
Array.prototype.forEvery = function(cb) { //不完全方法
    for (var i = 0; i < this.length; i++) {
        cb(this[i]);
    }
} //自己定义了一个方法
[1, 2, 3, 4].forEvery(function(i) {
    console.log(i);
}) //1 2 3 4
[].forEvery.call(o, function(i) {
    console.log(i)
}) //"123" "456" "789"

callapply的唯一区别

javascript
fn.call(this, x1, x2, x3, x4) //函数原本参数是一个一个传进去的
fn.apply(this, [x1, x2, x3, x4]) //函数原本参数放到数组中传进去
  • bind

bind方法同样也可以修改函数执行的主体对象,但是bind是硬绑定,是在执行的时候返回一个绑定完成之后的函数,可以再任意地方执行

javascript
var name = "window name"
var o1 = {
    name: "object name",
    getThis: function() {
        console.log(this.name)
    },
}
var o2 = {
    name: "another name",
}
var sayName = o1.getThis.bind(o2) //返回一个绑定好的函数,啥都不返回
sayName() //"another name"
sayName.call(o1) //"another name"已经改不了了