js基础深入总结


  • 便于阅读和交流

4.3 如何定义函数?

  • 函数声明
  • 表达式
  • 实例化函数对象

4.4 函数的2种角色

  • 函数: 通过()使用
  • 对象: 通过.使用 ==> 称之为: 函数对象

4.5 如何调用(执行)函数?

  • test()
  • new test()
  • obj.test()
  • test.call/apply(obj)
/*
  编写程序实现以下功能需求:
    1. 根据年龄输出对应的信息
    2. 如果小于18, 输出: 未成年, 再等等!
    3. 如果大于60, 输出: 算了吧!
    4. 其它, 输出: 刚好!
*/
function showInfo (age) {
    if(age<18) {
        console.log('未成年, 再等等!')
    } else if(age>60) {
        console.log('算了吧!')
    } else {
        console.log('刚好!')
    }
}
//多次调用
showInfo(17)
showInfo(22)

/*函数也是对象*/
function fn() {
    console.log('fn()')
}
console.log(fn instanceof Object) // true 函数是Object类型的实例
console.log(fn.prototype) // 有属性
console.log(fn.call) // 有方法
fn.xxx = 'abc' // 可以添加属性
fn.yyy = function () { // 可以添加方法

}
/*
  函数的2种角色
  1. 函数: 通过()使用
  2. 对象: 通过.使用  ==> 称之为: 函数对象
   */
fn() // fn是函数
fn.yyy() // fn是函数对象

4.6 回调函数

  • 回调函数一般指的是:一个函数A被作为参数传递给另一个函数B,回调函数B在A中被调用

  • 还有其他类型的回调函数

    • 你定义的
    • 你没有直接调用
    • 但最终它执行了(在特定条件或时刻)
  • 常见的回调函数?

    • DOM事件函数
    • 定时器函数
    • ajax回调函数(后面学)
    • 生命周期回调函数(后面学)
//1. DOM事件回调函数
var btn = document.getElementById('btn')
btn.onclick = function () {
    alert(this.innerHTML)
}

//2. 定时器回调函数
setInterval(function () {
    alert('到点啦!')
}, 2000)

IIFE

  • 理解

    • 全称: Immediately-Invoked Function Expression 立即调用函数表达式
    • 别名: 匿名函数自调用
  • 作用

    • 隐藏内部实现
    • 不污染外部命名空间
(function (i) {
    var a = 4
    function fn() {
        console.log('fn ', i+a)
    }
    fn()
})(3)

5. 函数中的this

5.1 this是什么?

  • 一个关键字, 一个内置的引用变量
  • 在函数中都可以直接使用this
  • this代表调用函数的当前对象
  • 在定义函数时, this还没有确定, 只有在执行时才动态确定(绑定)的

5.2 this的指向方式

  1. 默认绑定 :常用的函数调用类型:独立函数调用

    可以把这个规则看作是无法应用其他规则的时候 默认的规则,基本指向的是window

    function foo() {
        console.log(this);
    }
    foo(); //window
    
    var obj = {
        do: function () {
            foo(); //foo是直接使用不带任何修饰的函数引用进行调用,因此只能使用默认绑定 规则
        },
    };
    obj.do();
  2. 隐式绑定

    当函数引用有上下文对象的时候(obj),隐式绑定规则会把函数中的this绑定到这个上下文对象上

    function foo() {
        console.log(this.a);
    }
    var obj = {
        a: 2,
        foo: foo, //
    };
    obj.foo(); // //当foo调用的时候,它的落脚点确实是指向的obj对象,当函数引用有上下文对象的时候(obj),隐式绑定规则会把函数中的this绑定到这个上下文对象上
  3. 隐式绑定可能会出现隐式丢失的问题 :被隐式绑定的函数,会丢失了绑定对象

    function foo() {
        console.log(this.a);
    }
    var obj = {
        a: 2,
        foo: foo,
    };
    var fn1 = obj.foo;
    var a = "hello";
    fn1(); //hello 虽然fn1是obj.foo的一个引用,但是实际上它的引用是foo函数本身,因此fn1其实是一个不带任何修饰的函数调用,属于默认绑定
    
    //
    function foo() {
        console.log(this.a);
    }
    function doFoo(fn) {
        fn(); //传参也是隐式赋值,所以传递函数也是隐式赋值,赋值的是foo函数本身
    }
    var obj = {
        a: 2,
        foo: foo,
    };
    doFoo(obj.foo);
  4. 显式绑定

    function foo() {
        console.log(this.a);
    }
    var obj = {
        a: 2,
    };
    foo.call(obj); //2 //通过call 调用foo时,把foo的this强制的绑定给了obj上
  5. new绑定

    构造函数只是一些使用new

    操作符被调用的函数,使用new调用函数的时候,会构造一新的对象,这个时候 就把新的对象绑定给了函数的this上

    function Foo(a) {
        this.a = a;
    }
    var bar = new Foo(2);
    console.log(bar.a); //2

