当前位置: 首页 > article >正文

三、js笔记

(一)JavaScript概述


1、发展历史

  • ScriptEase.(客户端执行的语言):1992年Nombas开发出C-minus-minus(C--)的嵌入式脚本语言(最初绑定在CEnvi软件中).后将其改名ScriptEase.(客户端执行的语言)
  • Javascript:Netscape(网景)接收Nombas的理念,(Brendan Eich)在其Netscape Navigator 2.0产品中开发出一套livescript的脚本语言.Sun和Netscape共同完成.后改名叫Javascript
  • Jscript:微软随后模仿在其IE3.0的产品中搭载了一个JavaScript的克隆版叫Jscript.
  • EcmaScript规范:为了统一三家,ECMA(欧洲计算机制造协会)定义了ECMA-262规范.国际标准化组织及国际电工委员会(ISO/IEC)也采纳 ECMAScript 作为标准(ISO/IEC-16262)。从此,Web 浏览器就开始努力(虽然有着不同的程度的成功和失败)将 ECMAScript 作为 JavaScript 实现的基础。EcmaScript是规范. 

2、JavaScript组成

ECMAScript 是一个重要的标准,但它并不是 JavaScript 唯一的部分,当然,也不是唯一被标准化的部分。实际上,一个完整的 JavaScript 实现是由以下 3 个不同部分组成的:

  • 核心(ECMAScript) 
  • 文档对象模型(DOM) Document object model (整合js,css,html)
  • 浏览器对象模型(BOM) Broswer object model(整合js和浏览器) 

注:Javascript 在开发中绝大多数情况是基于对象的,也是面向对象的


(二)ECMAScript


包含内容:

  • 语法 
  • 类型 
  • 语句 
  • 关键字 
  • 保留字 
  • 运算符 
  • 对象 (封装 继承 多态) 基于对象的语言.使用对象.

1、JavaScript的引入方式

使用<script>标签,写在哪个位置都行,一般放在body最后,因为加载顺序从上到下,放在前面标签还没加载找不到,放最后标签已经加载了,更好找到标签

1.1 嵌入式 

<script>
    /*这里直接编写js代码,如:alert('hello yuan')*/
</script>

 1.2 导入式(推荐)

<script src="hello.js"></script>  // src是js文档的路径

2、Javascript语法 

2.1 变量

  • js变量是弱类型,声明变量时不区分数据类型,统一用var关键字声明变量,如:var a;
  •  可以声明变量的同时赋值,一行可以声明多个变量(以逗号,分隔),并且可以是不同类型,如:var name="张三", age=18, job="lecturer";
  • (了解) 声明变量时 可以不用var. 如果不用var 那么它是全局变量,但推荐都使用var关键字声明变量,效率更高,也能避免一些问题。
  • 还可以用let关键字声明块作用域变量(更推荐):
    • 只在声明它所在的块(由 {} 包围的代码块)、语句或表达式内部有效。
    • 同一作用域内,不能使用 let 重复声明同一个变量名,如果尝试这样做,将会引发一个错误。
    • 暂时性死区:变量声明之前的作用域范围内,该变量是不可访问的,尝试在声明之前访问 let 变量会引发一个 ReferenceError
    • 虽然 let 声明的变量会被提升到它们所在的作用域顶部,但是在变量声明之前的任何访问都会因为暂时性死区而失败。
    • 在循环中的特殊行为‌:let 在循环内部声明变量时(特别是 for 循环),每次迭代都会为该变量创建一个新的绑定。这意味着循环体内的每个变量都是独立的,并且具有自己的值。
      /*例子:let 如何提供块作用域,并且如何在不同的块中独立地声明和使用变量。*/
      {
        let x = 10;
        console.log(x); // 输出 10
      }
      console.log(x); // ReferenceError: x is not defined
      
      let y = 20;
      {
        let y = 30; // 这是一个新的块作用域内的 y
        console.log(y); // 输出 30
      }
      console.log(y); // 输出 20,外部的 y 没有被内部的 y 影响
      
      // 在循环中使用 let
      for (let i = 0; i < 3; i++) {
        console.log(i); // 分别输出 0, 1, 2
      }
      console.log(i); // ReferenceError: i is not defined,因为 i 只在循环块内有效
      
  • 变量命名,首字符只能是字母,下划线,$美元符 三选一,且区分大小写,x与X是两个变量。
  • 变量还应遵守以下某条著名的命名规则:
    • Camel 标记法(小驼峰式):首字母是小写的,接下来的字母都以大写字符开头。例如:var myTestValue = 0, mySecondValue = "hi";
    • Pascal 标记法(大驼峰式):首字母是大写的,接下来的字母都以大写字符开头。例如:Var MyTestValue = 0, MySecondValue = "hi";
    • 匈牙利类型标记法:在以 Pascal 标记法命名的变量前附加一个小写字母(或小写字母序列),说明该变量的类型。例如,i 表示整数,s 表示字符串,则:Var iMyTestValue = 0, sMySecondValue = "hi";

