细说(值传递、引用传递)的区别, 数组和对象解构的常用方法, call.apply.bind的区别与联系, 访问器属性的原理与实现
程序员文章站
2022-02-17 11:28:34
...
值传递与引用传递的区别与联系:
深拷贝:
值传递: 原始类型,string,number,bool
引用传递: 引用类型,object,array
浅拷贝: 引用传递
入参:调用函数是传入的参数,简称:"入参"
样式代码:
<script>
let a = 1; //赋值、值传递:原始类型,string,number,bool
console.log("a = %d, b = %d", a, b);
a = 2;
console.log("a = %d, b = %d", a, b); //更新a,不影响b
let obj1 = { a: 1, b: 2 }; //引用传递:引用类型,object,array
console.log(obj1);
let obj2 = obj1;
console.log(obj2);
obj1.a = 10; // 更新obj1
console.log(obj1);
console.log(obj2); //obj2同步更新
const f1 = (x) => (x = 10); //传参时,不论什么类型,都是"值传递"
let m = 5;
console.log("m = %d", m);
f1(m);
console.log("m = %d", m); //函数中对参数的更新,并不会影响到入参
const f2 = (x) => (x.a = 10);
let o = { a: 1, b: 2 };
console.log(o);
f2(o);
console.log(o); //看上去函数中对于o.a的更新生效,实际上仍是值传递
const obj = { x: 1, y: 2 }; //对于引用类型,只有全新赋值才算是更新,修改属性不算的
obj.x = 20;
const f3 = (x) => (x = {}); // 赋值一个全新对象,才是更新
f3(o);
console.log(o); // 函数中对于对象/引用参数的更新并没有影响到入参
</script>
效果预览:
数组和对象解构的常用方法与函数传数:
解构赋值: 快速从集合数据(数组/对象解构出独立变量)
<script>
let [a, b, c] = [1, 2, 3]; //数组
console.log(a, b, c);
[a, b] = [1, 2, 3];
console.log(a, b);
[a, b, c, d = "xxxx"] = [1, 2, 3];
console.log(a, b, c, d);
[a, b, ...c] = [1, 2, 3, 4, 5];
console.log(a, b, c);
[, , a, ,] = [1, 2, 3, 4, 5];
console.log(a);
let x = 1,
y = 2,
t;
console.log("x = %d, y = %d", x, y);
[y, x] = [x, y];
console.log("x = %d, y = %d", x, y);
let { id, name } = { id: 10, name: "手机" }; //对象解构
console.log(id, name);
({ name, id } = { id: 10, name: "手机" }); //属性名与变量名必须一一对应,顺序无所谓
console.log(id, name);
let email = "admin@php.cn";
let { role, email: userEmail } = { role: "user", email: "user@php.cn" };
console.log(userEmail);
console.log(email);
//参数解构
let sum = ([a, b]) => a + b; //数组传参
console.log(sum([10, 20]));
let getUser = ({ name, email }) => [name,email]; // 对象传参
console.log(getUser({ email: "tp@php.cn", name: "老师" }));
</script>
效果预览:
bind,call,apply的区别与联系:
bind()不会立即执行,只返回一个函数声明
call/apply立即执行
样式代码:
<body>
<button>click</button>
<script>
function hello(name) {
this.name = name;
console.log(this.name);
}
const obj = { name: "admin" };
//经典调用
console.log(hello("朱老师"));
//bind()不会立即执行
let f = hello.bind(obj, "天蓬老师");
console.log(f());
//call/apply立即执行
f = hello.call(obj, "灭绝老师");
console.log(f);
f = hello.apply(obj, ["西门老师"]);
console.log(f);
</script>
</body>
效果预览:
访问器属性的原理与实现过程:
将方法伪造成一个属性
样式代码:
<script>
const product = {
data: [
{ name: "电脑", price: 5000, num: 5 },
{ name: "手机", price: 4000, num: 10 },
{ name: "电视", price: 9000, num: 4 },
],
get total() { // 将方法伪造成一个属性
return this.data.reduce((t, c) => (t += c.price * c.num), 0);
},
set setPrice(price) {
this.data[1].price = price;
},
};
console.log("总金额 :", product.total);
console.log(product.data[1].price);
product.setPrice = 9988;
console.log(product.data[1].price);
</script>
访问器属性的优先级:
访问器属性优先级高于同名的普通属性
<script>
let user = {
data: { name },
get name() {
return this.data.name;
},
set name(value) {
this.data.name = value;
},
};
user.name = "今天天气真不错";
console.log(user.name);
</script>
多分支与swithc转换的技巧:
score = 90; //多分支
if (score >= 60 && score < 80) {
console.log("合格");
} else if (score >= 80 && score <= 100) {
console.log("学霸");
}
else if (score > 100 || score < 0) { // 判断成绩是否合法
console.log("非法数据");
} else {
console.log("补考吧");
}
score = 90; //switch来简化多分支时,switch是严格匹配
switch (true) {
case score >= 60 && score < 80:
console.log("合格");
break;
case score >= 80 && score <= 100:
console.log("学霸");
break;
case score > 100 || score < 0: //判断成绩是否合法
console.log("非法数据");
break;
default:
console.log("补考吧");
}
let response = "Success"; // switch用在单值判断
switch (response.toLocaleLowerCase()) {
case "fail":
console.log("请求失败");
break;
case "success":
console.log("请求成功");
break;
default:
console.log("未知错误");
}
</script>
效果预览:
三元运算符:
简化双分支:条件? true : false
如果为真执行第一个分支,
如果为假执行第二个分支,
三元运算符会将:右边的视为一个整体,其优先级应该是很低的,如果要先求三元运算符中的顺,必须先将其用括号括起来:
<script>
//双分支
score = 60;
console.log(score >= 60 ? "及格" : "补考吧");
</script>