JS对象类型函数篇函数概述

定义函数

定义函数的方式有三种:函数声明语句、函数表达式和Function构造函数

函数声明语句

function functionName([arg1 [,arg2 [...,argn]]]) {
    statemant
}

functionName指要声明函数的名称(标识符),圆括号中是参数列表,参数之间用逗号分隔。当调用函数时,这些形参(参数列表)会被替换成实参(传入的参数)。

【声明提升】:函数声明语句定义的函数有个特点,就是函数体和函数名称会提升。

foo()
function foo(){
    console.log(1)
}
// 1

由于函数声明提升,上面的函数正常执行,相当于下面代码:

function foo(){
    console.log(1)
}
foo()

【重复】:如果两个函数重名了,那么后声明的函数会覆盖前声明的函数。

function b(){
    console.log(1)
}

function b(){
    console.log(2)
}
b() // 2
// 示例1
var a;
function a(){
    console.log(1)
}
a() // 1

// 示例2
var a = 2;
function a(){
    console.log(1)
}
console.log(a) // 2

// 示例3
var a = 2;
var a = 3;
console.log(a) // 3

// 示例4
var a = 2;
var a;
console.log(a) // 2

个人理解:如果变量只声明未初始化,则它的权重很低,重名函数或者已赋值重名变量都可以覆盖它。如果变量初始化了,那么它和重名的函数或变量权重一样,后面的会覆盖前面的。

【删除】:函数声明语句创建的变量无法删除

function a(){
    console.log(1)
}
delete a
a() // 1

函数表达式

var funcName = function([arg1 [,arg2 [...,argn]]]){
    statement;
}

var funcName = function functionName([arg1 [,arg2 [...,argn]]]){
    statement;
}

函数表达式定义的函数,函数名字是可选的。如果没有函数名字就是匿名函数(也叫拉姆达函数)。

var a = function(){
    console.log(1)
}
a() // 1

当函数有名字时,函数的名字会成为一个函数内部的局部变量,这个名字相当于函数对象的形参。

var a = function foo(){
    return foo
}

console.log(a) // foo(){ return foo }
console.log(a()) // foo(){ return foo }
console.log(a()()) // foo(){ return foo }

Function构造函数

var functionName = new Function(['arg1' [,'arg2' [...,'argn']]],'statement;');

类似于函数表达式,但它只能创建匿名函数。不推荐使用这种方式定义函数,因为它会解析两次代码,影响性能。

var sum = new Function('num1','num2','return num1 + num2');
//等价于
var sum = function(num1,num2){
    return num1+num2;
}

函数返回值

函数中的return语句用来定义函数的返回值。

return expression;

如果函数体中没有定义return语句,或者return语句没有expression,函数返回undefined。

var a = function(){
    return;
}
console.log(a()) // undefined

如果函数调用时在前面加了new关键字,且返回值不是一个对象,则返回this。

// 示例1
function foo(){
    this.name = 'hello'
    return 1;
}
var test = new foo()
console.log(test) // {name: 'hello'}

// 示例2
function foo(){
    this.name = 'hello'
    return {a: 1};
}
var test = new foo()
console.log(test) // {a: 1}

函数调用

函数调用有四种方式:函数调用模式、方法调用模式、构造器调用模式和间接调用模式

函数调用模式

函数调用模式在非严格模式下,this指向window对象。严格模式下this是undefined。

// 示例1
function add(x,y){
    console.log(this);//window
}    
add();

// 示例2
function add(x,y){
    'use strict';
    console.log(this);//undefined
}    
add();

可以根据this值判断当前是否是严格模式

var isStrict = (function(){return !this;}());

由于this指向全局对象,所以全局属性可能被重写

var a = 1;

function b() {
    this.a = 2
}
b()
console.log(a, this.a) // 2 2 

方法调用模式

当一个函数作为对象的属性时,这个函数就是该对象的方法。方法被调用时,this绑定到该对象,所以可以通过this修改对象的属性和方法。注意是方法调用时this才绑定到该对象。

var o = {
    a: 1,
    b: function(){
        return this
    },
    c: function(){
        this.a = 2
    }
}

console.log(o.b().a) // 1
o.c()
console.log(o.b().a) // 2

关键字this没有作用域限制,所以嵌套的函数不会从调用他的函数中继承this。如果嵌套函数作为方法调用,则this执行调用他的函数。如果嵌套函数作为函数调用,则this指向window(非严格模式)对象或是undefined(严格模式)

// 示例1
var o = {
    a: function(){
        // 嵌套函数
        function b(){
          return this
        }
        return b()
    }
}

console.log(o.a()) // window

// 示例2
'use strict'
var o = {
    a: function(){
        // 嵌套函数
        function b(){
          return this
        }
        return b()
    }
}

console.log(o.a()) // undefined

如果想要把嵌套函数的this绑定到外部函数,可以把this保存一个临时变量。

var o = {
    a: function(){
        var self = this
        // 嵌套函数
        function b(){
          return self
        }
        return b()
    }
}
console.log(o.a() === o) // true

构造函数调用模式

如果函数或者方法使用new关键字进行调用,就成为了构造函数调用。

// 示例1
function fn(x) {
    this.a = x
}
var test = new fn('good')
console.log(test.a) // 'good'

// 示例2 没有形参的构造函数可以省略圆括号
function fn() {
    this.a = 'good'
}
var test = new fn
console.log(test.a) // 'good'

当使用构造函数方式调用对象的方法时,对象中的this指向新对象的上下文。

var o = {
    name: 'good',
    a: function(){
        return this.name;
    }
}
var obj = new o.a();
// this指向obj而不是o,obj没有name属性,所以结果是空对象
console.log(obj, obj === o) // {} false

构造函数通常不适用return语句,当构造函数执行完毕后,会把新对象作为调用结果返回。

如果构造函数使用return语句但是没有指定返回值,或者返回一个原始值,那么返回值会被忽略,会把新对象作为调用结果返回。

如果构造函数使用return语句返回一个对象,那么会把这个对象作为调用结果返回。

// 示例1
function fn(){
  this.a = 1
}

var test = new fn()
console.log(test) // {a: 1}


// 示例2
function fn(){
  this.a = 1
  return 'hello'
}

var test = new fn()
console.log(test) // {a: 1}

// 示例3
var obj = {name: 'hello'}
function fn(){
  this.a = 1
  return obj
}

var test = new fn()
console.log(test) // {name: 'hello'}

间接调用模式

JS中的函数也是对象,函数对象中的方法可以通过call()apply()间接调用,这两个方法可以显式的改变this指向,所以任何函数都可以作为任何对象的方法来调用,即使这个函数不是该对象的方法。call()方法和apply()方法有些差别:call()方法以参数列表的形式传参,apply()方法以数组的方式传入参数。

var obj = {}
function sum(x,y){
   return x + y
}

console.log(sum.call(obj, 1,2)) // 3
console.log(sum.apply(obj, [1,2])) // 3
优秀文章首发于聚享小站,欢迎关注!
原文地址:https://www.cnblogs.com/yesyes/p/15351889.html