JavaScript高级第二天知识点以及代码演示

1. 函数进阶

1.1. 定义函数的三种方式

1.函数声明 function:可以先调用再声明,因为预解析(把函数声明、变量声明进行提升)

function fn() {
  //函数体
  conle.log(1);
}

2.函数表达式:不可以先调用再声明,因为预解析只是把变量声明提升了,赋值留在原位。

var fn2 = function() {
  conle.log(2);
}
fn(2);

3.函数也是对象,函数也是通过构造函数new出来的 Function(大写的)(了解,工作当中不会使用到)

var fn3 = new Function(arg1, arg2, arg3..., bodyFn);

参数:

  1. 参数的个数是若干个
  2. 参数的类型都是字符串类型的
  3. 除了最后一个参数bodyFn外,其他参数都是创建的函数的形参
  4. 最后一个参数bodyFn 是创建的函数的函数体

代码演示:

var fn4 = new Function('n1', 'n2', 'alert(n1 + n2)');

// 等价于以下代码:
var fn4 = function(n1, n2) {
  alert(n1 + n2);
}

综合代码演示:

<body>
    <script>

        // 定义函数的三种方式

        /*// 1. 函数声明 function
        //  可以先调用在声明,因为预解析(把函数声明、变量声明进行提升)
        fn();
        function fn(){
            // 函数体
            console.log(1);
        }

        // 2. 函数表达式
        //  不可以先调用在声明,因为预解析只是把变量声明提升了,赋值留在原位
        fn2();
        var fn2 = function () {
            console.log(2);
        }*/


        // 3. 函数也是对象,函数也是通过构造函数new出来的 Function
        // 语法: var fn3 = new Function(arg1, arg2, ...., bodyFn);
        // 参数:
        //  1. 参数的个数是若干个
        //  2. 参数的类型都是字符串类型的
        //  3. 除了最后一个参数bodyFn外,其他参数都是创建的函数的形参
        //  3. 最后一个参数bodyFn是创建的函数的函数体

        var fn4 = new Function("n1", "n2", "alert(n1 + n2)");
        // 等价于以下代码
        /*var fn4 = function(n1, n2){
            alert(n1 + n2)
        }*/
        // console.log(fn4);
        fn4(1, 2);
    </script>
</body>

1.2 函数也是对象

1.2.1-函数的作用域链

在这里插入图片描述

1.2.2-函数的原型链

例:

function Person(){}
// 底层是通过 Function new 出来的
// var Person = new Function();  //Person是实例对象,是函数

Person的原型链:

Person ==> Function.prototype ==> Object.prototype ==> null

在这里插入图片描述
代码演示:

<body>
    <script>
        function Person(){}
        // 底层是通过 Function new 出来的
        //  var Person = new Function(); // Person是实例对象,是函数

        // Person的原型链:
        //  Person ==> Function.prototype ==> Object.prototype ==> null;

        // console.log(Function.prototype.__proto__); 

        // console.log(Person.prototype);
        console.dir(Function.prototype); // js中唯一的原型对象是个函数类型的
        //  在Function.prototype中,看到有call、apply、bind三个方法

        // 问函数是否可以使用call方法?可以,根据原型链来查找使用的。
    </script>
</body>

1.2.3-Function.prototype常用成员

  • call:调用函数,重新指向this
  • apply:调用函数,重新指向this
  • bind:重新指向this,返回一个新的函数,不调用

1.2.4-完整版原型链

核心的点:函数的双重身份,函数是函数,也是对象

1.函数作为构造函数来使用去创造对象
function Person(){

}
var p = new Person();

绘制原型三角关系:

  1. 构造函数:Person
  2. 原型对象:Person.prototype
  3. 实例对象:p
2.把函数当实例看,函数也是构造函数 Function 创建
底层就是 var Person = new Function();

绘制原型三角关系:

  1. 构造函数:Function
  2. 原型对象:Function.prototype
  3. 实例对象:Person