2.2 常量

常量 :直接在程序中出现的数据值,或使用const关键字声明的变量,不可被修改和重新赋值 

2.3 基础规范 

  • js代码每个语句后要有语句结束标志——分号;
  • 但如果一个语句写一行的话,不加分号也不会有问题,因为js会自动把换行符视为这一行结束;
  • 但如果语句结束不加分号也不换行就写别的语句,那就报错了
  • 注释:
    • 单行注释://
    • 多行注释:/* */
  • 使用{}来封装代码块,如:
    • function f(参数列表){函数体}
    • if (条件语句){代码块}

2.4 标识符 

  • 标识符: 
    • 由不以数字开头的字母、数字、下划线(_)、美元符号($)组成
    • 常用于表示函数、变量等的名称
    • 例如:_abc,$abc,abc,abc123是标识符,而1abc不是
    • JavaScript语言中代表特定含义的词称为保留字,不允许程序再定义为标识符

2.5 数据类型 

  • 基本类型(数据存储在栈内存):数字类型(Number)、字符串(String)、布尔型(Boolean)、Null、Undefined
  • 引用类型(数据存储在堆内存,把指向堆内存地址的引用存储在栈内存):对象(object)、数组、函数
  • 类似python的字典在js中是object类型:不同于python中的字典,js中a={name:"alex"}就相当于a={"name":"alex"},取值方法为a.name或a["name"]
 (1)数字类型(Number)
  • 最基本的数据类型
  • 不区分整型数值和浮点型数值
  • 所有数字都采用64位浮点格式存储,相当于Java和C语言中的double格式
  • 能表示的最大值是±1.7976931348623157 x 10308 
  • 能表示的最小值是±5 x 10 -324  
  • 在JavaScript中10进制的整数由数字的序列组成:
    • 精确表达的范围是:-9007199254740992 (-253) 到 9007199254740992 (253)
    • 超出范围的整数,精确度将受影响
  • 浮点数:
    • 使用小数点记录数据,例如:3.4,5.6
    • 使用指数记录数据,例如:4.3e23 = 4.3 x 1023
  • 16进制和8进制数的表达:
    • 16进制数据前面加上0x,八进制前面加0
    • 16进制数是由0-9,A-F等16个字符组成
    • 8进制数由0-7等8个数字组成
    • 16进制和8进制与2进制的换算:
      # 2进制: 1111 0011 1101 0100   <-----> 16进制:0xF3D4 <-----> 10进制:62420
      # 2进制: 1 111 001 111 010 100 <-----> 8进制:0171724
(2)字符串(String) 
  • 是由Unicode字符、数字、标点符号组成的序列
  • 字符串常量:首尾由单引号或双引号括起的字符序列
  • JavaScript中没有字符类型
  • 常用特殊字符在字符串中的表达:
    • 字符串中部分特殊字符必须加上反斜杠\,如Unicode字符\u4f60
    • 常用的转义字符 \n:换行 \':单引号 \":双引号 \\:右划线
(3)布尔型(Boolean) 
  • Boolean类型仅有两个值:true和false,也代表1和0,实际运算中true=1,false=0
  • 布尔值也可以看作on/off、yes/no、1/0对应true/false
  • Boolean值主要用于JavaScript的控制语句,例如:
    if (x==1){
        y=y+1;
    }else{
        y=y-1;
    }
(4)Null & Undefined 
  •  Null 类型:只有一个专用值 null,即它的字面量。值 undefined 实际上是从值 null 派生来的,因此 ECMAScript 把它们定义为相等的
  • Undefined 类型只有一个值,即 undefined:
    • 当声明的变量未初始化时,该变量的默认值是 undefined
    • 当函数无明确返回值时,返回的也是值 "undefined"
  • 尽管这两个值相等,但它们的含义不同:
    • undefined 是声明了变量,但未对其初始化时赋予该变量的值;
    • null 则用于表示尚未存在的对象,如果函数或方法要返回的是对象,那么找不到该对象时,返回的通常是 null。
    • typeof null的结果是object
(5)对象object 
  • 在JavaScript中,对象(Object)是一种包含多个键值对(key-value pairs)的数据结构。
  • 每个键值对将一个键(也称为属性名)映射到一个值。
  • JavaScript对象具有动态性,可以在运行时添加、修改或删除属性,而不需要预先定义对象的结构,这有助于JavaScript对象处理复杂和多变的数据。
  • 对象是JavaScript编程中的核心概念之一,广泛用于存储和管理复杂的数据。
