JavaScript 中的对象是非常重要的概念,它是用来封装相关属性和行为的数据类型,JavaScript 对象实际上是一个特殊的键值对集合,每个键值对被称为一个属性或者方法。
JavaScript 对象与 Prototype 原型用法实例分析
JavaScript 中的对象是非常重要的概念,它是用来封装相关属性和行为的数据类型,JavaScript 对象实际上是一个特殊的键值对集合,每个键值对被称为一个属性或者方法。
JavaScript 中对象的创建有很多方式,包括字面量语法、构造函数语法、Object.create() 等,本文主要讲解 JavaScript 中的 Prototype 原型用法,这种方式可以实现灵活的对象继承,方便地复用已有的代码。
JavaScript 原型
在 JavaScript 中,每个对象都有一个原型,原型是一个对象,对象可以通过原型来继承另一个对象的属性和方法,这种机制被称为原型继承,原型可以通过 __proto__
属性来访问,也可以使用 Object.getPrototypeOf() 方法来访问。
原型的作用是为对象提供一些共享的属性和方法,当对象调用一个属性或者方法时,如果该属性或方法不存在于该对象本身,则会继续在原型链中查找,直到找到该属性或方法或者到达 Object.prototype。
prototype 属性和构造函数
JavaScript 中的函数也是对象,每个函数对象都有一个 prototype
属性,该属性是一个对象,表示该函数的原型对象,当使用该函数作为构造函数创建新的实例对象时,该实例对象会从原型对象中继承属性和方法,这种机制被称为构造函数继承。
构造函数的属性和方法都存在于构造函数的原型对象中,这可以极大地减少每个实例对象所占用的内存空间,并且使得对象间共享属性和方法成为可能。
下面是一个例子,首先定义一个构造函数 Person
,然后定义 Person.prototype
对象,并在其上定义了一个 sayHello
方法,该方法用来打印字符串 "Hello, I'm ${this.name}",其中 ${this.name} 是一个占位符,表示实例对象的 name
属性值。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function() {
console.log(`Hello, I'm ${this.name}.`);
};
然后,我们可以使用 Person
构造函数来创建实例对象,并调用 sayHello
方法,例如:
let p1 = new Person('Alice', 18);
let p2 = new Person('Bob', 20);
p1.sayHello(); // Hello, I'm Alice.
p2.sayHello(); // Hello, I'm Bob.
可以看到,两个实例对象 p1
和 p2
都可以调用 sayHello
方法,因为该方法存在于它们的原型对象 Person.prototype
中。
原型链
JavaScript 中的对象可以通过原型链来继承多个对象的属性和方法,原型链就是多个对象原型的链式链接。
例如,我们可以通过定义一个 Student
构造函数来继承 Person
的属性和方法,该构造函数的原型对象 Student.prototype
是 Person
的实例对象,这样所有通过 new Student()
创建的对象都会从 Student.prototype
继承 Person
的属性和方法。
function Student(name, age, grade) {
Person.call(this, name, age); // 调用 Person 构造函数初始化 name 和 age 属性
this.grade = grade;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.sayGrade = function() {
console.log(`My grade is ${this.grade}.`);
};
上述代码中,我们首先调用 Person
构造函数来初始化 name
和 age
属性,然后使用 Object.create()
方法来创建一个新对象作为 Student.prototype
,该新对象的原型对象是 Person.prototype
,这样就实现了 Student
构造函数对 Person
属性和方法的继承。
注意,我们还需要将 Student.prototype
的 constructor
属性设置为 Student
,以便后续使用 new
关键词来创建 Student
对象。
最后,我们在 Student.prototype
上定义了一个新的方法 sayGrade
,该方法用来打印字符串 "My grade is ${this.grade}",其中 ${this.grade} 是实例对象的 grade
属性值。
现在,我们可以使用 Student
构造函数来创建一个实例对象,并调用它的 sayHello
和 sayGrade
方法:
let s1 = new Student('John', 20, 'A');
s1.sayHello(); // Hello, I'm John.
s1.sayGrade(); // My grade is A.
我们可以在 Chrome 的控制台中输入 s1.__proto__
来查看该对象的原型链:
s1.__proto__ // => Student.prototype
s1.__proto__.__proto__ // => Person.prototype
s1.__proto__.__proto__.__proto__ // => Object.prototype
s1.__proto__.__proto__.__proto__.__proto__ // => null
注意到 s1.__proto__
的原型是 Student.prototype
,该对象的原型是 Person.prototype
,以此类推,最后到达 Object.prototype
,该对象是所有对象的默认原型,最后再到达 null
,表示原型链的终止。
结语
JavaScript 中的对象和原型继承是非常灵活的,它们能够让我们在开发中轻松地实现代码的复用和组合,同时还可以简化代码,提高代码的可读性和可维护性。我们需要认真学习和掌握 JavaScript 对象和原型继承的知识,以便能够在开发中灵活地使用它们。
示例一:原型链继承的缺陷
function Animal(name) {
this.name = name;
this.sleep = function() {
console.log(`${this.name} is sleeping`);
};
}
Animal.prototype.eat = function(food) {
console.log(`${this.name} is eating ${food}`);
};
function Cat(name) {
this.name = name;
}
Cat.prototype = new Animal("cat");
Cat.prototype.constructor = Cat;
let cat1 = new Cat("cat1");
let cat2 = new Cat("cat2");
cat1.eat("fish");
cat1.sleep();
cat2.eat("meat");
cat2.sleep();
console.log(cat1.sleep === cat2.sleep); //false
我们使用 Cat
构造函数来继承 Animal
的属性和方法,但是,使用 Cat.prototype = new Animal("cat");
这种方式会导致所有 Cat
实例对象共享原型对象 Animal.prototype
,如果我们通过 cat1.sleep === cat2.sleep
来比较两个实例对象的 sleep
方法,我们会发现它们不相等,原因是该方法存在于原型对象而非实例对象上,因此根据原型链继承的规则,它们实际上继承自不同的方法对象。这就是原型链继承的一个常见缺陷。
示例二:使用 Object.create() 来创建原型对象
let animal = {
name: "",
sleep: function() {
console.log(`${this.name} is sleeping`);
},
eat: function(food) {
console.log(`${this.name} is eating ${food}`);
},
};
function Cat(name) {
this.name = name;
}
Cat.prototype = Object.create(animal);
Cat.prototype.constructor = Cat;
let cat1 = new Cat("cat1");
let cat2 = new Cat("cat2");
cat1.eat("fish");
cat1.sleep();
cat2.eat("meat");
cat2.sleep();
console.log(cat1.sleep === cat2.sleep); //true
在该例子中,使用 animal
对象作为 Cat
的原型对象,可以避免多实例对象共享原型对象的问题,因为每个实例对象都拥有它自己的原型对象,而该对象是通过 Object.create()
方法来创建的,该方法会返回一个新对象,新对象的原型是参数中传入的对象。
注意,我们需要手动将 Cat.prototype
的 constructor
属性设置为 Cat
,否则会使用默认的 Object.prototype.constructor
。
本文标题为:javascript 对象 与 prototype 原型用法实例分析
基础教程推荐
- bool当成函数参数错误理解 2024-03-02
- SpringMVC拦截器快速掌握上篇 2023-04-18
- 老生常谈Java中List与ArrayList的区别 2023-05-08
- jQuery+jsp实现省市县三级联动效果(附源码) 2024-01-09
- @FeignClient注解中属性contextId的使用说明 2023-01-13
- java日期时间格式化@JsonFormat与@DateTimeFormat的使用 2023-04-17
- SpringBoot搭建Dubbo项目实现斐波那契第n项详解 2023-01-03
- java分布式事务之可靠消息最终一致性解决方案 2023-03-22
- android客户端从服务器端获取json数据并解析的实现代码 2024-03-02
- jsp页面验证码完整实例 2023-07-30