3.把Object考虑进来 ==> 当构造函数来使用
var obj = new Object();

绘制原型三角关系:

  1. 构造函数:Object
  2. 原型对象:Object.prototype
  3. 实例对象:obj
4.把Object当成实例对象来使用

任何函数底层都是 Function 创建的,都是Function的实例对象

底层 var Object = new Function();

绘制原型三角关系:

  1. 构造函数:Function
  2. 原型对象:Function.prototype
  3. 实例对象:Object
5.Function 当实例对象来看,谁把 Function 创建出来的
var Function = new Function();

绘制原型三角关系:

  1. 构造函数:Function
  2. 原型对象:Function.prototype
  3. 实例对象:Function
绘制完整版原型链的目的是辅助大家理解js中对象的继承关系:

在这里插入图片描述

小结:
  1. 任何对象的原型链上都有Object.prototype
  2. 任何函数的原型链上都有 Function.prototype
  3. 函数是一等公民
    1. typeof 函数==> function
    2. Function.prototype ==> 原型对象的类型是个函数
    3. Function 自己生自己
  4. 函数的双重身份
    是函数,也是对象
    是函数,有prototype属性
    是对象,有 _ _ proto_ _ 属性
    所以说函数有prototype属性,也有 _ _ proto_ _ 属性
综合代码演示:
<body>
    <script>
    // 从__proto__和prototype来深入理解JS对象和原型链
    // https://github.com/creeperyang/blog/issues/9

    // 王福朋 - 博客园
    // https://www.cnblogs.com/wangfupeng1988

    // 面试题
    /*console.log(Function instanceof Function);
    console.log(Function instanceof Object);
    console.log(Object instanceof Object);
    console.log(Object instanceof Function);*/


    // 完整版原型链
    //  核心点:函数的双重身份,函数是函数,也是对象

    // 1. 函数作为构造函数来使用,去创建对象
    function Person() {

    }
    var p = new Person();
    // 绘制原型三角关系
    // 构造函数:Person
    // 原型对象:Person.prototype
    // 实例对象:p


    // 2. 把函数当实例对象来看,函数也是构造函数Function创建
    // 底层就是 var Person = new Function();
    // 绘制原型三角关系
    // 构造函数:Function
    // 原型对象:Function.prototype
    // 实例对象:Person


    // 3. 把Object考虑进来 ==> 当构造函数来使用
    var obj = new Object();
    // 绘制原型三角关系
    // 构造函数:Object
    // 原型对象:Object.prototype
    // 实例对象:obj


    // 4. 把Object当成实例对象来使用
    //  任何函数底层都是Function创建的,都是Function的实例对象
    // 底层 var Object = new Function();
    // 绘制原型三角关系
    // 构造函数:Function
    // 原型对象:Function.prototype
    // 实例对象:Object

    // console.log( Object.__proto__ === Function.prototype );


    // 5. Function 当实例对象来看,谁把Function创建出来的
    //  var Function = new Function();
    // 绘制原型三角关系
    // 构造函数:Function
    // 原型对象:Function.prototype
    // 实例对象:Function

    // console.log(Function.__proto__ === Function.prototype);


    // 小结:
    //  1. 任何对象的原型链上都有Object.prototype
    //  2. 任何函数的原型链上都有Function.prototype
    //  3. 函数是一等公民
    //      1. typeof 函数 ==> function
    //      2. Function.prototype ==> 原型对象的类型是个函数
    //      3. Function自己生自己
    //  4. 函数的双重身份
    //      是函数,也是对象
    //      是函数,有prototype属性
    //      是对象,有__proto__属性
    //      所以说函数有prototype属性,也有__proto__属性

    // console.log( Function.prototype === Function.prototype  ); // true
    // console.log( Object.__proto__ === Function.prototype ); // true
    // console.log( Function.prototype.__proto__ === Object.prototype ); // true
    // console.log( Object.prototype.__proto__ === Object.prototype ); // false
    // console.log( Object.__proto__.__proto__ === Object.prototype ); // true
    </script>
