<script>
// 在javascript中
// 面向对象编程
var Father = {
Xing: '李',
height: 1.8,
run:function(){console.log(this.Xing + ' is running...');
}
};
// 那么在javascript过程中我们怎么才能实现类似java中的继承过程呢
var Son = Object.create(Father);//通过Object.create(Father),Son对象的原型被设置为Father,从而实现了继承。并建立了正确的原型链
console.log("Son的原型",Son.__proto__);//{Xing: "李", height: 1.8, run: ƒ},
console.log("Son的姓",Son.Xing);//李
Son.run()//李 is running...
// 在上面的代码中我们引入了原型这里来具体介绍一下
// 原型
// 在JavaScript中,原型(prototype)是核心特性之一,它用于实现对象之间的继承和共享属性或方法。
// 每个JavaScript对象(除了null)都有一个内置的属性,称为[[Prototype]](或者可以间接通过__proto__访问,尽管这不是标准推荐的做法)。这个属性指向另一个对象,即该对象的原型。
// 当我们试图访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript引擎会继续在其原型对象中查找,这个过程会一直向上追溯,
// 直到找到该属性或方法,或者到达原型链的末端(通常是Object.prototype)。
// 原型链
// 这个机制形成了所谓的“原型链”。简单来说,原型链就是对象与其原型之间链接形成的链式结构。
// 通过这个链条,对象可以从其原型以及原型的原型等中继承属性和方法。
// 原型对象的用途
// 继承: 原型最显著的用途是实现继承。一个对象可以继承另一个对象的属性和方法,无需复制这些属性和方法到自身,这样可以节省内存并支持代码复用。
// 方法共享: 对象的实例共享其构造函数的原型上的方法,这意味着不同实例上的同名方法其实引用的是同一个函数,这在大量创建相似对象时特别有用。
// 动态扩展: 即使对象已经被创建,我们也可以向其构造函数的原型添加属性和方法,进而所有实例都会自动获得这些新增的属性和方法。
// 原型的使用示例
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log('Hello, my name is ' + this.name);
};
let person1 = new Person('Alice');
let person2 = new Person('Bob');
person1.greet(); // 输出 "Hello, my name is Alice"
person2.greet(); // 输出 "Hello, my name is Bob"
// 向Person的原型添加方法,两个实例都可以访问
Person.prototype.sayGoodbye = function() {
console.log('Goodbye!');
};
person1.sayGoodbye(); // 输出 "Goodbye!"
person2.sayGoodbye(); // 输出 "Goodbye!"
console.log("person1的原型为",person1.__proto__);//Object { greet: greet(), sayGoodbye: sayGoodbye(), … }
console.log("person2的原型为",person2.__proto__);//Object { greet: greet(), sayGoodbye: sayGoodbye(), … }
console.log("person1.prototype为",person1.prototype)//person1.prototype为 undefined得到undefined的原因是,普通对象(如通过构造函数创建的实例person1)并没有prototype属性。只有函数才有prototype属性,用于设置作为其实例对象的原型。
console.log("Person.__proto__为",Person.__proto__);//Person.__proto__为 function (),实际上看到的是Function.prototype,它是所有函数对象的原型对象。
console.log("Person.prototype为",Person.prototype);//Person.prototype为 Object { greet: greet(), sayGoodbye: sayGoodbye(), … }
console.log("Person.prototype.__proto__为",Person.prototype.__proto__);//Person.prototype.__proto__为 Object { … }
// 我们发现person2.__proto__和Person.prototype相同,这是为什么呢?
// 这是因为在JavaScript中,当使用构造函数(如Person)通过new关键字创建一个实例对象(如person2)时,
// 该实例对象的内部属性__proto__(或更标准的[[Prototype]])会被自动设置指向构造函数的prototype属性所指向的原型对象。
// 即当使用new Person()创建一个新的对象实例时,这个新对象的__proto__就会被自动设置为Person.prototype。
// Person.prototype通常用来存放那些你想让所有Person实例共享的方法和属性。
// 上面的person1和person2是Person的一个实例(或对象)。
// 实例对象没有自己的prototype属性(这是构造函数的属性)。
// 实例对象有原型链上的原型对象(通过__proto__或Object.getPrototypeOf(instance)访问),
// 这个原型对象是从构造函数的prototype属性来的。
//那么我们可以总结一下:
// 1. __proto__属性:用于访问对象的原型(prototype)。
// 2. prototype属性:用于定义构造函数的原型对象(prototype object)。
// 3. prototype链:通过__proto__属性链接起来的原型链。
// 4. 原型对象:通过prototype属性定义的构造函数的原型对象。
// 5. 实例对象:通过new构造函数创建的对象实例。
//6. 原型链:通过__proto__属性链接起来的原型链
</script>