三、js笔记

server/2025/2/2 21:13:21/

(一)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 嵌入式 

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

 1.2 导入式(推荐)

javascript"><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 循环),每次迭代都会为该变量创建一个新的绑定。这意味着循环体内的每个变量都是独立的,并且具有自己的值。
      javascript">/*例子:let 如何提供块作用域,并且如何在不同的块中独立地声明和使用变量。*/
      {let x = 10;console.log(x); // 输出 10
      }
      console.log(x); // ReferenceError: x is not definedlet y = 20;
      {let y = 30; // 这是一个新的块作用域内的 yconsole.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进制的换算:
      javascript"># 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的控制语句,例如:
    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编程中的核心概念之一,广泛用于存储和管理复杂的数据。
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)创建对象:对象字面量

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

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

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

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

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

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

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

javascript">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及更高版本中推荐的方式,因为它提供了更清晰和更结构化的方式来定义对象和其行为。

javascript">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 关键字就能创建对象的方法,通常返回一个包含所需属性和方法的普通对象。 

javascript">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

javascript">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或undefinedlet 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 可以单独使用

javascript">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元素集包含了你上面输出的属性。
javascript">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代码。

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)‌:在类体内部,可以使用计算属性名来动态地定义属性。
javascript">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!");}// getterget ageInDogYears() {return this.age * 7;}// setterset 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)实例化
javascript">// 创建类的实例
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)来获取对象自身的所有可枚举属性的键值对数组,并使用循环来遍历它们。
    javascript">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)示例 
javascript">// 创建一个对象
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.ppmy.cn/server/164429.html

相关文章

rust如何操作oracle

首先鄙视甲骨文&#xff0c;这么多钱的公司&#xff0c;不做一个rust库&#xff0c;还要社区帮忙。有个开源的rust库&#xff0c;叫oracle&#xff0c;但是并不是甲骨文做的。 我们来看一个从oracle数据库取所有表和视图的示例: // 定义连接字符串let conn_str1 format!(&quo…

【Linux探索学习】第二十七弹——信号(一):Linux 信号基础详解

Linux学习笔记&#xff1a; https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言&#xff1a; 前面我们已经将进程通信部分讲完了&#xff0c;现在我们来讲一个进程部分也非常重要的知识点——信号&#xff0c;信号也是进程间通信的一…

Dest1ny漏洞库:用友 U8 Cloud ReleaseRepMngAction SQL 注入漏洞(CNVD-2024-33023)

大家好&#xff0c;今天是Dest1ny漏洞库的专题&#xff01;&#xff01; 会时不时发送新的漏洞资讯&#xff01;&#xff01; 大家多多关注&#xff0c;多多点赞&#xff01;&#xff01;&#xff01; 0x01 产品简介 用友U8 Cloud是用友推出的新一代云ERP&#xff0c;主要聚…

42步进电机

“42步进电机”通常是指安装法兰尺寸为 42mm x 42mm 的步进电机&#xff0c;符合 NEMA 17 标准。这种电机因其适中的尺寸和性能&#xff0c;广泛应用于各种中小型自动化设备中&#xff0c;如 3D 打印机、CNC 机床、机器人等。 以下是关于 42 步进电机的详细介绍&#xff1a; 一…

mysql.sock.lock 导致mysql重启失败

背景 今天公司物业断电&#xff0c;导致机房服务器停电宕机&#xff0c;所有的服务都得重启。本着mysql实例都做了服务自启动&#xff0c;所以没有太担心影响开发的日常工作。但是今天一上班开发就找来&#xff0c;各种服务都没起来有问题&#xff0c;数据库连不上。马上登陆数…

JAVA篇12 —— 泛型的使用

​ 欢迎来到我的主页&#xff1a;【Echo-Nie】 本篇文章收录于专栏【JAVA学习】 如果这篇文章对你有帮助&#xff0c;希望点赞收藏加关注啦~ 1 泛型介绍 先对集合进行说明&#xff0c;不能对加入到集合中的元素类型进行约束&#xff08;不安全&#xff09;。遍历的时候需要…

数据结构-Stack和栈

1.栈 1.1什么是栈 栈是一种特殊的线性表&#xff0c;只允许在固定的一段进行插入和删除操作&#xff0c;进行插入和删除操作的一段称为栈顶&#xff0c;另一端称为栈底。 栈中的数据元素遵顼后进先出LIFO&#xff08;Last In First Out&#xff09;的原则&#xff0c;就像一…

早期车主告诉后来者,很后悔买电车,一辈子都被车企拿捏了

从2015年开始大力发展电车&#xff0c;至今已有快10年了&#xff0c;头几批车主或是已换车&#xff0c;或是准备换车&#xff0c;他们用车这么多年的困扰以及换车的麻烦&#xff0c;却告诉准备买电车的消费者&#xff0c;电车没有媒体宣传的那么好&#xff0c;买了电车基本上一…