</body>
练习题1:(看图就可以完全答出来)
console.log( Function.prototype === Function.prototype  ); // true
console.log( Object.__proto__ === Function.prototype ); // true
console.log( Function.prototype.__proto__ === Object.prototype ); // true
console.log( Object.prototype.__proto__ === Object.prototype ); // false
console.log( Object.__proto__.__proto__ === Object.prototype ); // true

1.2.5-练习题

<body>
    <script>
    /*function Person() {}
    var p = new Person()

    console.log(p.constructor); // Person
    console.log(Person.constructor); // Function*/

    // 2.
     // 构造函数Function.prototype 是否在Function实例对象的原型链上
    // console.log(Function instanceof Function); // true
    // console.log(Function instanceof Object); // true
    // console.log(Object instanceof Object);  // true
    // console.log(Object instanceof Function);  // true
    console.log( Function instanceof Array ); // false
    console.log( Array instanceof Function ); // true
    </script>
</body>

1.2.6-instanceof

instanceof:实例对象

语法:

对象 instanceof 构造函数

作用:

  • 字面上理解:对象是否是构造函数的实例对象,如果是的,就返回 true
  • 从原型链角度来理解:
    • 构造函数的prototype属性是否在对象的原型链上,如果在 返回true,否则返回false

代码演示:

<body>
    <script>
        // instanceof
        // instance 实例对象 
        // 语法:对象 instanceof 构造函数
        // 作用:
        //  字面上理解:对象是否是构造函数的实例对象,如果是的,返回true
        //  从原型链角度来理解:
        //    构造函数的prototype属性是否在对象的原型链上,如果在返回true,否则返回false

        var arr = [10, 20];
        // arr的原型链:
        //  arr ==> Array.prototype ==> Object.prototype ==> null;
        
        console.log( arr instanceof Array ); // true
        console.log( arr instanceof Object ); // true
    </script>
</body>

1.3 作用域

  • 变量可以起作用的区域(就是说一个变量声明定义好了,就可以在哪些区域内使用)
  • 在js中,有全局作用域和函数作用域(词法作用域,静态作用域)

函数作用域:当函数声明定义好了,其函数作用域就定下来了,其作用域链也定下来了

作用域链:任何函数可以形成作用域,函数嵌套在另外一个函数中,那么外层函数也有自己的作用域,这样从里到外直到全局作用域,形成的链式结构叫做作用域链。

每一个函数的作用域链:都是从当前函数作用域出发,从里到外形成

代码演示:

<body>
    <script>
        // 作用域:变量可以起作用的区域(就是说:一个变量声明定义好了,可以在哪些区域内使用)
        // 在js中,有全局作用域和函数作用域(词法作用域、静态作用域)

        // 函数作用域: 是当函数声明定义好了,其作用域就定下来了。

        function fn() {
            var num = 10;

            function inner(){

                function bar(){

                }

            }

        }

        console.log(num);

        // 作用域链:任何函数可以形成作用域,函数嵌套在另外一个函数中,外层函数也有自己的作用域,这样从里到外,直到全局作用域,形成的链式结构叫做作用域链。

        // 每一个函数作用域链:都是从当前函数作用域出发,从里到外形成

        // bar函数的作用域链: bar函数作用域 ==>  inner函数作用域 ==>  fn函数作用域 ==> 全局作用域
        // inner函数的作用域链: inner函数作用域 ==>  fn函数作用域 ==> 全局作用域
    </script>
</body>

1.3.1-变量的搜索原则

沿着作用域链来查找

  1. 首先会在当前作用域内查找是否有声明该变量,如果有就返回变量的值
  2. 如果没有,就去外层作用域中查找
  3. 如果外面也没有,就沿着作用域链继续往外找,直到全局作用域,如果有就返回
  4. 如果还没有,报错。(属性值找不到就是undefined,变量找不到就报错)

