var 回顾
一、 let的特性
1.变量不能重复声明
2.块级作用域,全局,eval
3.不存在变量提升
4.不影响作用域链
{
let school = ‘小明’
function fn(){
console.log(shool);
}
使用场景:for循环计数
二、const关键字
- 一定要赋初始值
- 一般常量使用大写(潜规则)
- 常量的值不能修改
- 块级作用域
- 对于数组和对象的元素修改,不算做对常量的修改,不会报错,直接给数组,对象赋值一个常量,会报错
三、变量的解构赋值
1.数组的解构
const F4 = ['小沈阳','刘能','赵四’,‘宋小宝’]
let[xiao,liu,zhao,song] = F4
2.对象的解构
const zhao = {
name:'赵本山',
age:'不详',
xiaopin:function(){
console.log("我可以演小品");
}
};
//let{name,age,xiaopin} = zhao;
//console.log(name);
//console.log(age);
//需要同名
let{xiaopin} = zhao;
console.log(xiaopin);
xiaopin()
四、模板字符串
-
声明
let str = `我也是一个字符串哦` -
内容中可以直接出现换行符
var str = ` <ul>
<li>沈腾</li>
<li>玛丽</li>
<li>魏翔</li>
<li>艾伦</li>
</ul>
`
3.变量拼接
let loverst = '魏翔’
let out = ` &{lovest}是我心目中最搞笑的演员`
五、简化对象写法
// ES6允许在大括号里面,里面直接写入变量和函数,作为对象的属性和方法。这样的书写更加简介
let name = '尚硅谷'
let change = function(){
console.log('我们可以改变你!!');
const school = {
name,
change,
//原先函数赋值方法
improve: function()
{
console.log('我们可以提高你的技能')
}
//es6新增
improve(){
console.log("我们可以提高你的技能")
}
六、箭头函数
- ES6允许使用箭头定义函数
//声明一个函数
let fn = function(){
}
//使用箭头函数声明
let fn = ( a,b)=>{
return a +b;}
fn(1,2)
- this 是静态的。this始终指向函数声明时所在作用域下的this的值。
// 普通函数的this指向window
function getName() {
console.log(this.name);
}
// 全局作用域下,声明的箭头函数的this指向window
let getName2 = () => {
console.log(this.name);
}
window.name = '尚硅谷';
const school = {
name: "ATGUIGU"
}
getName();//输出尚硅谷
getName2();//输出尚硅谷
getName.call(school)//输出ATGUIGU
getName2.call(school)//输出尚硅谷
- 不能作为构造实例化对象
let person = (name, age) => {
this.name = name;
this.age = age;
}
let me = new Person('xiao', 30)
console.log(me);
//则会报错 Person is not defined
4.不能使用arguments变量
let fn = (a, b, c) => {
console.log(arguments);
}
fn(1, 2, 3)
//会出现 arguments is not defined 错误
- 箭头函数的简写
//1)省略小括号,当形参有且只有一个的时候
let add = (n) =>{
return n+n;
}
console.log(add(9));
//省略小括号
let add = n =>{
return n+n;
}
console.log(add(9));
//省略花括号
let add = n =>{
return n+n;
}
console.log(add(9));
// 省略花括号,当代码体只有一条语句的时候,此时return 必须省略,而且语句的执行结果就是函数的返回值
//省略小括号
let add = n => {
return n + n;
}
//省略花括号
let pow = (n) => n * n;
console.log(pow(8))
//都省略
let pow = n => n * n;
console.log(pow(8))
5.箭头函数的应用场景
一、定时器
let ad = document.getElementById('ad');
ad.addEventListener("click", function() {
setTimeout(() => {
this.style.background = 'pink';
})
})
二、数组的方法回调
const arr = [1, 6, 9, 100, 25];
const result = arr.filter(item => item % 2 === 0)
console.log(result)
箭头函数适合与this无关的回调:定时器,数组的方法回调 箭头函数不适合与this有关的回调:事件回调,对象的方法
{
name:'',
getName:()=>{
this.name;
}
}
七、参数默认值
//ES6 允许给函数参数赋值初始值
//1. 形参初始值 具有默认值的参数,一般位置要靠后(潜规则)
function add(a, c = 10, b) {
return a + b + c;
}
let result = add(1, 2);
console.log(result);
//与解构赋值结合
function connect({
host = "127.0.0.1",
username,
password,
port
}) {
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connect({
host: 'a',
username: 'root',
password: 'root',
port: 3306
})
rest (剩余参数)
作用与 arguments 类似
function add(...args)
{
console.log(args);
}
add(1,2,3,4,5);
/** * rest 参数必须是最后一个形参 */
function minus(a,b,...args)
{
console.log(a,b,args);
}
minus(100,1,2,3,4,5,19);
rest 参数非常适合不定个数参数函数的场景
spread 扩展运算符
扩展运算符(spread)也是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包
let tfboys = ['德玛西亚之力','德玛西亚之翼','德玛西亚皇子'];
function fn()
{
console.log(arguments);
}
fn(...tfboys)
扩运算符的应用
1.数组的合并
const kuaizi = ['苹果','橘子']
const sucai =['萝卜','地瓜']
//第一种方式
//const hebing = kuaizi.concat(sucai)
//第二种方式
const hebing = [...kuaizi,...sucai]
console.log(hebing) //输出['苹果','橘子','萝卜','地瓜']
2.数组的克隆
const sanzhihua = ['E','G','M']
const sanyecao = [...sanzhihua]
console.log(sanyecao) //输出 'E','G','M'
3.将伪数组转为真正的数组
const divs = document.querySelectorAll('div');
console.log(divs)// object
const divArr = [...divs];
symbol
浅析对象访问属性的"."和"[]"方法区别
在JavaScript中通常使用”."运算符来存取对象的属性的值。或者使用[]作为一个关联数组来存取对象的属性。但是这两种方式有什么区别了?
例如,读取object中的property属性值:
object.property
object['property']
以上两种方式都可以实现属性的存取。
1.语法方面的区别
点表示法的对象的属性名是标识符,而后者的属性名则是一个字符串。
2.灵活性方面的区别
在JavaScript编写程序中,可以为对象创建任意数目的属性。但使用”.“运算符来存取一个对象的属性时,属性名是用标识符表示的。而在JavaScript程序中,标识符必须被逐字地输入,它们不是一种数据类型,因此程序不能对其操作。也就是说,标识符是静态的,在程序中必须对其进行硬编码。
而使用数组[]表示法来存取一个对象的属性时,属性名是用字符串表示的。字符串是JavaScript的一种数据类型,因此可以在程序运行中操作并创建它们。
3.性能方面区别
数组[]表示法在存取属性值时会进行表达式运行。而点表示法是直接存取属性值,理论上执行效率会比数组表示法高。性能方面其实可以忽略。
某些场景必须用到数组表示法来动态存取属性值,这个是点表示法无法做到的。
总的来说,这两种方法区别上不大,都有对应的使用场景。点表示法一般作为静态对象使用时来存取属性。而数组表示法在动态存取属性时就非常有用。
迭代器
概述
一、是为各种数据结构,提供一个统一的、简便的访问接口;
二、是使得数据结构的成员能够按某种次序排列;
三、是 ES6 创造了一种新的遍历命令for...of循环,Iterator 接口主要供for...of消费。
特点
ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费;原生具备 iterator 接口的数据(可用 for of 遍历):
Array;
Arguments;
Set;
Map;
String;
TypedArray;
NodeLis
原理
-
创建一个指针对象,指向当前数据结构的起始位置;
-
第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员;
-
接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员;
-
每调用 next 方法返回一个包含 value 和 done 属性的对象
** 需要自定义遍历数据的时候,要想到迭代器;**
// 声明一个数组
const xiyou = ['唐僧', '孙悟空', '猪八戒', '沙僧'];
// 使用 for...of 遍历数组
for(let v of xiyou){
console.log(v);
}
et iterator = xiyou[Symbol.iterator]();
// 调用对象的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
// 重新初始化对象,指针也会重新回到最前面
let iterator1 = xiyou[Symbol.iterator]();
console.log(iterator1.next());
同步编程和异步编程
同步编程
简单描述: 一个线程获得了一个任务,然后去执行这个任务, 当这个任务执行完毕后,才能执行接下来的另外一个任务。
注意: 这个线程不能将当前的任务放置在一边,转而去做另外一个任务。
一个线程,相当于一个人,这个人做完一个任务,再去做下一个任务。
这个人有两个任务,第一个是吃水果,第二个是写文章。
那么这个人是先去吃一堆水果,然后再去写文章。
异步编程
它和同步的编程模型有很大的区别:
一个线程中执行一堆任务,
这个线程可以自由的保存,恢复任务的状态。
也就是,它有能力穿插的执行任务。
一个线程,相当于一个人,这个人交替的做任务。
这个人有两个任务,第一个是吃水果,第二个是写文章。
那么这个人是先去吃两个水果,然后再去写文章,过一会再去吃水果,然后再来写文章。 原文链接: 同步编程 vs 异步编程 - 简书 (jianshu.com)
异步解决方案
使用场景: ajax请求, 事件回调, nodeAPI, 定时器
异步编程解决方案有: 生成器,promise, async 和 await
关于事件循环机制的解释: (19条消息) js 事件循环执行顺序(setTimeout,async,promise多层嵌套)_ZFZ5720-CSDN博客
生成器
其中生成器是一个特殊的函数,是异步编程的一种解决方案。
function getUsers() {
setTimeout(() => {
let data = "用户数据";
iterator.next(data);
}, 5000)
}
function getOrders() {
setTimeout(() => {
let data = "订单数据";
iterator.next(data); // 这里将data传入
}, 6000);
}
function getGoods() {
setTimeout(() => {
let data = "商品数据";
iterator.next(data); // 这里将data传入
}, 1000);
}
function* gen() {
let users = yield getUsers();
console.log(users);
let orders = yield getOrders();
console.log(orders);
let goods = yield getGoods();
console.log(goods);
}
let iterator = gen();
iterator.next();
//最后输出用户数据,订单数据,商品数据,其中iterator.next()第二次传入的值,被第一次yield接受
promise
Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果
Promise封装读取文件:
一般写法:
const fs = require("fs");
// 2、调用方法,读取文件
fs.readFile("resources/text.txt",(err,data)=>{
// 如果失败则抛出错误
if(err) throw err;
// 如果没有出错,则输出内容
console.log(data.toString());
});
Promise封装
// 1、引入 fs 模块
const fs = require("fs");
// 2、使用Promise封装
const p = new Promise(function(resolve,data){
fs.readFile("resources/text.txt",(err,data)=>{
// 判断如果失败
if(err) reject(err);
// 如果成功
resolve(data);
});
});
p.then(function(value){
console.log(value.toString());
},function(reason){
console.log(reason); // 读取失败
})
Promise封装Ajax请求:
原生请求:
// 请求地址:https://api.apiopen.top/getJoke
// 原生请求
// 1、创建对象
const xhr = new XMLHttpRequest();
// 2、初始化\
xhr.open("GET","https://api.apiopen.top/getJoke");
// 3、发送
xhr.send();
// 4、绑定事件,处理响应结果
xhr.onreadystatechange = function(){
// 判断状态
if(xhr.readyState == 4){
// 判断响应状态码 200-299
if(xhr.status>=200 && xhr.status<=299){
// 成功
console.log(xhr.response);
}else{
// 失败
console.error(xhr.status);
}
}
}
Promise封装Ajax请求:
const p = new Promise(function(resolve,reason){
// 原生请求
// 1、创建对象
const xhr = new XMLHttpRequest();
// 2、初始化
xhr.open("GET","https://api.apiopen.top/getJoke");
// 3、发送
xhr.send();
// 4、绑定事件,处理响应结果
xhr.onreadystatechange = function(){
// 判断状态
if(xhr.readyState == 4){
// 判断响应状态码 200-299
if(xhr.status>=200 && xhr.status<=299){
// 成功
resolve(xhr.response);
}else{
// 失败
reason(xhr.status);
}
}
}
});
p.then(function(value){
console.log(value.toString());
},function(reason){
console.log(reason); // 读取失败
})
Promise.prototype.then:
调用then方法,then 方法返回的是promise对象,对象状态由回调函数的执行结果决定。
1.如果回调函数中返回的结果是非promise类型的属性,状态为成功,返回值为对象的成功的值。
// 创建 Promise 对象
const p = new Promise((resolve,reject) => {
setTimeout(() => {
resolve("用户数据");
},1000);
});
// 调用then方法,then方法的返回结果是promise对象,
// 对象的状态有回调函数的结果决定;
const result = p.then(value => {
consolr.log(value)
},reason => {
console.error(reason);
})
// 链式调用
// then里面两个函数参数,可以只写一个
p.then(value=>{},reason=>{}).then(value=>{},reason=>{});
console.log(result);
promise 封装多个文件读取
“回调地狱”方式写法
// 1、引入 fs 模块
const fs = require("fs");
// 2、调用方法,读取文件
fs.readFile("resources/text.txt",(err,data1)=>{
fs.readFile("resources/test1.txt",(err,data2)=>{
fs.readFile("resources/test2.txt",(err,data3)=>{
let result = data1 + data2 + data3;
console.log(result);
});
});
});
Promise实现
// 1、引入 fs 模块
const fs = require("fs");
// 3、使用Promise实现
const p = new Promise((resolve,reject)=>{
fs.readFile("resources/text.txt",(err,data)=>{
resolve(data);
运行结果:
Promise对象catch方法:
代码示例及相关说明:
});
});
p.then(value=>{
return new Promise((resolve,reject)=>{
fs.readFile("resources/test1.txt",(err,data)=>{
resolve([value,data]);
});
})
}).then(value=>{
return new Promise((resolve,reject)=>{
fs.readFile("resources/test2.txt",(err,data)=>{
// 存入数组
value.push(data);
resolve(value);
});
})
}).then(value=>{
console.log(value.join("\r\n"));
})
Promise对象catch方法:
// Promise对象catch方法
const p = new Promise((resolve,reject)=>{
setTimeout(()=>{
// 设置p对象的状态为失败,并设置失败的值
reject("失败啦~!");
},1000);
})
// p.then(value=>{
// console.log(value);
// },reason=>{
// console.warn(reason);
// });
p.catch(reason=>{
console.warn(reason);
});
async 和await
概述
async 和 await 两种语法结合可以让异步代码看起来像同步代码一样;简化异步函数的写法
async 函数
概述
- async 函数的返回值为 promise 对象;
代码实现:
//返回普通数据,async依然返回的是promise对象
async function fn() {
return 123;
}
console.log(fn())
实现结果:
如果抛出一个错误,那么返回的primise对象的状态就是失败,promise对象的值就是失败的值
async function fn() {
throw new Error("出错了!")
}
console.log(fn())
- promise 对象的结果由 async 函数执行的返回值决定;
//成功
async function fn() {
return new Promise((resolve, reject) => {
resolve("成功啦!")
})
}
console.log(fn())
//失败
async function fn() {
return new Promise((resolve, reject) => {
reject("失败啦!");
})
}
console.log(fn())
完整代码
async function fn() {
return new Promise((resolve, reject) => {
// reject("失败啦!");
resolve("我想成功")
})
}
console.log(fn())
result = fn()
result.then(value => {
console.log(value);
}, reson => {
console.warn(reson)
})
结果
await
概述
- await 必须写在 async 函数中;
- await 右侧的表达式一般为 promise 对象;
- await 返回的是 promise 成功的值;
- await 的 promise 失败了, 就会抛出异常, 需要通过 try...catch 捕获处理;
代码实现
基本实现
const p = new Promise((resolve, reject) => {
resolve("成功啦!");
})
async function fn() {
let result = await p;
console.log(result)
}
fn()
async await实现多文件读取
const fs = new require("fs");
function readtext1() {
return new Promise((reslove, reject) => {
fs.readFile("text1.txt", (err, data) => {
if (err) reject(err);
reslove(data);
})
})
}
function readtext2() {
return new Promise((reslove, reject) => {
fs.readFile("text2.txt", (err, data) => {
if (err) reject(err);
reslove(data);
})
})
}
function readtext3() {
return new Promise((reslove, reject) => {
fs.readFile("text3.txt", (err, data) => {
if (err) reject(err);
reslove(data);
})
})
}
async function main() {
let result1 = await readtext1();
let result2 = await readtext2();
let result3 = await readtext3();
console.log(result1.toString());
console.log(result2.toString());
console.log(result3.toString());
}
main()
async await实现ajax封装
function sendAjax(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open("GET", url);
xhr.send();
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status <= 299) {
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
}
})
}
//传统写法
// const result = sendAjax("https://api.apiopen.top/getJoke");
// result.then(value => {
// console.log(value)
// }, reason => {
// console.warn(reason)
// })
//async,await 写法
async function main() {
let result = await sendAjax("https://api.apiopen.top/getJoke")
console.log(result)
}
main()
Javascript异步编程的4种方法
Javascript异步编程的4种方法 - 阮一峰的网络日志 (ruanyifeng.com)
set
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator接口,所以可以使用『扩展运算符』和『for…of…』进行遍历,集合的属性和方法。
- size 返回集合的元素个数;
- add 增加一个新元素,返回当前集合;
- delete 删除元素,返回 boolean 值;
- has 检测集合中是否包含某个元素,返回 boolean 值;
- clear 清空集合,返回 undefined;
let s = new Set();
console.log(s,typeof s);
let s1 = new Set(["大哥","二哥","三哥","四哥","三哥"]);
console.log(s1); // 自动去重
// 1. size 返回集合的元素个数;
console.log(s1.size);
// 2. add 增加一个新元素,返回当前集合;
s1.add("大姐");
console.log(s1);
// 3. delete 删除元素,返回 boolean 值;
let result = s1.delete("三哥");
console.log(result);
console.log(s1);
// 4. has 检测集合中是否包含某个元素,返回 boolean 值;
let r1 = s1.has("二姐");
console.log(r1);
// 5. clear 清空集合,返回 undefined;
s1.clear();
console.log(s1);
// Set集合实践
let arr = [1,2,3,4,5,4,3,2,1];
// 数组去重
let s1 = new Set(arr);
console.log(s1);
// 交集
let arr2 = [3,4,5,6,5,4,3];
// 看来我需要学学数组的一些方法
let result = [...new Set(arr)].filter(item=>new
Set(arr2).has(item));
console.log(result);
// 并集
// ... 为扩展运算符,将数组转化为逗号分隔的序列
let union = [...new Set([...arr,...arr2])];
console.log(union);
// 差集:比如集合1和集合2求差集,就是1里面有的,2里面没的
let result1 = [...new Set(arr)].filter(item=>!(new
Set(arr2).has(item)));
console.log(result1);
Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类 型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历;
// Map集合
// 创建一个空 map
let m = new Map();
// 创建一个非空 map
let m2 = new Map([
['name','尚硅谷'],
['slogon','不断提高行业标准']
]);
// 1. size 返回 Map 的元素个数;
console.log(m2.size);
// 2. set 增加一个新元素,返回当前 Map;
m.set("皇帝","大哥");
m.set("丞相","二哥");
console.log(m);
// 3. get 返回键名对象的键值;
console.log(m.get("皇帝"));
// 4. has 检测 Map 中是否包含某个元素,返回 boolean 值;
console.log(m.has("皇帝"));
// 5. clear 清空集合,返回 undefined;
m.clear();
console.log(m);
结果
class
概述
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已;
代码实现
// 手机 ES5写法
// function Phone(brand,price){
// this.brand = brand;
// this.price = price;
// }
// // 添加方法
// Phone.prototype.call = function(){
// console.log("我可以打电话!");
// }
// // 实例化对象
运行结果:
class静态成员:
代码实现:
// let HuaWei = new Phone("华为",5999);
// HuaWei.call();
// console.log(HuaWei);
// ES6写法
class Phone{
// 构造方法,名字是固定的
constructor(brand,price) {
this.brand = brand;
this.price = price;
}
//打电话,方法必须使用该方式写
call(){
console.log("我可以打电话!");
}
}
let HuaWei = new Phone("华为",5999);
HuaWei.call();
console.log(HuaWei);
class静态成员
// class静态成员
// ES5写法
// function Phone(){}
// Phone.name = "手机";
运行结果:
ES5构造函数实现继承:
代码实现:
// Phone.change = function(){
// console.log("我可以改变世界!");
// }
// let nokia = new Phone();
// console.log(nokia.name); // undefined
// // nokia.change();
// // 报错:Uncaught TypeError: nokia.change is not a function
// Phone.prototype.color = "黑色";
// console.log(nokia.color); // 黑色
// console.log(Phone.name);
// Phone.change();
// 注意:实例对象和函数对象的属性是不相通的
// ES6写法
class Phone{
// 静态属性
static name = "手机";
static change(){
console.log("我可以改变世界!");
}
}
let nokia = new Phone();
console.log(nokia.name);
console.log(Phone.name);
Phone.change();
运行结果 undefined 手机 我可以改变这个世界
es5构造函数实现继承
// ES5构造函数继承
// 手机
function Phone(brand,price){
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function(){
console.log("我可以打电话!");
}
/ 智能手机
function SmartPhone(brand,price,color,size){
Phone.call(this,brand,price);
this.color = color;
this.size = size;
}
/ 设置子级构造函数的原型
SmartPhone.prototype = new Phone;
SmartPhone.prototype.constructor = SmartPhone;
// 声明子类的方法
SmartPhone.prototype.photo = function(){
console.log("我可以拍照!");
}
SmartPhone.prototype.game = function(){
console.log("我可以玩游戏!");
}
const chuizi = new SmartPhone("锤子",2499,"黑色","5.5inch");
console.log(chuizi);
chuizi.call();
chuizi.photo();
chuizi.game();
运行结果
我可以打电话
我可以拍照
我可以玩游戏
ES6class类继承:
// ES6class类继承
class Phone{
constructor(brand,price) {
this.brand = brand;
this.price = price;
}
call(){
console.log("我可以打电话!");
}
}
class SmartPhone extends Phone{
// 构造函数
constructor(brand,price,color,size) {
super(brand,price); // 调用父类构造函数
this.color = color;
this.size = size;
}
photo(){
console.log("我可以拍照!");
}
game(){
console.log("我可以玩游戏!");
}
}
const chuizi = new SmartPhone("小米",1999,"黑色","5.15inch");
console.log(chuizi);
chuizi.call();
chuizi.photo();
chuizi.game();
运行结果
我可以打电话
我可以 拍照
我可以玩游戏
class Phone{
constructor(brand,price) {
this.brand = brand;
this.price = price;
}
call(){
console.log("我可以打电话!");
}
}
class SmartPhone extends Phone{
// 构造函数
constructor(brand,price,color,size) {
super(brand,price); // 调用父类构造函数
this.color = color;
this.size = size;
}
// 子类对父类方法重写
// 直接写,直接覆盖
// 注意:子类无法调用父类同名方法
call(){
console.log("我可以进行视频通话!");
}
photo(){
console.log("我可以拍照!");
}
game(){
console.log("我可以玩游戏!");
}
}
const chuizi = new SmartPhone("小米",1999,"黑色","5.15inch");
console.log(chuizi);
chuizi.call();
chuizi.photo();
chuizi.game();
class中的getter和setter设置
// class中的getter和setter设置
class Phone{
get price(){
console.log("价格属性被读取了!");
// 返回值
return 123;
}
set price(value){
console.log("价格属性被修改了!");
}
}
/ 实例化对象
let s = new Phone();
console.log(s.price); // 返回值
s.price = 2999;