IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> JavaScript 进阶 - 第4天(笔记) -> 正文阅读

[JavaScript知识库]JavaScript 进阶 - 第4天(笔记)

JavaScript 进阶 - 第4天

了解函数中 this 在不同场景下的默认值,动态指定函数 this 的值,提升代码封装的灵活度。

  • 能够区分不同场景下函数中 this 的默认值
  • 知道箭头函数的普通函数的区别,掌握箭头函数的使用
  • 能够动指定函数中 this 的值
  • 了解基于类的面向对象的实现语法

一、this

了解函数中 this 在不同场景下的默认值,知道动态指定函数 this 值的方法。

1.1 默认值

this 是 JavaScript 最具“魅惑”的知识点,不同的应用场合 this 的取值可能会有意想不到的结果,在此我们对以往学习过的关于【 this 默认的取值】情况进行归纳和总结。

普通函数

普通函数的调用方式决定了 this 的值,即【谁调用 this 的值指向谁】,如下代码所示:

<script>
  // 普通函数
  function sayHi() {
    console.log(this);
  }
  // 函数表达式
  let sayHello = function () {
    console.log(this);
  }
	
  // 函数的调用方式决定了 this 的值
  sayHi(); // window
  window.sayHi();
	
 	// 普通对象
  let user = {
    name: '小明',
    walk: function () {
      console.log(this);
    }
  };
  // 动态为 user 添加方法
  user.sayHi = sayHi;
  uesr.sayHello = sayHello;
	
  // 函数调用方式,决定了 this 的值
  user.sayHi();
  user.sayHello();
</script>

注: 普通函数没有明确调用者时 this 值为 window,严格模式下没有调用者时 this 的值为 undefined

箭头函数

箭头函数中的 this 与普通函数完全不同,也不受调用方式的影响,事实上箭头函数中并不存在 this !箭头函数中访问的 this 不过是箭头函数所在作用域的 this 变量。

<script>
  console.log(this); // 此处为 window
  // 箭头函数
  let sayHi = function() {
    console.log(this); // 该箭头函数中的 this 为函数声明环境中 this 一致
  }

  // 普通对象
  let user = {
    name: '小明',
    // 该箭头函数中的 this 为函数声明环境中 this 一致
    walk: () => {
      console.log(this);
    },
    
    sleep: function () {
      let str = 'hello';
      console.log(this);
      let fn = () => {
        console.log(str);
        console.log(this); // 该箭头函数中的 this 与 sleep 中的 this 一致
      }
      // 调用箭头函数
      fn();
    }
  }

  // 动态添加方法
  user.sayHi = sayHi;
  
  // 函数调用
  user.sayHi();
  user.sleep();
  user.walk();
</script>

在开发中【使用箭头函数前需要考虑函数中 this 的值】,事件回调函数使用箭头函数时,this 为全局的 window,因此DOM事件回调函数不推荐使用箭头函数,如下代码所示:

<script>
  // DOM 节点
  let btn = document.querySelector('.btn');

  // 箭头函数 此时 this 指向了 window
  btn.addEventListener('click', () => {
    console.log(this);
  })

  // 普通函数 此时 this 指向了 DOM 对象
  btn.addEventListener('click', function () {
    console.log(this);
  })
</script>

同样由于箭头函数 this 的原因,基于原型的面向对象也不推荐采用箭头函数,如下代码所示:

<script>
  function Person() {

  }

  // 原型对像上添加了箭头函数
  Person.prototype.walk = () => {
    console.log('人都要走路...');
    console.log(this); // widow
  }

  let p1 = new Person();
  p1.walk();
</script>

1.2 定义值

以上归纳了普通函数和箭头函数中关于 this 默认值的情形,不仅如此 JavaScript 中还允许指定函数中 this 的指向,有 3 个方法可以动态指定普通函数中 this 的指向:

call

使用 call 方法调用函数,同时指定函数中 this 的值,使用方法如下代码所示:

