JavaScript函数来喽!

1.普通函数

  • 普通函数

  • 不管是不是全局作用域,this都指向执行环境或者调用对象(重点理解)

// 1.如果在html文件中执行,那么执行环境为window
<html lang="en">
// 在html文件中引入script文件
  <script src="./test.js"></script>
// 在html文件中直接使用script标签执行JS代码
  <script>
      function myfn(){
        console.log(this); // this指向window对象
      }
      myfn();
      console.log(this); // this指向window对象
  </script>
</html>
// test.js文件下的代码
function myfn(){
    console.log(this); // window对象
}
// 调用方式
myfn();
// 或者 利用双阔号的方式,让其自动调用(网页被打开或者测试的时候,它就自行调用)
(function myfn(){
    console.log(this);
})()

// 2.在JS文件下测试(node环境),执行环境是准确来讲应该是 module.exports,也就是{} 空对象,也就会出现undefined(重点理解)
function myfn(){
    console.log(this); // undefined
}
myfn();
console.log(this); // undefined
  • 注意:

    • 在严格模式下(函数内部的this不能指向全局对象,默认等于undefined)

    • 全局作用域下,this指向执行环境

    • 非全局作用域下,this指向undefined

// 1.在html文件下执行
<body>
  <script>
    "use strict"; // 严格模式下
    function myfn() {
      console.log(this); // 非全局作用域里面的this指向 undefined
    }
    myfn()
    console.log(this); // 全局作用域里面this指向执行环境 window
  </script>
</body>
// 2.在JS文件下测试,没有对应的执行环境,则不管是不是全局作用域,this都指向 node环境的module.exports空对象{}
"use strict"; // 严格模式下
function myfn() {
  console.log(this); // undefined
}
myfn() // 调用函数
console.log(this); // undefined
  • 匿名函数

    • 说白了就是用一个变量来接收函数的返回值,输出这个变量,也就是输出这个变量的返回值

  • 注意:

    • 竟然是用变量来接收一个函数的返回值,则这个函数的性质就跟着定义变量的关键字来了,也就是说变量提不提升(意味着函数提不提升),提升之后是否进行初始化啊等等这些问题