代码演示:

<body>
    <script>
        // 变量的搜索原则 ==> 沿着作用域链来查找
        // 1. 首先会在当前作用域内查找是否有声明该变量,如果有就返回变量的值
        // 2. 如果没有,就去外层作用域中查找,如果有就返回变量的值
        // 3. 如果也没有,就沿着作用域链继续往外找,直到全局作用域,,如果有就返回变量的值
        // 4. 如果还没有,报错。

        var num = 888;
        function outer(){
            function inner() {
                var num;                
                function fn(){
                    console.log(num);
                }
                fn()
            }
            inner()
        }
        outer()
    </script>
</body>

1.3.2-练习题

<body>
    <script>
    // 1.
    /*var num = 10;
    fn1();

    function fn1() {
        console.log(num); // undefined
        var num = 20;
        console.log(num); // 20 20
    }
    console.log(num); // 10 10*/


    // 代码在执行之前,先要经过预解析
    // 函数内的代码在执行之前也要经过预解析

    // 预解析
    /*function fn1() {
        var num; // undefined


        console.log(num); // undefined
        num = 20; // 修改的是局部num为20
        console.log(num); // 20
    }
    var num;

    num = 10; // 修改全局num为10
    fn1();
    
    console.log(num); // 10*/



    // 2.
    /*var num = 10;
    fn1();

    function fn1() {
        console.log(num); // 找的是全局num  10
        num = 20;          // 修改的是全局的num 为 20
        console.log(num); // 20
    }
    console.log(num); // 20*/


    // 3. 经典
    /*var num = 123;

    // 核心的点:
    //  函数写好了,其函数作用域就定下来了,也就是函数作用域链就定下来了。
    //  变量的查找遵循变量的搜索原则(沿着作用域链来查找)
    function f1() {
        console.log(num);
    }

    function f2() {
        var num = 456;
        f1();
    }
    f2(); // 打印啥?*/


    // 修改以上代码
    /*var num = 123;

    function f1(num) {
        // 函数形参的理解:是函数内部声明定义的局部变量
        //  var num = 实参; // 456

        console.log(num); // 456
    }

    function f2() {
        var num = 456;
        f1(num); 
        // f1(num)调用是传递的参数是实参,实际的值,找,找的是f2的局部num的值
        // 等价于 f1(456)
    }
    f2(); // 打印啥?*/



    // 4
    var num1 = 10;
    var num2 = 20;

    function fn(num1) {
        // var num1 = 实参undefined;
        // var num3; //  预解析

        num1 = 100;  // 局部的num1 为 100
        num2 = 200;  // 修改全局的num2 为 200
        num3 = 300;  // 局部的num3 为 300
        
        console.log(num1); // 100 
        console.log(num2); // 200
        console.log(num3); // 300
        var num3;
    }

    fn();

    console.log(num1); // 10
    console.log(num2); // 200
    console.log(num3); // error

    // 考虑的点:
    //  预解析(函数内的代码也要预解析)
    //  函数内的形参
    //  函数作用域什么时候定下来 ==> 函数写好之后就定下来了。
    </script>
</body>

几种特殊的this指向

  • 定时器中的this指向了window,因为定时器的function最终是由window来调用的。
  • 事件中的this指向的是当前的元素,在事件触发的时候,浏览器让当前元素调用了function

1.4 函数的四种调用模式

分析this指向的问题:

  1. 任何函数都有属于自己的this指向。
  2. this指向是动态灵活的,只有当函数调用的时候,才能确定下来this的指向
  3. 如何去分析this指向:
    1. 看这个this属于哪个函数
    2. 看这个函数是如何调用的 ==> 就能决定下来this指向谁

函数的四种调用模式:

第一种:函数调用模式

这种调用模式,函数内的this指向window。

第二种:构造函数调用模式

new + 构造函数():这种调用模式,构造函数的this指向新创建出来的实例对象

