js三座大三之函数

js三座大山

一:作用域和闭包 本质上是对函数的应用,对应的是函数式编程。

二:对象,原型,继承,类系列即面向对象编程

三:异步和单线程,目前主流是以promise为代表的异步编程

第一篇:

如何理解函数:函数是可运行的对象。

函数的声明方式:

函数声明:

csharp 复制代码
function myFunction() {
  return 'Hello, world!';
}

函数表达式

javascript 复制代码
var myFunctionExpression = function() {
  return 'Hello, world!';
};

区别:

  1. 提升(Hoisting):函数声明在整个作用域中都是可见的,因为它们会被提升到作用域的顶部。这意味着你可以在声明之前调用这个函数。而函数表达式(包括具名和匿名)在声明之前是不可见的,因为它们不会被提升。
javascript 复制代码
// 函数声明
console.log(myFunction()); // 输出:"Hello, world!"
function myFunction() {
  return 'Hello, world!';
}

// 函数表达式
console.log(myFunctionExpression()); // 报错:myFunctionExpression is not a function
var myFunctionExpression = function() {
  return 'Hello, world!';
};

2:可选的函数名:函数声明必须有一个函数名,而函数表达式可以是匿名的,不过大部分情况下js引擎是可以推断出函数名的。

javascript 复制代码
// 函数声明
function myFunction() {
  return 'Hello, world!';
}
// 匿名函数表达式
(function() {
  return 'Hello, world!';
}());

// 可以推断出的函数表达式
var test = function(){
 return 'Hello, world!';
}
consoel.log(test.name) // 'test'
  1. 作用域:函数声明的名称在整个作用域中都是可见的。而具名函数表达式的名称只在函数体内部有效&只读不可更改。
javascript 复制代码
// 函数声明
function myFunction() {
  return 'Hello, world!';
}
console.log(typeof myFunction); // 输出:"function"

// 具名函数表达式
var myFunctionExpression = function innerFunction() {
  return 'Hello, world!';
};
console.log(typeof innerFunction); // 输出:"undefined"

函数的组成结构:

- 函数名: 可选 但是确定后只读不可改变

arduino 复制代码
function myFunction() {
  return 'Hello, world!';
}
const origin = myFunction;
myFunction = 123
conosole.log(origin.name) // 'myFunction'

这段代码可以解释为 声明了一个myFunction的变量 然后开辟一段堆内存存储函数对象,里面有name,length,函数字符串,内部定义的变量,作用域链等上下文环境。然后将myFunction这个变量指向这段内存。这样后续就可以访问到这个函数了。需要注意的是 堆内存里面函数对象的name名字也是'myFunction'并且是只读的永远不会在改变。 所以平时我们说的函数名其实是指引用函数的变量。真正的函数名只能通过name属性或者在函数内部访问。函数的 name 属性可用于在调试工具或错误消息中标识该函数。它对语言本身没有任何意义。

javascript 复制代码
// case1:具名iife表达式 立即执行的函数表达式外部没有指向函数的引用
(function fn(name) {
  fn = '123' // 这里想要在内部改变函数名 无效因为是只读的
  console.log(fn); // 打印函数本身
})();

// case2:函数声明
function fn(){
  fn = '123' // 这里是改变了指向函数引用的变量fn 所以成功了
  console.log(fn); // 打印123
}
fn();


var myFunctionExpression = function innerFunction() {
    innerFunction = '123'
    myFunctionExpression = '123'
    console.log('test myFunctionExpression', myFunctionExpression); //  打印'123'
    console.log('test innerFunction', innerFunction); // 打印函数本身
};
myFunctionExpression()

在函数内部 指向函数引用的变量fn和函数名称fn同时存在且命名相同时 函数的引用变量fn优先级更高。

- 函数参数:形参 实参 默认参数 剩余参数 arguments(已弃用: 不再推荐使用该特性)

  1. 形参:形参是在函数定义时声明的参数,它们是函数内部的局部变量。当函数被调用时,形参会接收实参的值,可以通过函数的length属性获取。
javascript 复制代码
// 依次列出函数的形参
function myFunction(name, age) {
  return name + age;
}
myFunction.length // 2

// 默认参数影响形参
function myFunction(name, age = 1) {
  return name + age;
}
myFunction.length // 1

// 剩余参数影响形参
function myFunction(name, ...info) {
  return name + age;
}
myFunction.length // 1

所以在使用函数的形参即lenght属性来做判断时 要慎重 因为可能因为函数的写法不同导致功能异常

  1. 实参:实参是在函数调用时传递给函数的值,它们会赋值给函数的形参。

  2. 默认参数:在ES6中,函数可以有默认参数。如果在函数调用时没有提供实参,或者实参的值是undefined,那么形参会使用默认参数的值。

javascript 复制代码
function greet(name = 'World') { // 'World' 是默认参数
  console.log('Hello, ' + name);
}
greet(); // 输出:"Hello, World"

4.剩余参数(Rest Parameters):在ES6中,可以使用...语法定义剩余参数。剩余参数是一个数组,它包含了从它开始到所有后面的实参。

