14-函数的深扒

第十四章 函数的深扒

1. arguments

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

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,指的是函数本身,可以在函数内部调用函数自己(不推荐使用)

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

这里不知道函数名字(匿名函数),但是还是依旧可以调用自身。

2. 剩余参数rest

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

function add(name,...rest){
    let sum = 0;
    for(var i = 0;i<rest.length;i++){
        sum+=rest[i];
    }
    return name+sum
}
add("pika",12,321,3,123,12,31,23);//"pia525"

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

默认参数:

function Person(name="pika",sex="boy",age=18){
    var o = {
        "name": name,
        "age": age,
        "sex": sex,
    }
    return o;
}
let myperson = Person("pika")//{name:"pika",age:18,sex:"boy"}
let newperson = Person();//{name:"pika",age:18,sex:"boy"}

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

3. 箭头函数与function的区别

function foo(){//普通的函数声明
    console.log(1)
}
var foo = () => console.log(1);//箭头函数

区别:

  1. 一个是function函数申明,一个是箭头函数函数表达式
  2. function里面有arguments,箭头函数没有arguments,用(…rest)代替
  3. 箭头函数没有构造函数,this指向是外部上下文的this(无法改变)。

4. this是什么,this在function函数里面的指向

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

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

在全局中this指向window

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

但是

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"。

5. this在箭头函数里的指向,this的作用是什么

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在声明阶段硬绑定到上下文中。

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
  • 作用

绑定事件

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

循环绑定

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

6. 函数的name与length属性

函数得name是函数名下面的属性,是函数的唯一标识符

function foo(){
    console.log(arguments.callee.name)
}
foo();//"name"
var a = function(){
    console.log(arguments.callee.name)
}
a();//"a"
var b = () =>{}
console.log(b.name);//

函数的name属性就是函数名

7. arguments的length

函数的arguments的length属性是指参数类数组中参数的长度

function foo(){
    console.log(arguments.length)
}
foo(1,2,3,4,5);//5

8. this的指向修改call apply与bind的意义

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

  • call/apply
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/aplly都会使函数执行,相当于强行修改了调用函数得主体对象,在你想要得对象上借用了别的方法。方法得一处书写,到处使用。

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"

call,apply得唯一区别

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

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

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"已经改不了了

其实bind得内部实现是,用到了call,或者是apply

Function.prototype.mybind=function(obj,...arg1){
    return function(...arg2){
        return this.apply(obj,arg1.concat(arg2))
    }
}//粗略版,返回一个函数,此函数执行返回原函数绑定到obj上得硬绑定,arg1,arg2是参数,不考虑原型链,错误, 兼容性等情况

原型得问题在面向对象讲。call/apply/bind问题再深入讨论

9.严格模式

可以不是函数开头可以加一句"use strict";让函数变成严格模式

  • 不允许用with。
  • 所有变量必须声明,赋值给未声明的变量报错,而不是隐匿创建全局变量。
  • eval中的代码不能创建eval所在作用域下的变量、函数。而是为eval单独创建一个作用域,并在eval返回时丢弃。
  • 函数中的特殊对象arguments是静态副本,而不像非严格模式那样,修改arguments或修改参数变量会相互影响。
  • 删除configurable=false的属性时报错,而不是忽略。
  • 对象字面量重复属性名报错。
  • 禁止八进制字面量,如010(八进制的8)。
  • 严格模式下eval、arguments变为关键字,不能用作变量名。
  • 一般函数调用时(不是对象的方法调用,也不使用apply/call/bind等修改this)this指向null,而不是全局变量。
  • 试图修改不可写属性(writable=false),在不可扩展的对象上添加属性时报TypeError,而不是忽略。
  • arguments.caller,arguements.callee被禁用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值