let person = {
  firstName: "John",
  lastName: "Doe",
  age: 30,
  isStudent: false,
  courses: ["Math", "Science", "History"],
  address: {
    street: "123 Main St",
    city: "Anytown",
    state: "Anystate",
    zipCode: "12345"
  },
  greet: function() {
    console.log("Hello, my name is " + this.firstName + " " + this.lastName);
  }
};
/*示例中,person 对象包含了多个属性:

firstName 和 lastName 是字符串类型的属性,分别存储人的名和姓。
age 是数字类型的属性,存储人的年龄。
isStudent 是布尔类型的属性,表示该人是否为学生。
courses 是数组类型的属性,存储该人参加的课程列表。
address 是另一个对象类型的属性,包含街道、城市、州和邮政编码等子属性。
greet 是一个方法(函数),当调用时,会打印出一个问候消息。
你可以通过以下方式访问和操作对象的属性:
*/

// 访问属性
console.log(person.firstName); // 输出 "John"
console.log(person["lastName"]); // 输出 "Doe"
console.log(person.address.city); // 输出 "Anytown"

// 修改属性
person.age = 31;
console.log(person.age); // 输出 31

// 调用方法
person.greet(); // 输出 "Hello, my name is John Doe"

// 添加新属性
person.email = "john.doe@example.com";
console.log(person.email); // 输出 "john.doe@example.com"

// 删除属性
delete person.isStudent;
console.log(person.isStudent); // 输出 undefined,因为属性已被删除
 (5.1)创建对象:对象字面量

最简单和最常用的方法,只需用花括号 {} 包围一组键值对即可

let obj = {
  key1: "value1",
  key2: "value2",
  key3: 3,
  key4: true,
  key5: function() {
    console.log("This is a method!");
  }
};
(5.2)创建对象:Object 构造函数

使用 new Object() 来创建一个空对象,然后添加属性。 

let obj = new Object();
obj.key1 = "value1";
obj.key2 = "value2";
// ...
 (5.3)创建对象:Object.create() 方法

创建一个拥有指定原型和属性的对象,其中第一个参数是现有对象的原型,还可以传递一个描述符对象来添加或修改新对象的属性。

let proto = {
  greet: function() {
    console.log("Hello!");
  }
};
let obj = Object.create(proto);
obj.key1 = "value1";
// ...
(5.4)创建对象:自定义构造函数‌ 

自定义一个构造函数,然后使用 new 关键字来创建对象实例

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.sayHello = function() {
    console.log("Hello, my name is " + this.name);
  };
}

let person1 = new Person("John", 30);
let person2 = new Person("Jane", 25);
(5.5)创建对象:class 关键字‌(ES6引入) 

定义一个类,然后使用 new 关键字来创建类的实例。这是ES6及更高版本中推荐的方式,因为它提供了更清晰和更结构化的方式来定义对象和其行为。

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sayHello() {
    console.log("Hello, my name is " + this.name);
  }
}

let person1 = new Person("John", 30);
let person2 = new Person("Jane", 25);
(5.6)创建对象:工厂函数 

不使用 new 关键字就能创建对象的方法,通常返回一个包含所需属性和方法的普通对象。 

function createPerson(name, age) {
  return {
    name: name,
    age: age,
    sayHello: function() {
      console.log("Hello, my name is " + this.name);
    }
  };
}

let person1 = createPerson("John", 30);
let person2 = createPerson("Jane", 25);
(5.7)注意事项 
  • 每种方法都有其适用的场景和优缺点。
  • 通常,对于简单的对象,使用对象字面量是最方便的。
  • 对于需要多个实例的对象,使用构造函数或类可能更合适。
  • 工厂函数则提供了一种更加灵活和不需要 this 绑定的创建对象的方式。 

2.6 数据类型转换 

  • JavaScript属于松散类型的程序语言:
    • 变量在声明的时候并不需要指定数据类型
    • 变量只有在赋值的时候才会确定数据类型
    • 表达式中包含不同类型数据则在计算过程中会强制进行类别转换:
      • 数字 + 字符串:数字转换为字符串

      • 数字 + 布尔值:true转换为1,false转换为0

      • 字符串 + 布尔值:布尔值转换为字符串true或false