5.3 怎么判断this指向

  1. 函数是否在new中调用,如果是的话,this绑定的是新创建的对象

  2. 函数是否通过call、apply(显示绑定)调用,如果是,则this绑定的是执行的对象

  3. 函数是否在某个上下文对象中调用(隐式绑定),如果有,则this绑定在这个上下文对象上

  4. 如果以上都不是 则默认绑定 执行window

//obj.f在上面代码中,obj.f表示在obj对象上调用f函数,则调用对象为obj,此时this就指向obj,this.x就等于obj.x,即返回结果为2
//若把obj.f赋值给变量f1,然后在全局上下文中调用们函数,则f函数体的运行环境在全局上下文中执行,此时this就指向 window, this.x就等于 window.x,即返回结果为1
var x = 1;
var obj = {
    f:function(){
        console.log(this.x)
    },
    x:2
}
obj.f();
var f1 = obj.f;
f1();

6 call apply 与 bind

在JavaScript中,callapplybindFunction对象自带的三个方法。

这三个函数的存在意义是改变函数执行时的上下文,再具体一点就是改变函数运行时的this指向。

6.1 call()

  • call() 方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法

  • 当调用一个函数时,可以赋值一个不同的 this 对象。this 引用当前对象,即 call 方法的第一个参数。

  • 通过 call 方法,你可以在一个对象上借用另一个对象上的方法

  • 语法 fun.call(thisArg[, arg1[, arg2[, ...]]])

    • thisArg: 在fun函数运行时指定的this值。需要注意的是下面几种情况
      • 不传,或者传nullundefined, 函数中的this指向window对象
      • 传递另一个函数的函数名,函数中的this指向这个函数的引用,并不一定是该函数执行时真正的this
      • 值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象,如 StringNumberBoolean
      • 传递一个对象,函数中的this指向这个对象
    • arg1...
      • fun函数所需要的参数,逗号间隔
  • 案例:

    function a(){
        //输出函数a中的this对象
        console.log(this); 
    }
    //定义函数b
    function b(){} 
    
    var obj = {name:'我是obj'}; //定义对象obj
    a.call(); //window
    a.call(null); //window
    a.call(undefined);//window
    a.call(1); //Number
    a.call(''); //String
    a.call(true); //Boolean
    a.call(b);// function b(){}
    a.call(obj); //Object

6.2 apply()

  • 语法与 call() 方法的语法几乎完全相同,唯一的区别在于,apply的第二个参数必须是一个包含多个参数的数组(或类数组对象)。

6.3 bind()

bind() 函数会创建一个新函数(称为绑定函数)

  • bind是ES5新增的一个方法
  • 传参和call类似
  • 不会执行对应的函数,call或apply会自动执行对应的函数
  • 返回对函数的引用
  • 语法 fun.bind(thisArg[, arg1[, arg2[, ...]]])

6.4 练习

  • 求数组中的最大和最小值

    var arr = [34,5,3,6,54,6,-67,5,7,6,-8,687];
    console.log(Math.max.apply(Math, arr));
    console.log(Math.max.call(Math, 34,5,3,6,54,6,-67,5,7,6,-8,687));
    console.log(Math.max.bind(Math, 34,5,3,6,54,6,-67,5,7,6,-8,687)());
    console.log(Math.min.apply(Math, arr));
    console.log(Math.min.call(Math, 34,5,3,6,54,6,-67,5,7,6,-8,687));
    console.log(Math.min.bind(Math, 34,5,3,6,54,6,-67,5,7,6,-8,687)());
  • 将伪数组转化为数组

    var arrayLike = {
        0: 'qianlong',
        1: 'ziqi',
        2: 'qianduan',
        length: 3
    }
    console.log(Array.prototype.slice.call(arrayLike));
    console.log([].slice.call(arrayLike));

6.5 面试题

function fn1() {
    console.log(1);
}
function fn2() {
    console.log(2);
}
fn1.call(fn2); 
fn1.call.call(fn2);
posted @ 2023-01-13 22:28  z_bky  阅读(34)  评论(0)    收藏  举报