三、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 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进制的换算:
      # 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或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 可以单独使用

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!");}// 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)实例化
// 创建类的实例
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.rhkb.cn/news/11049.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript作用域详解

前言 作用域是JavaScript中一个重要的概念&#xff0c;它决定了变量和函数在代码中的可访问性和可见性。了解JavaScript的作用域对于编写高效、可维护的代码至关重要。本文将深入介绍JavaScript作用域相关的知识点&#xff0c;其中包括作用域类型&#xff0c;作用域链&#xff…

如何使用SliverList组件

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了沉浸式状态栏相关的内容&#xff0c;本章回中将介绍SliverList组件.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在这里介绍的SliverList组件是一种列表类组件&#xff0c;类似我们之前介…

vsnprintf() 将可变参数格式化输出到字符数组

vsnprintf{} 将可变参数格式化输出到一个字符数组 1. function vsnprintf()1.1. const int num_bytes vsnprintf(NULL, 0, format, arg); 2. Parameters3. Return value4. Example5. llama.cppReferences 1. function vsnprintf() https://cplusplus.com/reference/cstdio/vs…

一文大白话讲清楚webpack基本使用——17——Tree Shaking

文章目录 一文大白话讲清楚webpack基本使用——17——Tree Shaking1. 建议按文章顺序从头看&#xff0c;一看到底&#xff0c;豁然开朗2. 啥叫Tree Shaking3. 什么是死代码&#xff0c;怎么来的3. Tree Shaking的流程3.1 标记3.2 利用Terser摇起来 4. 具体使用方式4.1 适用前提…

仿真设计|基于51单片机的温湿度、一氧化碳、甲醛检测报警系统

目录 具体实现功能 设计介绍 51单片机简介 资料内容 仿真实现&#xff08;protues8.7&#xff09; 程序&#xff08;Keil5&#xff09; 全部内容 资料获取 具体实现功能 &#xff08;1&#xff09;温湿度传感器、CO传感器、甲醛传感器实时检测温湿度值、CO值和甲醛值进…

几种K8s运维管理平台对比说明

目录 深入体验**结论**对比分析表格**1. 功能对比****2. 用户界面****3. 多租户支持****4. DevOps支持** 细对比分析1. **Kuboard**2. **xkube**3. **KubeSphere**4. **Dashboard****对比总结** 深入体验 KuboardxkubeKubeSphereDashboard 结论 如果您需要一个功能全面且适合…

GenAI 在金融服务领域的应用:2025 年的重点是什么

作者&#xff1a;来自 Elastic Karen Mcdermott GenAI 不是魔法 我最近参加了 ElasticON&#xff0c;我们与纽约 Elastic 社区一起度过了一天&#xff0c;讨论了使用检索增强生成 (retrieval augmented generation - RAG) 为大型语言模型 (large language models - LLMs) 提供…

如何对系统调用进行扩展?

扩展系统调用是操作系统开发中的一个重要任务。系统调用是用户程序与操作系统内核之间的接口,允许用户程序执行内核级操作(如文件操作、进程管理、内存管理等)。扩展系统调用通常包括以下几个步骤: 一、定义新系统调用 扩展系统调用首先需要定义新的系统调用的功能。系统…

LightM-UNet(2024 CVPR)

论文标题LightM-UNet: Mamba Assists in Lightweight UNet for Medical Image Segmentation论文作者Weibin Liao, Yinghao Zhu, Xinyuan Wang, Chengwei Pan, Yasha Wang and Liantao Ma发表日期2024年01月01日GB引用> Weibin Liao, Yinghao Zhu, Xinyuan Wang, et al. Ligh…

Cubemx文件系统挂载多设备

cubumx版本&#xff1a;6.13.0 芯片&#xff1a;STM32F407VET6 在上一篇文章中介绍了Cubemx的FATFS和SD卡的配置&#xff0c;由于SD卡使用的是SDIO通讯&#xff0c;因此具体驱动不需要自己实现&#xff0c;Cubemx中就可以直接配置然后生成SDIO的驱动&#xff0c;并将SD卡驱动和…

