JS函数

Posted liu_kaiyao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS函数相关的知识,希望对你有一定的参考价值。

函数
1) 作用 -- 函数也是对象,是一个引用数据类型

1. 利用函数可以封装一些具有特殊功能的代码,之后调用即可实现相应的效果
    arr.sort(); // 排序
    arr.reverse(); // 反转
    jQuery();
        ajax(); // http请求
2. 利用函数封装对象【api本质/构造函数】高级面向对象

2) 函数创建方式 --函数创建完毕后一般不会自动执行,需要调用

  1. 函数声明

     function 函数名(形参列表){       
         // 函数体
     }
    
     function sayMsg(name,age,gender){
         console.log(\'name:\',name);
         console.log(\'age:\',age);
         console.log(\'gender:\',gender);
     }
     sayMsg(\'zhangsan\',13,\'male\');
    实参的顺序与形参的顺序是一一对应的
    形参可以是对象,访问时obj.属性
    
  2. 函数表达式 -- 匿名函数赋值给变量

     var 函数名 = function(形参列表){
         // 函数体
     };
    
     var fun = function(name,age){
         console.log(name);
         console.log(age);
     }
     fun.call(this,\'tom\',20,\'male\');
     fun.apply(this,[\'larry\',18,\'female\']);
    

3) 调用方式

调用时解析器不会检查实参类型,数量
 多余的实参不会被赋值,实参不足,没有对应实参的形参是undefined
函数体return后的语句不会执行
return 后无值,无return --- 返回undefined
    函数名(实参列表);
    函数名.call(this,实参列表);
    函数名.apply(this,实参数组);

    sayMsg(\'zhangsan\',13,\'male\');
    fun.call(this,\'tom\',20,\'male\');
    fun.apply(this,[\'larry\',18,\'female\']);

4) 提升

 代码从它们在代码中出现的位置被移动到当前作用域最上方进行执行【解析器操作的】,这个过程叫做提升
  1. 变量的提升 -> 用var声明的变量会在所有代码执行前被声明(但是不会被赋值)
    1>

    a = 1;
    var a;
    console.log(a);
    ==>等价于
    var a;
    a = 1;
    console.log(a); // 1

    2>

    console.log(a);
    var a = 1;
    ==>等价于
    var a;
    console.log(a); // undefined --a未被赋值
    a = 1;
    
  1. 函数声明的提升 ->用函数声明方式创建的函数(function a(){}),会在所有代码执行前被创建

     1>  test();
        function test(){
            console.log(1);
        }
        ==>等价于
        function test(){
            console.log(1);
        }
        test(); // 1
    
    2>  fun();
        var fun = function(){     //函数表达式创建
            console.log(1);
        }
        ==>等价于
        var fun;
        fun(); // fun is not a function
        fun = function(){
            console.log(1);
        }
    
  2. 函数声明与函数表达式的提升 -> 函数声明的提升优先于函数表达式

        var fun = function(){
            console.log(2);
        }
        fun();
        function fun(){
            console.log(1);
        }
        ==>等价于
        function fun(){
            console.log(1);
        }
        var fun = function(){
            console.log(2);
        }
        fun();
    

5) 引用数据类型的比较

    同一个指针不可以同时指向多个堆内存中的区域
    但是同一个堆内存中的区域可以同时被多个指针所指向
    var obj1 = {
        name:\'tom\',
        age:13,
        gender:\'male\'
    }
    var obj2 = {
        name:\'tom\',
        age:13,
        gender:\'male\'
    }
    var obj3 = obj1;
    console.log(obj1 == obj2); // false
    console.log(obj1 === obj2); // false
    console.log(obj1 == obj3); // true
    console.log(obj1 === obj3); // true

6) 函数的内部属性 -> 只有在函数内部可以访问到的属性

  1. 形参
    接收参数的快捷方式
  2. arguments【类数组对象】
    当前函数接受的所有参数所存储的地方

    {
    \'0\': \'tom\',
    \'1\': \'13\',
    \'2\': \'male\',
    length:3 // 只有在浏览器打印时才显示
     }
    callee 指向当前的函数
    
    将类数组对象转换为数组
    

*3. this

当前函数执行时所依赖的环境
nodejs -> global对象
浏览器  -> window对象

this的指向性问题 
    可以根据函数的调用方式来判断
        函数名(实参列表);
        函数名.call(this,实参列表);
        函数名.apply(this,实参数组);

1、以()方式调用函数
    1>如果函数名的左边没有对象,即以函数方式调用,则this指向全局
        function test(){
            console.log(this);
        }
        test();            //函数方式调用
        nodejs -> global对象
        浏览器 -> window对象  =window.test()
    2>如果函数名的左边有对象,即以方法方式调用,则this指向该对象
        var obj1 = {
            name:\'tom\',
            sayName:function(){
                console.log(this.name);
            }
        }
        obj1.sayName(); // 以方法方式调用,this指向了obj1对象 tom

    3>以构造函数方式调用,this就是创建的对象
        function Person(name,age){
        this.name = name;   
        } 
        var per = new Person();  //this 指向per

2、以call和apply的方式调用
    更改this的指向

    var obj1 = {
        money:\'有钱\',
        pay:function(){
            console.log(this.money);
        }
    }
    var obj2 = {
        money:\'没钱\'
    }

    obj1.pay(); // 有钱
    obj1.pay.call(obj2); // 通过call()将this指向obj2 没钱
    obj1.pay.apply(obj2); // 通过apply()将this指向obj2 没钱

3、箭头函数的this指向外部函数的this
    function(){} es5
    ()=>{}  es6
    

7) 闭包

    函数内部的函数        
    function test(){
        function a(){
        }
    }

    function test(){
        var name = \'tom\';
        function a(){
            return name;
        }
        return a();
    }
    var res = test();
    console.log(res); // tom

    function test(){
        var name = \'tom\';
        console.log(age,\'-----\');   //age--undefined
        function a(){
            var age = 13;
            return name;
        }
        return a();
    }
    var res = test();
    console.log(res);

    内部函数可以访问外部函数中的属性,但是外部函数不能访问内部函数的属性

8) 匿名函数和自执行函数

匿名函数:没有名字的函数
    function(){}
    
自执行函数:会自动执行的函数---只执行一次
    ( function(){} ) ()
         函数对象
(function(){
    console.log(1);
})(); // 1

(function(name,age){
    console.log(name);
    console.log(age);
})(\'zhangsan\',13); // zhangsan 13

9) 方法

函数作为对象的属性,将该函数叫做对象的方法
var obj = new Object();
obj.name="jerry";
obj.sayName = function(){     //方法
    console.log(obj.name);
};
obj.sayName();   //调用对象的方法

10)作用域
1.全局作用域

 -  页面打开时创建,页面关闭时销毁
 -  有一个全局对象window--代表浏览器窗口,由浏览器创建,可以直接使用
 -  全局中创建的变量都会作为window对象的属性保存
   全局中创建的函数都会作为window对象的方法保存
  - 域中变量都为全局变量,页面任意部分均可访问
    var a=1;
    console.log(window.a);
    function fun(){}
    window.fun();

2.函数作用域

  -调用函数时创建,函数执行结束则销毁
  -每调用一次函数就会创建一个新的作用域
  -函数作用域中可以访问全局变量
  -在函数作用域中创建变量,会先在自身作用域寻找,无则在上一级作用域寻找,直到全局作用域,若依旧无,则会报错ReferenceError
  -函数作用域中想访问全局变量 -- window.a
  -有变量提升 -- var声明变量会提前, 有函数提升
  -函数内变量未用var 声明,则是全局变量
  -定义形参相当于在函数作用域中声明了变量

eg:

1>
var a = 10;
function fun(){
    var a = 20;
    function func2(){
        console.log(a);               //a = 20
        console.log(window.a)  //a = 10 
    }
    fun2();
} 
fun();  

2> 
var c =10;
function fun(){
    console.log(c);               
    c=20;
    d=100;
    }
fun();                   //c=10  --找全局
console.log(c);    //c=20   --函数内c未用var 声明,是全局变量
console.log(d);   //d = 100 -- 可访问,因为d是全局
       3> 
var e = 10;
function fun(e){      
    //var e; 定义形参即声明变量
    console.log(e);
}
fun();  //underfined    

11) 构造函数

function Person(name,age){
    this.name = name;
    this.age = age;
    this.sayName= function(){
        alert(this.name);
    };
}   
var per1 = new Person("zhangsan",18);  
console.log(per1 instanceof Person);    //true
console.log(per1 instanceof Object);    //true

构造函数执行流程:

1.立刻创建一个新的对象
2.将新的对象设置为函数中的this,在构造函数中可以使用this来引用新建的对象
3.逐行执行函数中的代码
4.将新建的对象作为返回值返回

使用同一个构造函数创建的对象称作一类对象或类的实例,也将一个构造函数成为一个类

使用instanceof 可以检查一个对象是否是一个类的实例
语法:
    对象 instanceof 构造函数
如果是,则返回true,否则返回false
任何对象和Object做instanceof检查是都会返回true

构造函数为每个对象都添加方法
构造函数内部的方法,在构造函数每次执行时都会创建一个新的,即所有实例的方法都是唯一的
eg.Person的每个对象都有 sayName方法,每次new Person执行 都会创建新的sayName方法
-->使所有对象共享同一方法:

  1. 将方法定义在全局作用域中
    问题:函数定义在全局作用域会污染全局作用域的命名空间,且不安全(可能被覆盖)

2.在原型中添加方法

function Person(name){
    this.name = name;
    this.sayName = function(){
        alert(this.name);
    }
}
-->
1.
    function Person(name){
        this.name = name;
        this.sayName = fun;

    }
    //sayName 方法在全局中定义
    function fun(){
        alert(this.name);
    }
    var per1 = new Person("A");
    var per2 = new Person("B");
    per1.sayName();  //alert

    per1.sayName == per2.sayName  // true

2.
    function Person(name){
        this.name = name;    
    }
    //原型中添加sayName 方法
    Person.prototype.sayName = function(){
        alert(this.name);
    };
    var per1 = new Person("A");
    var per2 = new Person("B");
    per1.sayName(); //alert

1.原型 prototype

创建的函数中,解析器会向函数添加一个属性prototype
该属性对应一个对象,该对象即原型对象
函数作为普通对象调用,prototype 无用
函数以构造函数方式调用,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,可以通过__proto__访问属性
原型对象相当于一个公共区域,同一类的所有实例都可访问该原型对象,可将对象中共有的内容统一设置到原型对象中
当访问对象的属性和方法时,先在对象自身找,无则去原型对象找,无去原型的原型中找,直到找到Object对象的原型,Object对象的原型无原型,若Object对象的原型依旧无,返回underfined

function MyClass(){
}
//向MyClass原型中添加属性
MyClass.prototype.a = 123;

//向MyClass原型中添加方法
MyClass.prototype.sayHello = function(){
    alert("hello");
};

var mc = new MyClass();

console.log(MyClass.prototype) // Object
console.log(mc.__proto__ == MyClass.prototype) //true
console.log(mc.a)  //123  --可访问到原型对象中的属性
mc.sayHello();  //原型找到alert

使用in检查对象中是否含有某个属性时,如果对象中没有但是原型有,返回true
可以使用对象的hasOwnProperty()联查对象自身中是否含有该属性

function Person(){
}
Person.prototype.name = "A";
var mc = new Person();
mc.age = 18;

console.log(\'\'name\'\' in mc);  //true

console.log(mc.hasOwnProperty(\'\'name\'\'));  //false
console.log(mc.hasOwnProperty(\'\'age\'\'));  //true


//原型对象也是对象,有原型
console.log(mc.__proto__.__proto__);   // object  --Object的原型
console.log(mc.__proto__.__proto__.__proto__); //null
console.log(mc.__proto__.__proto__.hasOwnProperty(\'\'hasOwnProperty\'\'));  //true

2.toString()
直接在页面中打印一个对象时,实际上时输出对象的toString()方法的返回值

function Person(name,age){
this.name = name;    
this.age = age;
}
var per = new Person("A",18);
console.log(per);  //[object Object]  
console.log(per.toString());  //[object Object]  
想输出对象内容,修改原型 toString方法
Person.prototype.toString = function(){
    return ...
}

3.封装实参的对象arguments
是类数组对象,可以通过索引操作数据,也可以获取长度
arguments中保存 调用函数时传递的实参
arguments.length --实参长度
不定义形参也可以用arguments使用实参,arguments[0]
arguments属性callee:对应一个函数对象,即当前执行的函数对象

function fun(){
    console.log(arguments.length);  //2
    console.log(arguments[0]);        //A 
    console.log(arguments.callee);   //fun
}
fun("A",18);

1、构造函数和普通函数的区别

1) 首字母
2) 调用方式
    构造函数通过new关键字调用
        var obj = new Object();
        new Vue();
    普通函数直接调用
        function sayName(){
            xxx
        }
        sayName();

2、函数使用()和不使用()的区别

使用(),表示调用当前函数,并返回函数的返回值
不使用(),表示一个指向当前函数的指针

如何将一个函数赋值给一个变量,再将变量放入到对象中?
错误代码:
    function test(){
        console.log(1);
        return \'hello world\';
    }
    var a = test();
    var obj = {
        name:a
    }
    console.log(obj); // 1 {name:\'hello world\'}
正确代码:
    function test(){
        console.log(1);
        return \'hello world\';
    }
    var a = test;
    var obj = {
        name:a
    }
    console.log(obj); // {name:[Function: test]}

3、return与console.log()的区别

函数使用return之后才会有返回值
函数使用console.log是没有返回值的

function test(){
    console.log(1);
}
function fun(){
    return 2;
}
var a = test();
var b = fun();
console.log(a); // 1 undefined
console.log(b); // 2

以上是关于JS函数的主要内容,如果未能解决你的问题,请参考以下文章

几个关于js数组方法reduce的经典片段

web代码片段

JS常用代码片段-127个常用罗列-值得收藏

ES7-Es8 js代码片段

谷歌浏览器调试jsp 引入代码片段,如何调试代码片段中的js

VSCode自定义代码片段——JS中的面向对象编程