第三种:方法调用模式

对象.方法名():这种调用模式,方法内的this指向调用方法的那个对象

谁调用,this指向谁

是点语法和中括号语法,都是方法调用模式

第四种:上下文调用模式 ==> call()、apply()、bind() 这三个方法

综合代码演示:

<body>
    <script>
        // 函数的四种调用模式 ==> 分析this指向的
        //  1. 任何函数都有属于自己的this指向。
        //  2. this的指向是动态灵活的,只有当函数调用的时候,才能确定下来this的指向
        //  3. 如何去分析this指向
        //     1. 看这个this属于哪个函数
        //     2. 看这个函数是如何调用的 ==> 就能决定下来this指向谁。

        
        // 函数的四种调用模式

        // 1. 函数调用模式
        /*function fn(){
            console.log(this);
        }
        // 函数名(); 这种调用模式属于函数调用模式,函数内的this指向window
        fn();*/


        // 2. 构造函数调用模式
        /*function Person(){
            this.name = "lw";
            console.log(this);
        }
        // new 构造函数();这种调用模式属于构造函数调用模式,构造函数中的this指向新创建出来的实例对象
        var p = new Person();*/


        // 3. 方法调用模式
        var obj = {
            a: "abc",
            fn: function () {
                console.log(this);
            }
        }
        // 对象.方法名(); 这种调用模式属于方法调用模式,方法内的this指向调用方法的那个对象
        // 谁调用,this指向谁

        // 是点语法和中括号语法,都是属于方法调用模式
        obj.fn();
        obj["fn"](); // [] 中是字符串或数值

        // 练习题:
        function foo(){
            console.log(this);
        }

        var arr = [10, 20, foo];
        // 方法调用模式 ==> foo是被arr数组调用的,所以foo内的this指向了arr
        // 怎么写的就怎么来分析
        // arr[2](); // arr[2] ==> foo() 思考方式不对

        /*var arr = {
            0: 10,
            1: 20,
            2: foo
        }
        arr[2]();*/

        //4. 上下文调用模式 ==> call apply bind
    </script>
</body>

1.4.1-this练习题

<body>
    <script>
    // 1
    /*var age = 38; // 全局变量 ==> 等价于 window的属性 window.age = 38;

    var obj = {
        age: 18,
        getAge: function() {
            console.log(this.age);
        }
    }

    var f = obj.getAge; // 仅仅是把getAge方法赋值给了变量f
    // 函数调用模式,函数内的this,this指向window
    f(); // 怎么写的怎么分析*/

    // 2.
    /*var age = 38;
    var obj = {
        age: 18,
        getAge: function() {
            // 方法内的this指向obj
            console.log(this.age); // 18

            function foo() {
                // 1. 任何函数都有属于自己的this
                //  foo内的this和getAge方法内的this不是一个,之间没有关系
                console.log(this.age); // 38        
            }
            // 函数调用模式,
            foo();
        }
    }
    // 方法调用模式
    obj.getAge();
    obj["getAge"]();*/

    
    // 3
    var length = 10

    function fn() {
        console.log(this.length)
    }

    var obj = {
        length: 5,
        method: function(fn) {
            // 函数调用模式 fn函数内的this指向window
            fn(); // 10
            // arguments 伪数组 实参列表 ==>类似于这样 [fn, 10, 5]

            // 方法调用模式,fn方法被arguments调用,fn内的this指向arguments
            // console.log(arguments);
            arguments[0]();
        }
    }
    obj.method(fn, 10, 5);
    // 10 3
    </script>
</body>

1.4.2-上下文调用模式

作用:可以自己去取指定this指向

call()、apply()、bind() 三个方法,任何函数都可以去使用以上三个方法

1.4.2.1-call()方法

1.除了小括号可以调用函数外,还可以使用call()调用函数

演示:

function fn() {
	conle.log(111);
}
fn();
fn.call();