电子电气架构 --- 汽车电子拓扑架构的演进过程

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 简单&#xff0c;单纯&#xff0c;喜欢独处&#xff0c;独来独往&#xff0c;不易合同频过着接地气的生活…

2025 年,链上固定收益领域迈向新时代

“基于期限的债券市场崛起与Secured Finance的坚定承诺” 2025年&#xff0c;传统资产——尤其是股票和债券——大规模涌入区块链的浪潮将创造历史。BlackRock 首席执行官 Larry Fink 近期在彭博直播中表示&#xff0c;代币化股票和债券将逐步融入链上生态&#xff0c;将进一步…

数据密码解锁之DeepSeek 和其他 AI 大模型对比的神秘面纱

本篇将揭露DeepSeek 和其他 AI 大模型差异所在。 目录 ​编辑 一本篇背景&#xff1a; 二性能对比&#xff1a; 2.1训练效率&#xff1a; 2.2推理速度&#xff1a; 三语言理解与生成能力对比&#xff1a; 3.1语言理解&#xff1a; 3.2语言生成&#xff1a; 四本篇小结…

Ollama部署指南

什么是Ollama&#xff1f; Ollama是一个专为在本地机器上便捷部署和运行大型语言模型&#xff08;LLM&#xff09;而设计的开源工具。 如何部署Ollama&#xff1f; 我是使用的云平台&#xff0c;大家也可以根据自己的云平台的特点进行适当的调整。 使用系统&#xff1a;ubun…

群晖Alist套件无法挂载到群晖webdav,报错【连接被服务器拒绝】

声明&#xff1a;我不是用docker安装的 在套件中心安装矿神的Alist套件后&#xff0c;想把夸克挂载到群晖上&#xff0c;方便复制文件的&#xff0c;哪知道一直报错&#xff0c;最后发现问题出在两个地方&#xff1a; 1&#xff09;挂载的路径中&#xff0c;直接填 dav &…

Kubernetes组成及常用命令

Pods(k8s最小操作单元)ReplicaSet & Label(k8s副本集和标签)Deployments(声明式配置)Services(服务)k8s常用命令Kubernetes(简称K8s)是一个开源的容器编排系统,用于自动化应用程序的部署、扩展和管理。自2014年发布以来,K8s迅速成为容器编排领域的行业标准,被…

hexo部署到github page时,hexo d后page里面绑定的个人域名消失的问题

Hexo 部署博客到 GitHub page 后&#xff0c;可以在 setting 中的 page 中绑定自己的域名&#xff0c;但是我发现更新博客后绑定的域名消失&#xff0c;恢复原始的 githubio 的域名。 后面搜索发现需要在 repo 里面添加 CNAME 文件&#xff0c;内容为 page 里面绑定的域名&…

vim的特殊模式-可视化模式

可视化模式&#xff1a;按 v进入可视化模式 选中 y复制 d剪切/删除 可视化块模式: ctrlv 选中 y复制 d剪切/删除 示例&#xff1a; &#xff08;vim可视化模式的进阶使用&#xff1a;vim可视化模式的进阶操作-CSDN博客&#xff09;

【教程】在CMT上注册账号并声明Conflicts

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 注册账号 声明冲突 账号验证 每位作者都要注册并声明冲突&#xff0c;不然会直接拒稿&#xff01; 注册账号 https://cmt3.research.microsoft…

拉格朗日定理

根号n为枚举的条件 d从c开始循环&#xff08;防止重复计算平方和&#xff09; #include<bits/stdc.h> using namespace std; using lllong long; const int N5e69;int n; int C[N],D[N];int main() {cin>>n;memset(C,-1,sizeof C);for(int c0;c*c<n;c)for(int d…