2.7 强制类型转换函数 

  • 函数parseInt:强制转换成整数,例如:
    • parseInt("6.12")=6 ;
    • parseInt(“12a")=12 ;
    • parseInt(“a12")=NaN ;  // NAN:意思是not a number,当强转数字时遇到不属于数字的字符时,会转换数字失败,如果前面有数字,截取前面的数字为结果,否则哪怕后面再有数字,值为NAN,属于Number类型
    • parseInt(“1a2")=1
  • 函数parseFloat:强制转换成浮点数,例如:parseFloat("6.12")=6.12
  • 函数eval:将字符串强制转换为表达式并返回结果,例如:
    • eval("1+1")=2 ;
    • eval("1<2")=true

2.8 类型查询函数(typeof) 

  • ECMAScript 提供了 typeof 运算符来判断一个值是否在某种类型的范围内,(string / number / boolean / object )。
  • 可以用这种运算符判断一个值是否表示一种原始类型:如果它是原始类型,还可以判断它表示哪种原始类型。 
  • 例如:
    • typeof("test"+3)   // "string";
    • typeof(null)  // "object ";
    • typeof(true+1)  // "number";
    • typeof(true-false)  // "number"

2.9 ECMAScript 运算符 

(1)ECMAScript 算数运算符
  • 加(+)、 减(-)、 乘(*) 、除(/) 、余数(% )  加、减、乘、除、余数和数学中的运算方法一样  例如:9/2=4.5,4*5=20,9%2=1

  • -除了可以表示减号还可以表示负号  例如:x=-y

  • +除了可以表示加法运算还可以用于字符串的连接  例如:"abc"+"def"="abcdef"

  • 递增(++) 、递减(--):

    • 假如x=2,那么x++表达式执行后的值为3,x--表达式执行后的值为1

    • i++相当于i=i+1,i--相当于i=i-1

    • 递增和递减运算符可以放在变量前也可以放在变量后:

      • i++,++在后,先取后加,即先把i本来的值作为表达式的值,i的值再自增1,如i=1, i++的表达式值=1,计算后i=2;

      • ++i,++在前,先加后取,即i先自增1,再作为表达式的值,如上文的i,++i的表达式值=3,计算后i=3;

      • i--,--在后,先取后减,即先把i本来的值作为表达式的值,i的值再自减1,如上文的i,i--的表达式值=3,计算后i=2;

      • --i,--在前,先减后取,即i先自减1,再作为表达式的值,如上文的i, --i的表达式值=1计算后i=1

  • 一元加减法:
    • -a:负号,把a变成负值;
    • +a:对a做类型转换;
    • a="yuan";a=+a;alert(a);  // 结果显示a的值为NaN,属于Number类型的一个特殊值,当遇到将字符串转成数字无效时,就会得到一个NaN数据
    • NaN特点: NaN参与的所有的运算都是false,除了!=是true外,如:
      • var n=NaN;
      • alert(n>3); // false
      • alert(n<3); // false
      • alert(n==3); // false
      • alert(n==NaN); // false
      • alert(n!=NaN); // true
(2)ECMAScript 逻辑运算符 

与 (&&) 、或(||) 、非(!):

  • 与(&&)运算符:全真即真
    • 运算数可以是任何类型的,不止是 Boolean 值。
    • 如果某个运算数不是原始的 Boolean 型值,&&运算并不一定返回 Boolean 值:
      • 如果某个运算数是null,返回 null;
      • 如果某个运算数是NaN,返回 NaN;
      • 如果某个运算数是undefined,返回undefined;
      • 如果一个运算数是对象,另一个是boolean值,返回该对象;(除了Boolean、null、NaN和undefined都是对象)
      • 如果两个运算数都是对象,返回第二个对象。
  • 或(||)运算符:全假即假,但与逻辑 AND 运算符相似,如果某个运算数不是 Boolean 值,逻辑或 运算并不一定返回 Boolean 值
  • 非(!)运算符:真即假,假即真
(3)ECMAScript位运算符 
  • 按位与&:二进制形式分别按照每一个位对应做与运算,都是1得1,否则得0,如:
    1&2=0
    0001
    0010
    ————
    0000
  • 按位或|:二进制形式分别按照每一个位对应做或运算,都是0得0,否则得1,如:
    1|2=3
    0001
    0010
    ————
    0011
  • 按位异或^:二进制形式分别按照每一个位对应做异或运算,只要位不同结果为1,否则结果为0,如:
    1^2=3
    0001
    0010
    ————
    0011
  • 左移<<:二进制形式每个位数字左移多少位,后面补0,如:
    3<<2=12
    0011
    ————
    1100
  • 右移>>:二进制形式每个位数字右移多少位,前面补0,如:
    12>>1=6
    1100
    ————
    0110
  • 取反(NOT)~:二进制形式每个位数字1变成0,0变成1,如;
    ~6=9
    0110
    ————
    1001 
(4)ECMAScript 赋值运算符 

赋值运算符=:JavaScript中一个等号=代表赋值,两个等号==表示判断是否相等(与c、c++、java、python中类似)

  • 配合其他运算符形成的简化表达式,例如:i+=1相当于i=i+1,x&=y相当于x=x&y 
(5)ECMAScript等性运算符 
  • 执行类型转换的规则如下:
    • 如果一个运算数是 Boolean 值,在检查相等性之前,把它转换成数字值。false 转换成 0,true 为 1。
    • 如果一个运算数是字符串,另一个是数字,在检查相等性之前,要尝试把字符串转换成数字。 
    • 如果一个运算数是对象,另一个是字符串,在检查相等性之前,要尝试把对象转换成字符串。 
    • 如果一个运算数是对象,另一个是数字,在检查相等性之前,要尝试把对象转换成数字。 
  • 在比较时,该运算符还遵守下列规则:
    • 值 null 和 undefined 相等。 
    • 在检查相等性时,不能把 null 和 undefined 转换成其他值。 
    • 如果某个运算数是 NaN,等号将返回 false,非等号将返回 true。 
    • 如果两个运算数都是对象,那么比较的是它们的引用值。
    • 如果两个运算数指向同一对象,那么等号返回 true,否则两个运算数不等。
(6)ECMAScript 关系运算符(重要) 

等于 ( == )  、全等(===)、不等于( != ) 、不全等(!==)、 大于( > ) 、 小于( < ) 大于等于(>=) 、小于等于(<=),比较规则如下:

  • 比较运算符两侧如果一个是数字类型,一个是其他类型,会将其类型转换成数字类型,转换失败就是NaN
  • 比较运算符两侧如果都是字符串类型,比较的是最高位的ascII码,如果最高位相等,继续取第二位比较. 
  • 全等(===)和不全等(!==)不会做类型转换,相当于其他语言如python的==和!=
(7)Boolean运算符(重要) 

经常用于条件判断、控制流语句(如if语句)以及逻辑运算中,以帮助程序根据条件执行不同的代码块,包括:

  • 逻辑运算符与(&&)、或(||)、非(!)
  • 空值合并运算符(??(ES2020引入):
    • 当左侧的操作数为nullundefined时,返回右侧的操作数;
    • 否则,返回左侧的操作数。 
  • 可选链运算符(?.)(ES2020引入):
    • 用于安全地访问对象的深层属性;
    • 当访问的属性不存在时,不会抛出错误,而是返回undefined

注:if的条件语句中[];0; null; undefined;object(new Object()创建的对象);都会判断为false

var temp=new Object();// false;[];0; null; undefined;object(new Object();)
if(temp){
    console.log("yuan")
}else {
    console.log("alex")
}
// 不论temp值是多少,只根据false和true判断走哪个分支语句

let x = null;
let y = "default";
console.log(x ?? y); // "default"

let z = 0;
console.log(z ?? y); // 0,因为0不是null或undefined

let user = { name: "John", address: { city: "New York" } };
console.log(user?.address?.city); // "New York"
console.log(user?.profile?.age);  // undefined,因为profile不存在

 2.10 控制语句

(1)if条件控制语句 

格式类似c语言的if:
if (表达式1){
    语句块1;
}else if (表达式2){
    语句块2;
}else{
    语句块3;
}   // 表达式的值为true则执行相应的{}里的语句块,if 可以单独使用

var x= (new Date()).getDay();
//获取今天的星期值,0为星期天
var y;

if ( (x==6) || (x==0) ) {
y="周末";
}else{
y="工作日";
}

alert(y);

//等价于

y="工作日";
if ( (x==6) || (x==0) ) {
y="周末";
}
(2)switch选择控制语句

格式如下:(类似c语言中的switch语句,python中没有switch语句)
switch (表达式) {
    case 值1:语句1;break;
    case 值2:语句2;break;
    case 值3:语句3;break;
    default:语句4;
}  // 因为只判断一个条件,执行一个表达式,将表达式的值与每个case的值比较,进而选择从哪一个case的语句块开始执行(break跳出),效率比if-else多分支结构更高,同时结构更加简洁清晰,使程序可读性更强,但只能对基本类型进行数值比较,而if 语句适用范围比较广,只要是 boolean 表达式都可以用 if 判断

 (3)for循环控制语句
  • 格式如下:(类似c语言的for循环语句,与python的for循环不一样)
    for (初始化;条件;增量){
        语句块;
    }
  • 功能说明:实现条件循环,当条件成立时,执行语句块,否则跳出循环体 
  • (初始化;条件;增量) 也可以写成(var i in arr),arr是数组,i得到的是索引下标,但这种方式渲染html时有bug,不推荐使用:循环的是你获取的一个DOM元素集,for in用来循环对象的所有属性,dom元素集包含了你上面输出的属性。
for (var i=1;i<=7;i++){
    document.write("<H"+i+">hello</H "+i+"> ");
    document.write("<br>");
}
----------------------------------------------
var arr=[1,"hello",true]//var dic={"1":"111"}
for (var i in arr){
    console.log(i)
    console.log(arr[i])
}
----------------------------------------------
doms=document.getElementsByTagName("p");

for (var i in doms){
    console.log(i); // 0 1 2 length item namedItem
    //console.log(doms[i])
}

//循环的是你获取的一个DOM元素集,for in用来循环对象的所有属性,dom元素集包含了你上面输出的属性。
//如果你只要循环dom对象的话,可以用for循环:

for (var i=0;i<doms.length;i++){
    console.log(i) ; // 0 1 2
    //console.log(doms[i])
    }
(4)while循环控制语句 

格式如下:
while (条件){
语句1;
...
}  // 功能说明:运行功能和for类似,当条件成立循环执行语句花括号{}内的语句,否则跳出循环 

2.11 异常处理 

  • 格式如下:
    try {
        //这段代码从上往下运行,其中任何一个语句抛出异常该代码块就结束运行
    }
    catch (e) {
        // 如果try代码块中抛出了异常,catch代码块中的代码就会被执行。
        //e是一个局部变量,用来指向Error对象或者其他抛出的对象
    }
    finally {
         //无论try中代码是否有异常抛出(甚至是try代码块中有return语句),finally代码块中始终会被执行。
    }
  • 注:主动抛出异常 throw Error('xxxx') 

2.12 ECMAScript类

  • 从ECMAScript 2015(也称为ES6)开始,ECMAScript引入了类的概念。类是通过 class 关键字来定义的,并且支持继承。这是JavaScript语言的一个重要更新,使得面向对象编程更加直观和方便。
  • 现代浏览器如Chrome、Firefox、Safari和Edge都已经广泛支持ES6的新特性。IE7到IE11等旧版浏览器则基本不支持ES6。要查看浏览器对ES6特性的具体支持情况,可以参考兼容性表,如Kangax的ECMAScript 6 Compatibility Table。

  • 此外,Node.js也逐步增加了对ES6特性的支持,从较新的版本开始,许多ES6特性已经可以在Node.js环境中直接使用。

  • 对于不支持ES6的环境,开发者可以使用Babel等转译工具将ES6代码转换为向后兼容的JavaScript代码。

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Dog extends Animal {
  speak() {
    console.log(`${this.name} barks.`);
  }
}

let dog = new Dog('Buddy');
dog.speak(); // 输出: Buddy barks.

/*例子中,定义了一个基类 Animal 和一个继承自 Animal 的子类 Dog。
每个类都有一个构造函数(constructor),用于初始化对象的状态。
Dog 类中还重写了Animal的speak 方法,以提供特定于狗的行为。

ECMAScript的类是基于原型的,这意味着它们实际上是函数的语法糖。
每个类都有一个与之关联的原型对象,该对象包含类的所有方法。
当你创建类的实例时,该实例实际上是从类的原型对象上继承而来的。

尽管ECMAScript的类提供了类似于传统面向对象编程语言的语法和特性,
但它们仍然是基于JavaScript的原型继承机制实现的。
这意味着你可以使用所有与原型相关的特性和操作
(如 Object.create() 和 instanceof 运算符)与类一起工作。*/
(1)定义类
  • 使用class关键字(ES6引入)定义类,作为面向对象编程(OOP)在JavaScript中的一个更直观和易于理解的实现 
  • 构造函数(Constructor)‌:
    • 一个特殊的方法,用于在创建类的实例时初始化对象的属性,类似python类的__init__方法。
    • 构造函数使用 constructor 关键字定义,并且会在你使用 new 关键字创建类的实例时自动调用。
  • 属性(Properties)‌:
    • 类的属性通常是在构造函数中定义的;
    • 也可以在类体内部直接定义;
    • 属性可以是任何JavaScript数据类型,包括原始值、对象、数组、函数等。
  • 方法(Methods)‌:
    • 在类体内部定义的函数;
    • 可以访问和修改类的属性,并提供类的行为。
  • 静态方法(Static Methods)‌:
    • 静态方法是属于类本身的,而不是属于类的实例的;
    • 它们使用 static 关键字定义;
    • 可以通过类名直接调用,而不是通过类的实例。
  • getter 和 setter‌:
    • 控制对类属性的访问和修改。
    • getter 方法让你能够定义一个方法来获取一个属性的值;
    • setter 方法让你能够定义一个方法来设置一个属性的值。
  • 计算属性名(Computed Property Names)‌:在类体内部,可以使用计算属性名来动态地定义属性。
class Person {
  // 构造函数
  constructor(name, age) {
    this.name = name; // 定义name属性
    this.age = age;   // 定义age属性
  }

  // 方法
  sayHello() {
    console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
  }

  // 静态方法
  static greet() {
    console.log("Hello from the Person class!");
  }

  // getter
  get ageInDogYears() {
    return this.age * 7;
  }

  // setter
  set age(newAge) {
    if (newAge > 0) {
      this._age = newAge; // 通常,我们会在内部使用一个不同的属性名来存储实际的值
    } else {
      console.log("Age must be positive!");
    }
  }

  // 计算属性名(这里只是作为示例,通常不会在构造函数之外使用)
  ‌:ml-search[`ageIn${this.unit}`] {
    return this.age * (this.unit === 'dogYears' ? 7 : 1);
  }
}

// 创建类的实例
let john = new Person("John", 30);

// 调用实例的方法
john.sayHello(); // 输出: Hello, my name is John and I am 30 years old.

// 访问getter
console.log(john.ageInDogYears); // 输出: 210

// 调用静态方法
Person.greet(); // 输出: Hello from the Person class!

// 使用setter设置属性
john.age = 31;
console.log(john.age); // 输出: 31 (注意:这里的输出是基于我们假设setter正确设置了_age属性)

// 尝试设置一个无效的年龄
john.age = -5; // 输出: Age must be positive!

/*例子中,Person 类有一个构造函数,
它接受 name 和 age 参数,并将它们分别赋值给实例的 name 和 age 属性。
类还有一个 sayHello 方法,用于输出一个问候语。
greet 是一个静态方法,它可以直接通过类名调用。
ageInDogYears 是一个 getter,它计算并返回人的年龄相当于狗的年龄(假设狗的年龄是人的年龄的7倍)。
age 的 setter 方法允许我们设置人的年龄,但会检查年龄是否为正数。
最后展示了如何使用计算属性名来定义一个动态的方法,
尽管在这个特定的例子中,它并不是很有用。*/
(2)实例化
// 创建类的实例
let john = new Person("John", 30);

2.13 ECMAScript对象 

  • ES6之前ECMAScript 并不真正具有类,ECMAScript 定义了“对象定义”,逻辑上等价于其他程序设计语言中的类。 
  • 对象(Object)是一种无序的集合,由键值对(key-value pairs)组成,用于存储和组织数据。
  • 键(key)通常是字符串,但也可以是符号(Symbol),而值(value)则可以是任何JavaScript数据类型,包括原始值(如数字、字符串、布尔值)、对象、数组、函数等。
  • 由ECMAScript定义的本地对象.独立于宿主环境的 ECMAScript 实现提供的对象.(native object)
  • ECMAScript 实现提供的、独立于宿主环境的所有对象,在 ECMAScript 程序开始执行时出现.这意味着开发者不必明确实例化内置对象,它已被实例化了。ECMA-262 只定义了两个内置对象,即 Global 和 Math (它们也是本地对象,根据定义,每个内置对象都是本地对象)。(built-in object)
  • 所有非本地对象都是宿主对象(host object),即由 ECMAScript 实现的宿主环境提供的对象。所有 BOM 和 DOM 对象都是宿主对象。
     
(1)创建对象 
  • ES6之前,传统的创建对象的方法查看上面2.4(5)节
  • ES6引入了类(class)语法,通过类实例化得到对象,提供了更清晰的面向对象编程风格
(2)访问和设置属性‌ 
  • 使用点符号:objectName.propertyName
  • 使用方括号语法:objectName["propertyName"],这在属性名是一个变量或包含特殊字符时特别有用。
(3)删除属性 

使用delete操作符,如:delete objectName.propertyName

(4)遍历对象 
  • 使用for...in循环来遍历对象原型链上的所有可枚举属性。
  • 使用Object.keys(obj)来获取对象自身的所有可枚举属性名,并使用循环来遍历它们。
  • 使用Object.values(obj) 返回一个包含给定对象自身所有可枚举属性值的数组。
  • 使用Object.entries(obj)来获取对象自身的所有可枚举属性的键值对数组,并使用循环来遍历它们。
    const obj = { name: 'Alice', age: 25, city: 'New York' };
    
    const keys = Object.keys(obj);
    console.log(keys); // 输出: ['name', 'age', 'city']
    
    const values = Object.values(obj);
    console.log(values); // 输出: ['Alice', 25, 'New York']
    
    const entries = Object.entries(obj);
    console.log(entries); // 输出: [['name', 'Alice'], ['age', 25], ['city', 'New York']]
    
    entries.forEach(([key, value]) => {
      console.log(`${key}: ${value}`);
    });
    // 输出:
    // name: Alice
    // age: 25
    // city: New York

(5)对象方法 

对象可以包含方法(即作为对象属性的函数),这些方法可以访问和修改对象的属性 

(6)this关键字 

在对象的方法内部,this关键字引用该方法所属的对象 

(7)对象的内置方法 

JavaScript提供了一些内置的对象方法,如Object.create()Object.defineProperty()Object.freeze()等,用于创建对象、定义属性、冻结对象等 

(8)示例 
// 创建一个对象
let person = {
  name: "John",
  age: 30,
  greet: function() {
    console.log("Hello, my name is " + this.name);
  }
};

// 访问对象的属性
console.log(person.name); // 输出 "John"
console.log(person["age"]); // 输出 30

// 调用对象的方法
person.greet(); // 输出 "Hello, my name is John"

// 设置对象的属性
person.age = 31;
console.log(person.age); // 输出 31

// 删除对象的属性
delete person.age;
console.log(person.age); // 输出 undefined,因为属性已经被删除

// 遍历对象的属性
for (let key in person) {
  console.log(key + ": " + person[key]);
}
// 输出:
// name: John
// greet: function () { ... }
/*
例子中,创建了一个名为person的对象,它包含name和age属性以及一个greet方法。
我们演示了如何访问和设置对象的属性,如何调用对象的方法,以及如何删除对象的属性。
最后,我们还展示了如何使用for...in循环来遍历对象的属性*/
 (9)高级用法

涵盖了多种技术和模式,更有效地利用对象的特性,提升代码的可读性、可维护性和重用性,常见高级用法如下:

  1. 对象字面量增强‌:

    • 在ES6及更高版本中,对象字面量得到了增强,支持属性名的简写、方法的简写以及计算属性名。
    • 例如,你可以直接在对象字面量中定义方法,而无需使用function关键字。
  2. 对象解构‌:

    • 解构赋值允许你从数组或对象中提取数据,并将其赋值给变量。
    • 对于对象,你可以使用花括号{}来解构,并指定要提取的属性名。
    • 你还可以使用默认值来处理不存在的属性。
  3. 对象的扩展运算符‌:

    • 扩展运算符...可以用于对象,以复制对象的属性到另一个对象中。
    • 这在合并对象、创建对象副本或向对象添加新属性时非常有用。
  4. 对象的保护‌:

    • Object.freeze()方法可以冻结一个对象,阻止修改其现有属性,阻止添加新属性,以及阻止删除已有属性。(数据属性变为不可写,访问器属性变为不可配置)
    • 冻结的对象在浅比较时是相等的,因为它们的内容不会改变。
    • Object.seal() 方法可以封闭一个对象,防止新属性的添加,但允许修改现有属性的值。
  5. 代理(Proxy)和反射(Reflect)‌:

    • 代理允许你创建一个对象的代理来定义其基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)。
    • 反射是一个内置的对象,它提供拦截JavaScript底层操作的方法。
    • 代理和反射通常一起使用,以实现高级的功能,如数据绑定、数据验证等。
  6. 对象的封装和私有字段‌:

    • 在类(class)中,你可以使用私有字段(在字段名前加#)来封装数据,使其只能在类的内部访问。
    • 这有助于隐藏实现细节,并提供一个更清晰的公共API。
  7. 混合(Mixins)‌:

    • 混合是一种将多个对象的行为合并到一个对象中的技术。
    • 它允许你重用代码,通过组合而不是继承来实现对象的多样化行为。
  8. 对象的迭代器‌:</


http://www.kler.cn/a/528530.html

相关文章:

  • 前端知识速记—JS篇:null 与 undefined
  • 理解动手学深度学习的自编包d2l
  • Debian 10 中 Linux 4.19 内核在 x86_64 架构上对中断嵌套的支持情况
  • 基于PLC的变频调速系统设计
  • Longformer:处理长文档的Transformer模型
  • jmap命令详解
  • 扬帆启航于数据结构算法之雅舟旅程,悠然漫步于C++秘境——探索线性表之栈的绮丽定义与精妙实现
  • 10.[前端开发-CSS]Day10-CSS的浮动和flex布局
  • 【LeetCode: 81. 搜索旋转排序数组 II + 二分查找】
  • 汽车中控屏HMI界面,安全和便捷是设计的两大准则。
  • 调音基础学习
  • 【LLM-agent】(task3)数据库对话Agent和RAG接入Agent
  • 【数据结构-前缀树】力扣208. 实现 Trie (前缀树)
  • Baklib揭示内容中台实施最佳实践的策略与实战经验
  • 好用的翻译工具
  • 基于VMware的ubuntu与vscode建立ssh连接
  • java练习(1)
  • 网络编程套接字(中)
  • 力扣动态规划-17【算法学习day.111】
  • 深入解析“legit”的地道用法——从俚语到正式表达:Sam Altman用来形容DeepSeek: legit invigorating(真的令人振奋)
  • 计算机网络之物理层通信基础(编码与调制)
  • java练习(2)
  • 初识ArkTS语言
  • Java小白入门教程:泛型,泛型类型参数<T> <K> <V> <E>(必须Get的知识)
  • WSL2中安装的ubuntu开启与关闭探讨
  • 使用Pygame制作“吃豆人”游戏