2.call的第一个参数可以用来修改函数内的this指向

演示:

function fn(2) {
  conle.log(2);
  conle.log(this);
}
fn2();  // 2 window
fn.call([10, 20, 30]);  // 2 [10, 20, 30]

3.call的参数是若干个

第一个参数 ==> 用来修改this指向

除了第一个参数之外的所有其他参数 ==> 都是用来给函数传递实参的

演示:

function fn3(n1, n2) {
  conle.log(this);
  conle.log(n1 + n2);
}
// fn3(10, 20)
fn3.call([], 100, 200);  //

作用:

  1. 调用函数
  2. 第一个参数来改this指向
  3. 给函数传递实参 ==> 除第一个以外的所有参数

综合代码演示:

<body>
    <script>
        // 上下文调用模式, 可以自己去指定this指向
        //  call apply bind三个方法
        //  任何函数都可以去使用以上三个方法。


        // call方法
        //  1. 除了小括号可以调用函数外,还可以使用call调用函数

        /*function fn(){
            console.log(1111);
        }
        fn();
        fn.call();*/

        // 2. call的第一个参数可以用来修改函数内的this指向
        /*function fn2(){
            console.log(2);
            console.log(this);
        }

        // fn2(); // 2 window
        fn2.call( {name: "lw"} );*/


        // 3. call的参数是若干个, 
        //  第一个参数 ==> 用来修改this指向
        //  除了第一个参数之外的所有其他参数 ==> 都是用来给函数传递实参的

        function fn3(n1, n2){
            console.log(this);
            console.log(n1 + n2);
        }

        // fn3(10, 20);
        fn3.call([], 100, 200);

        // call的作用
        //  1. 调用函数
        //  2. 第一个参数来改this指向
        //  3. 给函数传递实参 ==> 除第一个以外的所有参数
    </script>
</body>
1.4.2.2-方法借用(调)模式

上下文调用模式又称方法借用(调)模式

代码演示:

<body>
    <script>
        // 上下文调用模式又称方法借用(调)模式

        var dfg = {
            car: "加长版林肯",
            liaomei: function () {
                console.log("hello 啦, 妹子,哥有 " + this.car + ", 走啊,带你回家啊!!!");
            }
        }
        dfg.liaomei();

        var boge = {
            car: "小黄车"
        }
        
        // boge.liaomei(); // error
        // boge找dfg去借用liaomei方法
        dfg.liaomei.call(boge);
        dfg.liaomei.apply(boge);
        // 等价于boge.liaomei()的效果
        // 可以理解为第一个参数去借用了方法。

        //  1. call可以调用liaomei方法
        //  2. call的第一个参数把liaomei方法内的this修改指向boge
    </script>
</body>
1.4.2.3-伪数组与数组

伪数组与数组最大的区别:伪数组不能使用数组的方法,但可以让伪数组去借用数组的方法

伪数组定义:是个对象,有数字下标还有length属性,所以可以和数组一样进行循环,但是伪数组不能使用数组的方法。

常见的伪数组:

  1. arguments实参列表
  2. querySelectorAll()、getElementByTagName() 获取到的元素
  3. jq对象

例:

// 需求:给obj伪数组添加 2: '波哥'
var obj = {
  0: '班班',
  1: '大飞哥',
  length: 2
}

// 这是常规做法(第一种方法)
// obj[2] = '波哥';
// 还需要手动维护length
// obj.length++;
// conle.log(obj);

// Array.prototype.push:是从数组中的原型对象中去拿到push

// [].push ==> 从空数组上去获取到push方法

// 第二种:
// 数组的原型对象:
// Array.prototype.push.call(obj, '波哥');  //效果等价于:obj.push('波哥')

// 第三种:
;[].push.call(obj, '波哥', '啦啦', 'kuqi');

conle.log(obj);