<script>
  // 普通函数
  function sayHi() {
    console.log(this);
  }

  let user = {
    name: '小明',
    age: 18
  }

  let student = {
    name: '小红',
    age: 16}

  // 调用函数并指定 this 的值
  sayHi.call(user); // this 值为 user
  sayHi.call(student); // this 值为 student

  // 求和函数
  function counter(x, y) {
    return x + y;
  }

  // 调用 counter 函数,并传入参数
  let result = counter.call(null, 5, 10);
  console.log(result);
</script>

总结:

  1. call 方法能够在调用函数的同时指定 this 的值
  2. 使用 call 方法调用函数时,第1个参数为 this 指定的值
  3. call 方法的其余参数会依次自动传入函数做为函数的参数
apply

使用 call 方法调用函数,同时指定函数中 this 的值,使用方法如下代码所示:

<script>
  // 普通函数
  function sayHi() {
    console.log(this);
  }

  let user = {
    name: '小明',
    age: 18
  }

  let student = {
    name: '小红',
    age: 16
  }

  // 调用函数并指定 this 的值
  sayHi.apply(user); // this 值为 user
  sayHi.apply(student); // this 值为 student

  // 求和函数
  function counter(x, y) {
    return x + y;
  }

  // 调用 counter 函数,并传入参数
  let result = counter.apply(null, [5, 10]);
  console.log(result);
</script>

总结:

  1. apply 方法能够在调用函数的同时指定 this 的值
  2. 使用 apply 方法调用函数时,第1个参数为 this 指定的值
  3. apply 方法第2个参数为数组,数组的单元值依次自动传入函数做为函数的参数
bind

bind 方法并不会调用函数,而是创建一个指定了 this 值的新函数,使用方法如下代码所示:

<script>
  // 普通函数
  function sayHi() {
    console.log(this);
  }

  let user = {
    name: '小明',
    age: 18
  }

  // 调用 bind 指定 this 的值
  let sayHello = sayHi.bind(user);

  // 调用使用 bind 创建的新函数
  sayHello();
</script>

注:bind 方法创建新的函数,与原函数的唯一的变化是改变了 this 的值。

改变this三个方法总结:

call:fun.call(this,arg1, arg2,......)
apply:fun.apply(this, [arg1, arg2,......])
bind:fun.bind(this, arg1, arg2,......)

相同点:
	都可以用来改变this指向,第一个参数都是this指向的对象
区别:
	call和apply:都会使函数执行,但是参数不同
	bind:不会使函数执行,参数同call

二、class

了解 JavaScript 中基于 class 语法的面向对象编程,为后续课程中的应用做好铺垫。

传统面向对象的编程序语言都是【类】的概念,对象都是由类创建出来,然而早期 JavaScript 中是没有类的,面向对象大多都是基于构造函数和原型实现的,但是 ECMAScript 6 规范开始增加了【类】相关的语法,使得 JavaScript 中的面向对象实现方式更加标准。

2.1 封装

class(类)是 ECMAScript 6 中新增的关键字,专门用于创建类的,类可被用于实现逻辑的封装。

<script>
  // 创建类
  class Person {
	// 此处编写封装逻辑
  }

  // 实例化
  let p1 = new Person();
  console.log(p1);
</script>
实例成员
<script>
  // 创建类
  class Person {
    // 实例属性
    name = '小明';

    // 实例方法
    sleep () {
      console.log('sleeping...')
    }
  }

  // 实例化
  let p1 = new Person();
  p1.sayHi();
</script>

总结:

  • 关键字 class 封装了所有的实例属性和方法

  • 类中封装的并不是变量和函数,因此不能使用关键字 letconstvar

静态成员
<script>
  // 创建类
  class Person {
    // 静态属性
    static version = '1.0.0';

    // 静态方法
    static getVersion = function () {
      console.log(this.version);
    }
  }
	
  // 静态方法直接访问
  console.log(Person.version);
  Person.getVersion();
</script>

