1.1 原型对象
- prototype为原型对象。每一个构造函数都有一个prototype 属性,指向另一个对象。
- prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
- 原型对象的作用是共享方法。
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>prototype特点</title>
<script type="text/javascript">
function Person(myName, myAge){
this.name = myName;
this.age = myAge;
this.currentType = "构造函数中的type";
this.say = function (){
console.log("构造函数的的say构造方法");
}
}
Person.prototype = {
currentType:"hello javaScript!!!",
say: function (){
console.log("hello world");
}
}
// 创建对象
let obj1 = new Person("curry", 10);
obj1.say();
console.log(obj1.currentType);
console.log("++++++++++++++++");
let obj2 = new Person("james", 35);
obj2.say();
console.log(obj2.currentType);
</script>
</head>
<body>
<!--
原型 prototype:
1.每当创建的每一个函数,解析器都会向函数中添加一个属性prototype。
这个属性对应着一个对象,这个对象就是我们所谓的原型对象。函数作为普通函数调用prototype没有任何作用。
2.当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象。
可以通过__proto__来访问该属性。
3.原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,可以将对象中共有的内容,统一设置到原型对象中。
4.当访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。
5.以后创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中。
这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了。
-->
</body>
</html>
执行结果
1.2 对象原型
基本特点
- 每个对象都会有一个属性__ proto __ 指向构造函数的prototype原型对象。
对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有 __ proto __ 原型的存在。 - __ proto __ 对象原型和原型对象 prototype 是等价的。
- __ proto __对象原型的意义为对象的查找机制提供一个方向,实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype。
1.3 Constructor属性
对象原型(_ _ proto _ _)和构造函数原型对象(prototype)里面都有一个属性constructor属性,constructor称为构造函数,因为它指回构造函数本身。
注意事项
- constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
- 一般情况下,对象的方法都在构造函数的原型对象中设置。如果有多个对象的方法,可以给原型对象采取对象形式赋值。但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor 就不再指向当前构造函数了。
- 此时,可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>对象三角关系</title>
<script type="text/javascript">
/*
1.每个"构造函数"中都有一个默认的属性, 叫做prototype
prototype属性保存着一个对象, 这个对象我们称之为"原型对象"
2.每个"原型对象"中都有一个默认的属性, 叫做constructor
constructor指向当前原型对象对应的那个"构造函数"
3.通过构造函数创建出来的对象我们称之为"实例对象"
每个"实例对象"中都有一个默认的属性, 叫做__proto__
__proto__指向创建它的那个构造函数的"原型对象"
*/
// 1.创建Person构造函数
function Person(myName, myAge){
this.name = myName;
this.age = myAge;
}
// 示例化对象
let obj = new Person("guardwhy", 26);
// 输出结果
console.log(Person.prototype);
console.log(Person.prototype.constructor);
console.log(obj.__proto__);
</script>
</head>
<body>
</body>
</html>
执行结果
1.4 Function函数
基本特点
JavaScript中函数是引用类型(对象类型),既然是对象,所以也是通过构造函数创建出来的。所有函数都是通过Function构造函数创建出来的对象。
只要是函数就有prototype属性,Function函数的prototype属性指向Function原型对象。
JavaScript中只要原型对象就有constructor属性,Function原型对象的constructor指向它对应的构造函数。
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Function函数</title>
<script type="text/javascript">
/*
Person构造函数是Function构造函数的实例对象, 所以也有__proto__属性
Person构造函数的__proto__属性指向"Function原型对象"
*/
// 1.构造函数
function Person(myName, myAge){
this.name = myName;
this.age = myAge;
}
// 2.实例化对象
let obj = new Person("guardwhy", 26);
// 3.输出结果
console.log(Function);
console.log(Function.prototype);
console.log(Function.prototype.constructor);
console.log("+++++++++++++");
console.log(Function == Function.prototype.constructor); // true
console.log("=============");
console.log(Person.__proto__);
console.log(Person.__proto__ == Function.prototype); // true
</script>
</head>
<body>
</body>
</html>
Function关系图
1.5 Object函数
JavaScript中还有一个系统提供的构造函数叫做Object,只要是函数都是Function构造函数的实例对象。
只要是对象就有__ proto __ 属性, 所以Object构造函数也有__ proto __ 属性。Object构造函数的 __ proto__ 属性指向创建它那个构造函数的原型对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Object函数</title>
<script type="text/javascript">
/*
1.只要是构造函数都有一个默认的属性, 叫做prototype,prototype属性保存着一个对象, 这个对象我们称之为原型对象。
2.只要是原型对象都有一个默认的属性, 叫做constructor,constructor指向当前原型对象对应的那个构造函数。
*/
// 1.创建Person构造函数
function Person(myName, myAge){
this.name = myName;
this.age = myAge;
}
// 实例化对象
let obj1 = new Person("guardwhy", 26);
// 输出结果
console.log(Function.__proto__);
console.log(Function.__proto__ === Function.prototype); // true
console.log("++++++++++++++++++");
console.log(Object);
console.log(Object.__proto__);
console.log(Object.__proto__ === Function.prototype); // true
console.log("============");
console.log(Object.prototype);
console.log(Object.prototype.constructor);
console.log("-----------------");
console.log(Object.prototype.constructor == Object); // true
console.log(Object.prototype.__proto__); // null
</script>
</head>
<body>
</body>
</html>
执行结果
Object函数关系图
1.6 函数对象关系
函数对象特点
Function函数是所有函数的祖先函数。所有构造函数都有一个prototype属性。
所有原型函数对象都有一个constructor属性,所有函数都是对象,所有对象都有一个__proto__属性。
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>函数对象关系</title>
<script type="text/javascript">
/*
1.所有的构造函数都有一个prototype属性, 所有prototype属性都指向自己的原型对象
2,所有的原型对象都有一个constructor属性, 所有constructor属性都指向自己的构造函数
3.所有函数都是Function构造函数的实例对象
4.所有函数都是对象, 包括Function构造函数
5.所有对象都有__proto__属性
6.普通对象的__proto__属性指向创建它的那个构造函数对应的"原型对象"
7.所有对象的__proto__属性最终都会指向"Object原型对象"
8."Object原型对象"的__proto__属性指向NULL
*/
// 构造函数Person
function Person(myName, myAge){
this.name = myName;
this.age = myAge;
}
// 实例化对象
let obj1 = new Person("guardwhy", 21);
console.log(Function.prototype.__proto__);
console.log(Person.prototype.__proto__);
console.log(Function.prototype.__proto__ === Person.prototype.__proto__); // true
console.log("+++++++++++++");
console.log(Function.prototype.__proto__ === Object.prototype); // true
console.log("==================");
console.log(Person.prototype.__proto__ === Object.prototype); // true
</script>
</head>
<body>
</body>
</html>
执行结果
函数对象图示
1.7 原型链
1.7.1 原型链基本概念
任何对象都有原型对象,也就是prototype属性,任何原型对象也是一个对象。
该对象就有__ proto__ 属性,这样一层一层往上找,就形成了一条链。
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>原型链</title>
</head>
<body>
<script>
function Star(uname, age) {
this.name = uname;
this.age = age;
}
Star.prototype.sing = function() {
console.log('我会唱歌');
};
let obj = new Star('蔡徐坤', 18);
// 1. 只要是对象就有__proto__ 原型, 指向原型对象
console.log(Star.prototype);
console.log(Star.prototype.__proto__ === Object.prototype); // true
// 2.我们Star原型对象里面的__proto__原型指向的是 Object.prototype
console.log(Object.prototype.__proto__); // null
// 3. 我们Object.prototype原型对象里面的__proto__原型 指向为 null
</script>
</body>
</html>
执行结果
1.7.2 查找机制注意点
-
当访问对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。如果没有就查找它的原型(也就是__ proto __指向的 prototype 原型对象)。
-
如果还没有就查找原型对象的原型(Object的原型对象)。依此类推一直找到 Object 为止(null)。
-
__ proto__ 对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。
1.7.3 属性注意点
- 在给一个对象不存在的属性设置值的时候, 不会去原型对象中查找。
- 如果当前对象没有就会给当前对象新增一个不存在的属性。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>属性注意点</title>
<script type="text/javascript">
// 1.构造函数Person
function Person(myName, myAge){
this.name = myName;
this.age = myAge;
}
Person.prototype = {
constructor: Person,
currentType: "javaScript hello!!!",
say: function (){
console.log("属性注意点~~~");
}
}
// 2.创建对象
let obj = new Person("guardwhy", 26);
obj.currentType = "javaScript处理跳转..";
console.log(obj.currentType); // javaScript处理跳转..
console.log(obj.__proto__.currentType); // javaScript hello!!!
</script>
</head>
<body>
</body>
</html>
1.8 封装性
实例属性/实例方法 静态属性/静态方法
通过实例对象访问的属性, 称之为实例属性。通过实例对象调用的方法, 称之为实例方法。
通过构造函数访问的属性, 称之为静态属性。通过构造函数调用的方法, 称之为静态方法。
局部变量和局部函数
- 无论是ES6之前还是ES6, 只要定义一个函数就会开启一个新的作用域。
- 只要在这个新的作用域中, 通过let/var定义的变量就是局部变量,只要在这个新的作用域中, 定义的函数就是局部函数。
私有变量和函数
- 默认情况下对象中的属性和方法都是公有的, 只要拿到对象就能操作对象的属性和方法。
- 外界不能直接访问的变量和函数就是私有变量和是有函数。
- 构造函数的本质也是一个函数, 所以也会开启一个新的作用域, 所以在构造函数中定义的变量和函数就是私有和函数。
什么是封装
- 封装性就是隐藏实现细节,仅对外公开接口。
- 当一个类把自己的成员变量暴露给外部的时候,那么该类就失去对属性的管理权,可以任意的修改你的属性。
- 封装就是将数据隐藏起来,只能用此类的方法才可以读取或者设置数据,不可被外部任意修改。
- 封装是面向对象设计本质(将变化隔离)。这样降低了数据被误用的可能 (提高安全性和灵活性)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>封装性</title>
<script type="text/javascript">
function Person(){
this.name = "guardwhy";
// 定义age变量
let age = 26;
this.setAge = function (myAge){
if(myAge >= 0){
age = myAge;
}
}
this.getAge = function (){
return age;
}
}
// 创建obj对象
let obj = new Person();
// 操作的是私有属性(局部变量)
obj.setAge(-10);
// 输出结果
console.log("age大小(私有属性):" + obj.getAge());
/*
注意点:
在给一个对象不存在的属性设置值的时候, 不会去原型对象中查找, 如果当前对象没有就会给当前对象新增一个不存在的属性。
由于私有属性的本质就是一个局部变量, 并不是真正的属性, 如果通过 对象.xxx的方式是找不到私有属性的。
*/
// 操作公有属性
obj.age = -3;
console.log("age大小(公有属性):" + obj.age);
</script>
</head>
<body>
</body>
</html>
执行结果
1.9 this关键字
1.9.1 基本特点
- 当以函数的形式调用时,this是window。
- 当以方法的形式调用时,谁调用方法this就是谁。
- 当以构造函数的形式调用时,this就是新创建的那个对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>this关键字</title>
<script type="text/javascript">
// 1.创建Person构造函数
function Person(myName, myAge) {
this.name = myName;
this.age = myAge;
this.say = function () {
// 方法中的this谁调用就是谁, 所以当前是obj1调用, 所以当前的this就是obj1
console.log(this.name, this.age);
}
// return this; // 系统自动添加的
}
// 创建obj1对象
let obj1 = new Person("guardwhy", 26);
// console.log(obj1.name);
// console.log(obj1.age);
// 对象调用方法
obj1.say();
</script>
</head>
<body>
</body>
</html>
1.9.2 函数内部的this指向
这些 this 的指向,当调用函数的时候确定的。调用方式的不同决定了this 的指向不同,this一般指向调用者。
调用方式 | this指向 |
---|---|
普通函数调用 | window |
构造函数调用 | 实例对象,原型对象里面的方法也指向实例对象 |
对象方法调用 | 该方法所属对象 |
事件绑定方法 | 绑定事件对象 |
定时器函数 | window |
立即执行函数 | window |
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>函数内部的this指向</title>
</head>
<body>
<button>点击</button>
<script type="text/javascript">
// 函数的不同调用方式决定了this 的指向不同
// 1. 普通函数 this 指向window
function fn() {
console.log('普通函数的this' + this);
}
window.fn();
// 2. 对象的方法 this指向的是对象 o
let obj1 = {
sayHi: function() {
console.log('对象方法的this:' + this);
}
}
obj1.sayHi();
// 3. 构造函数 this 指向 ldh 这个实例对象 原型对象里面的this 指向的也是 ldh这个实例对象
function Person() {
};
Person.prototype.sing = function() {
}
let obj2 = new Person();
// 4. 绑定事件函数 this 指向的是函数的调用者 btn这个按钮对象
let btn = document.querySelector('button');
btn.onclick = function() {
console.log('绑定时间函数的this:' + this);
};
// 5. 定时器函数 this 指向的也是window
window.setTimeout(function() {
console.log('定时器的this:' + this);
}, 1000);
// 6. 立即执行函数 this还是指向window
(function() {
console.log('立即执行函数的this' + this);
})();
</script>
</body>
</html>
执行结果
1.9.3 改变函数内部this指向
call方法
call()方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的 this 指向。
应用场景: 经常做继承。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>call方法</title>
<script type="text/javascript">
let obj = {
name: 'guardwhy'
}
function func(a, b) {
console.log(this);
console.log("a+b=" + a + b);
}
// call 第一个可以调用函数 第二个可以改变函数内的this指向
func.call(obj, 1, 2);
function Father(myName, myAge, mySex) {
this.name = myName;
this.age = myAge;
this.sex = mySex;
}
function Son(myName, myAge, mySex) {
// call 的主要作用可以实现继承
Father.call(this, myName, myAge, mySex);
}
let son = new Son('小明', 18, '男');
console.log(son);
</script>
</head>
<body>
</body>
</html>
执行结果
apply方法
apply() 方法调用一个函数。简单理解为调用函数的方式,但是它可以改变函数的 this 指向。
应用场景: 经常跟数组有关系。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>apply方法</title>
</head>
<body>
<script type="text/javascript">
let obj = {
name: 'guardwhy'
};
function fn(array1) {
console.log(this);
console.log(array1); // 'pink'
}
fn.apply(obj, ['pink']);
// 1. 也是调用函数 第二个可以改变函数内部的this指向
// 2. 但是他的参数必须是数组(伪数组)
let array1 = [1, 66, 3, 99, 4];
let array2 = ['red', 'pink'];
// var max = Math.max.apply(null, arr);
let max = Math.max.apply(Math, array1);
let min = Math.min.apply(Math, array1);
console.log(max, min);
</script>
</body>
</html>
执行结果
bind方法
不会调用原来的函数,可以改变原来函数内部的this 指向。返回的是原函数改变this之后产生的新函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>bind方法</title>
</head>
<body>
<button>点击</button>
<button>点击</button>
<button>点击</button>
<script>
// bind() 绑定 捆绑的意思
let obj = {
name: 'guardwhy'
};
function func(a, b) {
console.log(this);
console.log(a + b);
}
let fs = func.bind(obj, 1, 2);
fs();
// 1. 如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向此时用bind
// 2. 我们有一个按钮,当我们点击了之后,就禁用这个按钮,2秒钟之后开启这个按钮
let btns = document.querySelectorAll('button');
for (let i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
// 点击就禁用
this.disabled = true;
setTimeout(function() {
this.disabled = false;
}.bind(this), 2000);
}
}
</script>
</body>
</html>
执行代码
1.9.4 方法区别
共同点
都可以改变this指向
不同点
- call 和 apply 会调用函数, 并且改变函数内部this指向.
- call 和 apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递
- bind 不会调用函数, 可以改变函数内部this指向.
应用场景
- call 经常做继承.
- apply经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值
- bind 不调用函数,但是还想改变this指向. 比如改变定时器内部的this指向。
1.10 JS 继承
子类继承父类的属性
继承图示
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>js继承</title>
<script type="text/javascript">
function Person(myName, myAge) {
// let per = new Object();
// let this = per;
// this = stu;
this.name = myName; // stu.name = myName;
this.age = myAge; // stu.age = myAge;
// return this;
}
Person.prototype.message = function () {
console.log("姓名:" + this.name, "年龄:" + this.age);
}
function Student(myName, myAge, myScore) {
// 在子类的构造函数中通过call借助父类的构造函数。
Person.call(this, myName, myAge);
this.score = myScore;
this.study = function () {
console.log("hello javaScript");
}
}
Student.prototype = new Person();
// 将子类的原型对象修改为父类的实例对象。
Student.prototype.constructor = Student;
// 实例化对象
let stu = new Student("guardwhy", 19, 99);
stu.message();
console.log( "分数:" + stu.score);
// 调用方法
stu.study();
</script>
</head>
<body>
</body>
</html>
执行结果
1.11 获取对象类型
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>获取对象类型</title>
<script type="text/javascript">
// 1.创建obj对象
let obj1 = new Object();
console.log("类型:" + typeof obj1); // 类型:Object
// 2.定义数组类型
let array = new Array();
console.log("类型:"+ array.constructor.name); // 类型:Array
// 3.对象类型
function Person(){
this.name = "guardwhy";
this.age = 21;
this.message = function (){
console.log("姓名:" + this.name, "年龄:" + this.age);
}
}
// 实例化对象
let obj2 = new Person();
console.log("类型:" + obj2.constructor.name); // 类型:Person
</script>
</head>
<body>
</body>
</html>
执行结果
1.12 instanceof
基本概念
instanceof用于判断 “对象” 是否是指定构造函数的 “实例”。
只要构造函数的原型对象出现在实例对象的原型链中都会返回true。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>instanceof关键字</title>
</head>
<body>
<script type="text/javascript">
function Person(myName){
this.name = myName;
}
function Student(myName, myScore){
Person.call(this, myName);
this.score = myScore;
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
// 实例化对象
let obj = new Student();
console.log(obj instanceof Person); // true
</script>
</body>
</html>
1.13 isPrototypeOf
基本概念
isPrototypeOf用于判断 一个对象是否是另一个对象的原型。
只要调用者在传入对象的原型链上都会返回true。
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>isPrototypeOf属性</title>
</head>
<body>
<script type="text/javascript">
function Person(myName){
this.name = myName;
}
function Student(myName, myScore){
Person.call(this, myName);
this.score = myScore;
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
// 实例化对象
let obj = new Student();
console.log(Person.prototype.isPrototypeOf(obj)); // true
</script>
</body>
</html>
1.14 对象属性
判断对象属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>判断对象属性</title>
</head>
<body>
<script type="text/javascript">
class Person{
name = null;
age = 0;
height = 1.80;
}
// 1.创建对象obj
let obj = new Person();
// in的特点: 只要类中或者原型对象中有, 就会返回true
console.log("name" in obj); // true
console.log("width" in obj); // false
console.log("height" in obj); // true
// hasOwnProperty:判断某一个对象自身是否拥有某一个属性
// 特点: 只会去类中查找有没有, 不会去原型对象中查找
console.log(obj.hasOwnProperty("name")); // true
console.log(obj.hasOwnProperty("score")); // false
</script>
</body>
</html>
对象增删改查
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>对象增删改查</title>
<script type="text/javascript">
// 创建Person类
class Person{
}
// 创建obj对象
let obj = new Person();
console.log("======添加操作======");
// 1.添加属性
obj["name"] = "guardwhy";
obj["age"] = "18";
// 2.添加方法
obj["say"] = function (){
console.log("hello world");
}
obj.say();
console.log(obj);
console.log("======修改操作======");
// 3.修改属性
obj["name"] = "curry";
obj["age"] = "10";
// 4.修改方法
obj["say"] = function (){
console.log("hello javaScript!!!");
}
obj.say();
console.log(obj);
console.log("======查询操作======");
console.log(obj["name"]);
console.log("======删除操作======");
// .删除属性
delete obj["name"];
// 4.删除方法
delete obj["say"];
console.log(obj);
</script>
</head>
<body>
</body>
</html>
执行结果
对象的遍历
对象的遍历就是依次取出对象中所有的属性和方法。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>对象遍历</title>
<script type="text/javascript">
// 1.构造函数
function Person(myName, myAge){
this.name = myName;
this.age = myAge;
this.say = function (){
console.log(this.name, this.age);
}
}
// 创建obj对象
let obj = new Person("guardwhy", 26);
console.log(obj);
// 条件遍历
for (let key in obj){
if(obj[key] instanceof Function){
continue;
}
// 注意点:取出obj对象中名称叫做当前遍历到的名称的属性或者方法的取值
console.log(obj[key]);
}
</script>
</head>
<body>
</body>
</html>
执行结果
对象解构赋值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>对象解构赋值</title>
<script type="text/javascript">
/*
注意点:
对象的解构赋值和数组的解构赋值 除了符号不一样, 其它的一模一样
数组解构使用[]
对象解构使用{}
*/
// 1.在数组的解构赋值中, 等号左边的格式必须和等号右边的格式一模一样, 才能完全解构
let [a1,b1,c1] = [1,3,5];
console.log(a1, b1, c1); // 1 3 5
// 2.在数组的解构赋值中, 两边的个数可以不一样
let [a2, b2] = [1,6,9];
console.log(a2, b2); // 1 6
// 3.在数组的解构赋值中,如果右边少于左边, 可以左边指定默认值
let [a3, b3, c3 = 666] = [1, 3];
console.log(a3, b3, c3); // 1 3 666
// 4.注意点: 在对象解构赋值中, 左边的变量名称必须和对象的属性名称一致, 才能解构出数据
/*
let obj = {
name: "lnj",
age: 34
}
let name = obj.name;
let age = obj.age;
console.log("name:" + name + ",age:" +age);
*/
// 结构赋值
let {
name, age} = {
name:"guardwhy", age:21};
console.log("name:" + name + ",age:" +age);
</script>
</head>
<body>
</body>
</html>
执行结果
1.15 拷贝
浅拷贝
修改新变量的值会影响原有的变量的值,默认情况下引用类型都是浅拷贝。
深拷贝
修改新变量的值不会影响原有变量的值,默认情况下基本数据类型都是深拷贝。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>深拷贝和浅拷贝</title>
<script type="text/javascript">
// 1.深拷贝
// 定义变量
let num1 = 123;
let num2 = num1;
// 修改形变量的值
num2 = 26;
// 输出结果
console.log("num1:" + num1);
console.log("num2:" + num2);
console.log("====深拷贝====");
// 2.浅拷贝
class Person{
name="guardwhy";
age = 26;
}
// 创建obj1对象
let obj1 = new Person();
let obj2 = obj1;
// 修改变量的值
obj2.name = "curry";
// 输出结果
console.log(obj1.name);
console.log(obj2.name);
console.log("====浅拷贝====");
</script>
</head>
<body>
</body>
</html>
执行结果
普通对象深拷贝
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>普通对象深拷贝</title>
<script type="text/javascript">
// 创建Person类
class Person{
name="guardwhy";
age = 27;
}
// 创建obj1对象
let obj1 = new Person();
// 深拷贝
let obj2 = new Object();
// assign方法可以将第二个参数的对象的属性和方法拷贝到第一个参数的对象中
Object.assign(obj2, obj1);
obj2.name = "Curry";
console.log("obj2:"+ obj2.name);
console.log("obj1:" + obj1.name);
</script>
</head>
<body>
</body>
</html>
执行结果
对象深拷贝
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>对象深拷贝</title>
<script type="text/javascript">
// 创建Person类
class Person{
name="Curry";
Student = {
age: 10
};
scores = [45, 68, 89];
}
// 创建obj1对象
let obj1 = new Person();
let obj2 = new Object();
// 调用函数
depCopy(obj2, obj1);
obj2.Student.age = 11;
// 输出结果
console.log("obj1年龄:" + obj1.Student.age);
console.log("obj2年龄:" + obj2.Student.age);
function depCopy(target, source){
// 1.通过遍历拿到source中所有的属性
for(let key in source){
// 2.取出当前遍历到的属性对应的取值
let sourceValue = source[key];
// 3.判断当前的取值是否是引用数据类型
if(sourceValue instanceof Object){
let subTarget = new sourceValue.constructor;
target[key] = subTarget;
depCopy(subTarget, sourceValue);
}else {
target[key] = sourceValue;
}
}
}
</script>
</head>
<body>
</body>
</html>
执行结果
转载:https://blog.csdn.net/hxy1625309592/article/details/116033713