javascript 复制代码
function greet(name, ...others) { // others 是剩余参数 是一个真正的数组
  console.log('Hello, ' + name);
  console.log('Others: ' + others.join(', '));
}

greet('John', 'Paul', 'George', 'Ringo'); // 输出:"Hello, John" 和 "Others: Paul, George, Ringo"
  1. arguments对象(不推荐):在函数内部,可以使用arguments对象访问所有的实参,无论函数是否定义了对应的形参。arguments是一个类数组对象,它有一个length属性和索引属性,但是没有数组的方法。
matlab 复制代码
function greet() {
  for (var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }
}
greet('John', 'Paul', 'George', 'Ringo'); // 输出:"John" "Paul" "George" "Ringo"

- 函数体: 一段逻辑代码

- 返回值:符合js规范的数据类型

函数可以通过return语句返回一个值。这个返回的值可以是任何类型的数据,包括基本类型(如数字、字符串、布尔值等)和复杂类型(如对象、数组、函数等)。当函数执行到return语句时,函数的执行会立即停止,并且返回return语句后面的值。如果return语句没有跟任何值,或者函数没有return语句,那么函数会返回undefined。

函数的表现形式:

  1. 普通函数:默认this是动态的 执行调用对象。
javascript 复制代码
function greet(name) {
  console.log('Hello, ' + name);
}
  1. 对象方法:默认this指向obj对象。
javascript 复制代码
var obj = {
  greet: function(name) {
    console.log('Hello, ' + name);
  }
};
  1. 构造函数:默认this指向新创建的对象。
ini 复制代码
function Person(name) {
  this.name = name;
}
var john = new Person('John');
  1. 箭头函数:ES6引入了箭头函数,它是一种更简洁的函数语法。箭头函数没有自己的thisargumentssupernew.target这些值由外层作用域的非箭头函数决定
    注意: 只有函数才能生成新的作用域
javascript 复制代码
var greet = (name) => {
  console.log('Hello, ' + name);
};


const obj = {
    name: 'hahha',
    run(){
        const say = (name) => {
          console.log(this); // this指向obj
        }; 
      say();
    }
}
obj.run()
javascript 复制代码
const obj = {
    name: 'hahha',
    run:()=>{
        console.log('run this', this)
    },
    say:function(){
        console.log('say this', this)
    }
}
obj.run() // this指向全局window 因为对象不生成作用域 只有函数才能生成新的作用域
obj.say() // this指向obj 
  1. 立即执行函数iife
javascript 复制代码
(function(name) {
  console.log('Hello, ' + name);
})('World');

// 具名立即执行函数
(function fn(name) {
  console.log(fn); // 打印函数 
  console.log(name);
})('World');
typeof fn // 'undefined' 实际上是一个函数表达式所以这里访问不到函数名字
  1. 闭包函数: 控制变量访问权限,延长变量的声明周期,因为声明周期被延长了 所以可能导致内存泄漏。因为内存泄漏的本质就是:对象的生命周期大于对象的作用域,导致对象没被及时释放.
csharp 复制代码
function fn(...list){
    let params = [...list]
    return function(...rest){
        params = [...params, ...rest]
        return params;
    }
    
}
  1. 函数对象:
javascript 复制代码
function fn(...list){
    console.log('fn:', list)
}
fn.test = 'test' // 函数就是一个对象,所以可以动态添加属性。
javascript 复制代码
function fn(){
    console.log('fn:', this)
}
let obj = {name: 'abc'}
fn.call(obj) // 函数是一个对象 所以在fn实例上找不到call方法后会向Function.prototype中寻找。
  1. 生成器函数(Generator Function):ES6引入了生成器函数,它可以返回一个生成器对象。生成器对象可以按需产生一系列的值。
javascript 复制代码
function* idGenerator() {
  var id = 0;
  while (true) {
    yield id++;
  }
}

参考:

  1. developer.mozilla.org/zh-CN/docs/...
  2. es6.ruanyifeng.com/#docs/funct...
相关推荐
在云端易逍遥1 分钟前
前端必学的 CSS Grid 布局体系
前端·css
ccnocare3 分钟前
选择文件夹路径
前端
艾小码3 分钟前
还在被超长列表卡到崩溃?3招搞定虚拟滚动,性能直接起飞!
前端·javascript·react.js
闰五月4 分钟前
JavaScript作用域与作用域链详解
前端·面试
泉城老铁8 分钟前
idea 优化卡顿
前端·后端·敏捷开发
前端康师傅8 分钟前
JavaScript 作用域常见问题及解决方案
前端·javascript
司宸9 分钟前
Prompt结构化输出:从入门到精通的系统指南
前端
我是日安10 分钟前
从零到一打造 Vue3 响应式系统 Day 9 - Effect:调度器实现与应用
前端·vue.js
Mintopia22 分钟前
🚀 Next.js 全栈 E2E 测试:Playwright vs Cypress
前端·javascript·next.js