总结:

  • static 关键字用于声明静态属性和方法
  • 静态属性和方法直接通过类名进行访问
构造函数

创建类时在类的内部有一个特定的方法 constructor ,该方法会在类被实例化时自动被调用,常被用于处理一些初始化的操作。

<script>
  class Person {
    // 实例化时 立即执行
    constructor (name, age) {
      this.name = name;
      this.age = age;
    }
		// 实例方法
    walk () {
      console.log(this.name + '正在走路...');
    }
  }
	
  // 实例化
  let p1 = new Person('小明', 18);
  p1.walk();
</script>

总结:

  • constructor 是类中固定的方法名
  • constructor 方法在实例化时立即执行
  • constructor 方法接收实例化时传入的参数
  • constructor 并非是类中必须要存在的方法

2.2 继承

extends

extends 是 ECMAScript 6 中实现继承的简洁语法,代码如下所示:

<script>
  class Person {
    // 父类的属性
    legs = 2;
    arms = 2;
    eyes = 2;
		// 父类的方法
    walk () {
      console.log('人类都会走路...');
    }
		// 父类的方法
    sleep () {
      console.log('人都得要睡觉...');
    }
  }

  // Chinese 继承了 Person 的所有特征
  class Chinese extends Person {}

  // 实例化
  let c1 = new Chinese();
  c1.walk();
</script>

如上代码所示 extends 是专门用于实现继承的语法关键字,Person 称为父类、Chinese 称为子类。

super

在继承的过程中子类中 constructor 中必须调 super 函数,否则会有语法错误,如下代码所示:

<script>
  class Person {
    // 构造函数
    constructor (name, age) {
      this.name = name;
      this.age = age;
    }
    
    // 父类的属性
    legs = 2;
  	arms = 2;
  
    walk () {
      console.log('人类都会走路...');
    }
  }

  // 子类 English 继承了父类 Person
  class English extends Person {
    // 子类的构造函数
    constructor (name, age) {
      super(name, age);
    }

    // 子类的属性
    skin = 'white';
  	language = '英文';
    }

  // 实例化
  let e1 = new English('jack', 18);
  console.log(e1.name);
</script>

子类构造函数中的 super 函数的作用是可以将子类实例化时获得的参数传入父类的构造函数之中。

2.3 写在最后

ECMAScript 6 中基于类的面向对象相较于构造函数和原型对象的面向对象本质上是一样的,基于类的语法更为简洁,未来的 JavaScript 中也都会是基于类的语法实现,当前阶段先熟悉基于类的语法,后面课程中会加强基于类语法的实践。

拷贝:

拷贝不是直接赋值

浅拷贝:

含义:只拷贝最外面层的拷贝方式
	let obj = {
			uname : '张三丰',
			age : 22,
			sex : '男',
			color : ['red', 'blue', 'yellow', 'pink'],
			message : {
				index : 1,
				score : 99
			}
		}

		let newObj = {};

		Object.assign(newObj, obj);

		console.log( obj, newObj );

深拷贝:

含义:所有层都拷贝的方式

let obj = {
			uname : '张三丰',
			age : 22,
			sex : '男',
			color : ['red', 'blue', 'yellow', 'pink'],
			message : {
				index : 1,
				score : 99
			}
		}

		let newObj = {};

		function kaobei (newObj, obj) {

			for ( let key in obj ) {

				if ( obj[key] instanceof Array ) {// obj[key] 是数组
					 // obj[key]是数组,遍历
					 newObj[key] = [];
					 kaobei(newObj[key], obj[key]);
				} else if ( obj[key] instanceof Object ) { // obj[key]是对象
					// obj[key]是对象,遍历
					newObj[key] = {};
					kaobei(newObj[key], obj[key]);
				} else {
					newObj[key] = obj[key];
				}

			}

		}

		kaobei(newObj, obj);

		obj.message.score = 123;

		console.log( obj, newObj );


  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-08-23 16:34:41  更:2021-08-23 16:36:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:01:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码