let、const、var都能造成变量提升(函数提升),但是let、const不初始化函数,而var初始化函数,输出 undefined

  • this指向执行环境或者调用对象(重点理解

// 语法格式:
let myfn = function(){ // 接收变量为 myfn
    console.log(this); // this指向执行环境
}
myfn() // 这里是执行环境调用的 myfn()
let obj = {
    sing:function(){ // 接收的变量为 sing
        console.log(this); // this指向 obj对象
    }
}
obj.sing() // 这里是 obj 对象调用的 sing

// var 变量提升
console.log(myfn) // 这里面myfn后面不能接括号,因为myfn这个时候被初始化成 undefined了,如果加括号会报错 myfn不是一个函数
var myfn = function(){ // var有变量提升,且初始化变量,myfn
  console.log(this)
};
// let、const 变量提升,但是不会初始化变量,则会直接报错 myfn没有被初始化
console.log(myfn) 
const myfn = function(){
    console.log(this)
}
console.log(myfn)
let myfn = function(){
    console.log(this)
}
  • 构造函数(重点理解)

    • 定义

      • 构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 一起使用

    • 创建(区别普通函数)

      • 首字母一般大写

      • 函数体内部使用了this关键字,代表了所要生成的对象实例(最后返回的也就是这个this实例对象)

      • 生成对象的时候,必须使用new命令

    • 运用

      • 使用new关键字运用,另外可以用一个变量接收

    • 注意:(特别注意)

      • 构造函数必须使用new关键词调用,不然会出现变量外出的误会

      • 当利用new关键字时,构造函数内如果出现return语句返回一个数值,new命令则会忽略这个数值,返回“构造”后的this对象

      • 当利用new关键字时,构造函数内如果出现return语句返回一个与this无关的对象,new命令则会返回这个新对象,而不是“构造”的this对象

为了保证构造函数必须与new命令一起使用,一个解决办法是,构造函数内部使用严格模式,即构造函数内部第一行加上“use strict”(严格模式)。这样的话,一旦忘了使用new命令,直接调用构造函数就会报错。

// 创建构造函数方法(1)
function Start(name,age){
    // 构造函数里面的属性
    this.name = name;
    this.age = age;
    // 构造函数下的方法 
    this.sing = function(){
        console.log('我会唱歌')    
    }
}
// 创建构造函数方法(2)
let Start = function(name,age){
    // 构造函数里面的属性
    this.name = name;
    this.age = age;
    // 构造函数下的方法 
    this.sing = function(){
        console.log('我会唱歌')    
    }
}
// 运用构造函数
let start = new Start('ldh',23);
// 调用构造函数里面的方法
start.sing() 

// 未用 new 关键字调用 构造函数(造成误会)
function Myfn(){
    this.height = 190;
    return 180;
}
let myfn = Myfn();
console.log(myfn); // 180
console.log(window.height); // 190
// 利用 new 关键字调用 构造函数 (含有return返回数值)
function Myfn(){
    this.height = 190;
    return 190; // 有return 语句,并且返回的是一个数值,则会被new忽略
}
let myfn = new Myfn();
console.log(myfn); // 得到Myfn {height: 190},而不是return返回来的值,说明new使 自定义的return返回的数值被忽略了
console.log(window.height); // undefined
// 利用 new 关键字调用 构造函数 (含有return返回新的对象)
function Myfn(){
    this.height = 190;
    return {height : 180,price : 20}; // 有return 语句,并且返回的是一个新的对象,则新对象会把“构造”的this对象覆盖
}
let myfn = new Myfn();
console.log(myfn); // 得到Myfn {height : 180,price : 20},而不是return返回来的值,说明new使 自定义的return返回的数值被忽略了
console.log(window.height); // undefined

1.new关键字干了些什么?(重点理解)

  1. 创建一个空对象,作为将要返回的对象实例。

  2. 将这个空对象的原型(__proto__)指向构造函数的prototype属性。

  3. 将这个空对象赋值给函数内部的this关键字。

  4. 开始执行构造函数内部的代码。

也就是说,构造函数内部,this指的是一个新生成的空对象, 所有针对this的操作,都会发生在这个空对象上。构造函数之所以叫“构造函数”, 就是说这个函数的目的,就是操作一个空对象(即this对象),将其“构造”为需要的样子!

2.new.target是干嘛的?(重点理解)

用来指向new关键字处理的函数,如果不为new关键字处理,则new.target为undefined

用途:可以用来判定函数是否由new关键字处理

function Myfn(name, age) {
  this.name = name;
  this.age = age;
  if(new.target === undefined){
    throw Error('请使用new');
  }else{
    console.log('你成功使用了new');
  }
}
let myfn = new Myfn('ldh', 23); // '你成功使用了new'
let myfn = Myfn('ldh',23); // '请使用new' 

重点理解:

1.对象是什么?记忆理解

面向对象编程(Object Oriented Programming,缩写为 OOP)是目前主流的编程范式。它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟

(1)对象是单个实物的抽象。

一本书、一辆汽车、一个人都可以是对象,一个数据库、一张网页、一个与远程服务器的连接也可以是对象。当实物被抽象成对象,实物之间的关系就变成了对象之间的关系,从而就可以模拟现实情况,针对对象进行编程。

(2)对象是一个容器,封装了属性(property)和方法(method)。

属性是对象的状态,方法是对象的行为(完成某种任务)。比如,我们可以把动物抽象为animal对象,使用“属性”记录具体是那一种动物,使用“方法”表示动物的某种行为(奔跑、捕猎、休息)等等。

2.构造函数和普通函数的对比

区别:构造函数是一个封装对象,可以有属性和方法并且可以使用new关键字得到一个实例对象,之后通过这个实例对象来运用它们,而普通函数只能处理简单逻辑,得到某个值

// 构造函数
function Myfn(name){
    // 属性
    this.name = name;
    // 方法
    this.sing = function(){
        console.log('我会唱歌')    
    }
}
let myfn = new Myfn(); // 得到一个 Myfn{name,sing(){console.log('我会唱歌')}} 对象,
                       // 我们可以根据new出来的实例运用对象里的方法和属性
console.log(myfn.sing); // '我会唱歌' 
// 普通函数
function myfn(){
    let name = 'ldh';
    let sing = function(){
        console.log('我会唱歌');    
    }
    return myfn; // 得到的是一个 myfn对象值,而并不是对象
}
let fn = myfn(); // 这里就是 fn 变量接受了 myfn() 函数的return的值,也就是 myfn对象值
/*
// myfn对象值
ƒ func(){
  let a = 10;
  let sing = function(){
    console.log(this);
  }
  return func;
}
*/
console.log(fn.sing); // undefined 

3.Arguments对象

arguments是一个对应于传递给函数的参数的类数组对象。除了箭头函数以外的所有函数都有这个局部变量,它存储着我们手动传入的参数。

// 普通函数
function myfn(n1,n2){
  console.log(arguments); // 得到一个类数组 Arguments(2) [1, 2, callee: ƒ, Symbol(Symbol.iterator): ƒ] 存下了我们传进的参数 1,2
  console.log(arguments[0]); // 1
  console.log(arguments[1]); // 2
}
myfn(1,2);
// 构造函数
function Myfn(name,age){
    this.name = name;
    this.age = age;
    console.log(arguments); // 得到一个类数组 Arguments(2) ['ldh', 23, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    console.log(arguments[0]); // 'ldh'
    console.log(arguments[1]); // 23
}
let myfn = new Myfn('ldh',23);

2.箭头函数

  • 与普通函数的区别

在ES6中,箭头函数是其中最有趣的新增特性之一,箭头函数是一种使用箭头 => 定义函数的新语法,但它和传统的JavaScript函数有些许不同:

1.没有this、super、arguments和new.target绑定:(以下三种情况)

  • 1.1对象字面量里面含有箭头函数

    • 箭头函数中的this、super、arguments和new.target这些值由外围最近一层非箭头函数(离得最近的function字样)所决定。其实再说简单点就是箭头函数的this在定义它的时候就诞生了,且this的指向是外围的第一个含有function字样的对象的作用域对应的变量值

  • 1.2构造函数里面包含箭头函数

    • 箭头函数中的this、super、arguments和new.target这些值由构造函数决定,也就是this指向构造函数

  • 1.3普通函数里面包含箭头函数

    • 箭头函数中的this、super、arguments和new.target这些值由执行环境决定,也就是this指向执行环境变量

2.不能通过new关键词调用:因为箭头函数没有[[Construct]]函数,所以不能通过new关键词进行调用,如果使用new进行调用会抛出错误。

3.没有原型:因为不会通过new关键词进行调用,所以没有构建原型的需要,也就没有了prototype这个属性。

4.不可以改变this的绑定:在箭头函数的内部,this的值不可改变(即不能通过call、apply或者bind等方法来改变)。

5.不支持arguments对象:箭头函数没有arguments绑定,所以必须使用命名参数或者不定参数这两种形式访问参数。

6.不支持重复的命名参数:无论是否处于严格模式,箭头函数都不支持重复的命名参数。

  • 箭头函数的this问题(重点理解

    • 对象字面量中包含箭头函数的情况(重点理解

// 1.普通函数的this指向和改变this指向
var name = 'window'; // 其实是window.name = 'window'
var A = {
   name: 'A',
   sayHello: function(){
      console.log(this.name)    
   }
}

A.sayHello();// 输出A (普通函数的this指向,谁调用它,它就指向谁)

var B = {
  name: 'B'
}

A.sayHello.call(B);//输出B (普通函数的this指向可以被改变)
A.sayHello.call();//不传参数指向全局window对象,输出window.name也就是window

// 2.箭头函数的this指向以及this指向能否改变
var name = 'window'; 
var A = {
   name: 'A',
   // 定义sayHello为箭头函数,它的this会往外围寻找,也就是先找到 var A = {} 块级作用域,但并不含有function字样,则继续往外围找,找到最后都没找到
   // this就会指向执行环境对应的对象(浏览器对应window,node对应module.exports空对象{}[undefined])
   sayHello: () => {
      console.log(this.name)
   }
}
A.sayHello();// 还是以为输出A ? 错啦,其实输出的是window

// 3.再举个例子(在浏览器环境下执行)
let obj = {
  sing: () => {
    console.log(this); // 往上找function字样,找不到,就指向执行环境对应的对象,所以指向window
    let ring = () => {
      console.log(this); // 往上找function字样,找不到,就指向执行环境对应的对象,所以指向window
    }
    return ring();
  }
}
let obj1 = {};
obj.sing();
obj.sing.apply(obj1); // 上面的指向依旧不改变,还是指向window
// 4.继续举个例子(在浏览器环境下执行)
let obj = {
  sing:function(){
    console.log(this); // 普通函数,谁调用,this就指向谁,则指向obj
    let ring = () => {
      console.log(this); // 往上找function字样,找到sing是带有function字样的,sing所在obj的块级作用域中,则就指向obj这个变量
    }
    return ring();
  }
}
let obj1 = {};
obj.sing();
obj.sing.apply(obj1); // 可以改变普通函数this指向,则箭头函数跟随function字样的作用域的this
  •  普通函数和构造函数里面包含箭头函数(重点理解

1.构造函数里面含有箭头函数

this会指向构造函数

2.普通函数里面含有箭头函数(用不用闭包都是一样的)

this会指向执行环境变量

// 构造函数里面含有箭头函数
function Myfn(name,age){
  this.name = name
  this.age = age
  this.song = () => {
    console.log(this) // 指向构造函数 Myfn {name: 'ldh', age: 23, song: ƒ}
  }
}
let myfn = new Myfn('ldh',23);
myfn.song(); 
// 普通函数里面含有箭头函数(未使用闭包,利用立即调用函数处理)(执行环境为window)
function my(){
  let fn = (function(){
    let func = (() => {
      console.log(this); // 指向window,这里会发现 this 并没有指向 fn ,而是指向window
    })();
  })();
}
my()
// 普通函数里面含有箭头函数(使用闭包,利用立即调用函数处理)(执行环境为window)
function my(){
  let fun = function(){
    let func = () => {
      console.log(this) // 指向window,这里会发现 this 并没有指向 fun ,而是指向window
    }
    return func();
  }
  return fun()
}
my()
  • 箭头函数的表现形式(四种)

// 表现形式之一:没有参数
let reflect = () => 5
// 相当于
let reflect = function () {
  return 5
}

// 表现形式之二:返回单一值
let reflect = value => value // 单个参数时,可以不用小括号
// 相当于
let reflect = function (value) {
  return value
}

// 表现形式之三:多个参数
let reflect = (val1, val2) => val1 + val2 // 没有大括号包裹时,假定是有return的
// 或者
let reflect = (val, val2) => {
  return val1 + val2
}
// 相当于
let reflect = function (val1, val2) {
  return val1 + val2
}

// 表现形式之四:返回一个对象,对象必须被小括号包裹着才能返回,或者直接使用return
let reflect = (id) => ({ id: id, name: 'why' })
// 相当于
let reflect = function (id) {
  return {
    id: id,
    name: 'why'
  }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

执迷原理

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值