注意点:

  1. [].push 简化写法,一定要注意: {} 和 [] 一定要使用 ; 分号隔开,否则语法报错

  2. 数组的push方法不仅有添加功能,内部还会自动的去维护length属性

代码演示:

<body>
    <script>
        // 伪数组与数组
        //  伪数组与数组最大的区别:伪数组不能使用数组的方法,但可以让伪数组去借用数组的方法。

        // 伪数组定义:是个对象,有数字下标和length属性,所以可以和数组一样进行循环,但是伪数组不能使用数组的方法。

        // 常见的伪数组
        //  1. arguments 实参列表
        //  2. querySelectorAll() getElementsByTagName() 获取到的元素
        //  3. jq对象

        // 需求:给obj伪数组添加 2: "波哥"
        var obj = {
            0: "班班",
            1: "大飞哥",
            length: 2
        }

        /*// 常规做法:
        obj[2] = "波哥";
        // 还需要手动维护length
        obj.length++;
        console.log(obj);*/

        /*var arr = [10, 20, 30];
        // arr.0 error
        arr[0]*/

        
        // obj.push("波哥"); // 直接使用无法,但是可以借用push方法
        // 找数组去要push方法
        // 数组的原型对象
        // Array.prototype.push ==> 是从数组的原型对象中去拿到push
        // [].push ==> 从空数组上去获取到push方法
        // Array.prototype.push.call(obj, "波哥", "xm", "xh", "lw");
        // 简化以上写法
        ;[].push.call(obj, "波哥", "xm", "xh", "lw", "aa", "bb");
        // 效果等价于:obj.push("波哥", "xm", "xh", "lw");
        console.log(obj);

        // 注意点:
        //  1. [].push 简化写法,一定要注意:{} 和 [] 一定要使用; 隔开,否则语法错误
        //  2. 数组的push方法不仅有添加功能,内部还会自动的去维护length属性
    </script>
</body>
1.4.2.4-伪数组借用数组的方法

代码演示:

<body>
    <script>
    var obj = {
        0: "班班",
        1: "大飞哥",
        2: "波哥",
        3: "xm",
        length: 4
    }

    // 把obj伪数组里面的每一项拼接成字符串 "班班-大飞哥-波哥-xm"

    var str = [].join.call(obj, "❥(^_-)❥");

    // 等价于:obj.join("-");

    console.log(str);
    </script>
</body>
1.4.2.5-apply方法

call方法和apply方法作用是一样的,写法上有区别

一样的参数:

  1. 可以调用函数
  2. 可以修改this指向
  3. 可以给函数传递实参

apply的语法

apply(thisArg, [实参列表])
  1. thisArg用来修改函数内的this指向
  2. 实参列表:是个数组或者伪数组,里面的就是传递给函数的所有实参

apply的平铺性:apply会把第二个参数里面的每一项取出来作为实参给函数传递过去。

代码演示:

<body>
    <script>
        // apply方法
        //  call方法和apply方法作用是一样的,写法上有区别

        // 一样的作用:
        //  1. 可以调用函数
        //  2. 可以修改this指向
        //  3. 可以给函数传递实参 (写法上有区别)

        // apply的语法
        //  apply(thisArg, 实参列表)
        //  1. thisArg 来修改函数内的this指向
        //  2. 实参列表 是个数组或伪数组,里面的就是传递给函数所有的实参

        /*function fn(){
            console.log(1);
        }
        fn();
        fn.call();
        fn.apply();*/


        /*function fn2(){
            console.log(2);
            console.log(this);
        }
        fn2.call({name: "call"});
        fn2.apply({name: "apply"});*/


        function fn3(n1, n2){
            console.log(this);
            console.log(n1 + n2);
            console.log(arguments);
        }

        // fn3.call([], 1, 2, 3, 4, 5, 6);
        fn3.apply({}, [1, 2, 3, 4, 5, 6]);
        //  apply的平铺性:apply会把第二个参数里面的每一项取出来作为实参给函数传递过去。
    </script>
</body>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值