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...
相关推荐
Мартин.2 小时前
[Meachines] [Easy] Sea WonderCMS-XSS-RCE+System Monitor 命令注入
前端·xss
昨天;明天。今天。3 小时前
案例-表白墙简单实现
前端·javascript·css
数云界3 小时前
如何在 DAX 中计算多个周期的移动平均线
java·服务器·前端
风清扬_jd3 小时前
Chromium 如何定义一个chrome.settingsPrivate接口给前端调用c++
前端·c++·chrome
安冬的码畜日常3 小时前
【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次
开发语言·前端·javascript·函数式编程·tdd·fp·jasmine
ChinaDragonDreamer3 小时前
Vite:为什么选 Vite
前端
小御姐@stella3 小时前
Vue 之组件插槽Slot用法(组件间通信一种方式)
前端·javascript·vue.js
GISer_Jing3 小时前
【React】增量传输与渲染
前端·javascript·面试
eHackyd3 小时前
前端知识汇总(持续更新)
前端
万叶学编程6 小时前
Day02-JavaScript-Vue
前端·javascript·vue.js