JavaScript-Advanced Days3 Notes
1、解释下如下代码,尤其是关于prototype的概念和使用。 最后介绍下为什么下面会提到用到prototype能够节约内存?
<script>
// 构造函数 公共的属性和方法 封装到 Star 构造函数里面了
// 1.公共的属性写到 构造函数里面
function Star(uname, age) {
this.uname = uname
this.age = age
this.sing = function () {
console.log(`${uname}'唱歌'`)
}
}
// 2. 公共的方法写到原型对象身上 节约了内存
Star.prototype.sing = function () {
console.log('唱歌')
}
const ldh = new Star('刘德华', 55)
const zxy = new Star('张学友', 58)
ldh.sing() //调用
zxy.sing() //调用
// console.log(ldh === zxy) // false
console.log(ldh.sing === zxy.sing) // false
console.dir(Star.prototype)
</script>
这段代码是JavaScript中的一个示例,展示了如何使用构造函数和原型对象来创建对象。下面我将逐一解释代码中的关键概念和作用。
构造函数(Constructor)
构造函数是一种特殊的函数,用于创建和初始化对象。在JavaScript中,当你使用new关键字调用一个函数时,这个函数就被视为构造函数。构造函数通常以大写字母开头,以区分于普通函数。
在这个例子中,Star是一个构造函数,用于创建明星对象。它接受两个参数:uname(名字)和age(年龄),并将它们作为对象的属性。
function Star(uname, age) { this.uname = uname; this.age = age; this.sing = function () { console.log(`${uname}'唱歌'`); }; }
原型对象(Prototype)
每个JavaScript对象都有一个原型对象,它是一个包含所有可继承属性的对象。当你尝试访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript引擎会沿着原型链向上查找,直到找到该属性或方法或者到达原型链的末端。
在这个例子中,Star.prototype是所有Star构造函数创建的对象共享的原型对象。通过将方法添加到原型对象上,所有实例都可以共享这些方法,而不需要在每个实例中重复定义。
Star.prototype.sing = function () { console.log('唱歌'); };
通俗解释
- 构造函数:就像一个工厂,用来制造具有相同特征(属性和方法)的对象。
- 原型对象:就像一个公共仓库,存储所有对象可以共享的属性和方法。
举例说明
假设我们有一个Car构造函数,用于创建汽车对象。每个汽车对象都需要有start和stop方法。
我们可以将这些方法定义在Car.prototype上,这样所有汽车对象都可以共享这些方法,而不需要为每个汽车对象单独定义。
为什么使用原型可以节约内存?
在JavaScript中,对象是引用类型,意味着它们在内存中占用的空间比基本数据类型(如数字、字符串)要大。如果每个对象都独立存储自己的方法,那么每个对象都会占用更多的内存。通过将方法定义在原型对象上,所有对象实例都可以共享这些方法,从而减少了内存的使用。
在这个例子中,如果sing方法定义在每个Star实例中,那么每个Star对象都会占用额外的内存来存储这个方法。但是,通过将sing方法定义在Star.prototype上,所有Star实例都共享同一个sing方法,从而节约了内存。
代码中的输出
ldh.sing()和zxy.sing()都会调用原型对象上的sing方法,输出"唱歌"。console.log(ldh.sing === zxy.sing)会输出false,因为尽管两个对象共享同一个sing方法,但是它们各自的sing属性是通过构造函数中的this.sing赋值的,所以它们指向的是不同的函数。
最后,console.dir(Star.prototype) 会输出Star原型对象的所有属性和方法,包括sing方法。
2、为什么如下代码的reduce前面一定得要加this呢?不加不行吗?
const arr = [1, 2, 3] Array.prototype.max = function () { return Math.max(...arr) } Array.prototype.min = function () { return min.max(...arr) } Array.prototype.sum = function (){ return this.reduce((prev, item) => prev + item, 0) # 这里 } console.log([1, 2, 3].sum()) console.log([11, 21, 31].sum())
reduce前面必须加上this,原因是 this 代表当前调用数组实例的上下文,也就是代码中的 [1, 2, 3] 或 [11, 21, 31]。在 Array.prototype.sum 函数里,如果你不使用 this,JavaScript 将不知道你要对哪个数组执行 reduce 操作。
来看具体的原因:
为什么需要 this?
-
当前上下文: 在
Array.prototype.sum方法中,this指代调用该方法的数组实例,比如[1, 2, 3]。也就是说,当你调用[1, 2, 3].sum()时,this就是[1, 2, 3]。 -
reduce 的作用:
reduce是一个数组的方法,用于将数组中的元素累积为一个值。如果不加this,代码将不知道你要对哪个数组进行累积操作。而加上this后,它明确告诉 JavaScript 应该在当前数组实例上执行reduce。
如果不加 this 会发生什么?
如果你不加 this,则代码找不到一个有效的数组来调用 reduce,会导致报错:
Array.prototype.sum = function () { return reduce((prev, item) => prev + item, 0); }
上述代码会导致一个 ReferenceError 错误,因为 reduce 是数组实例的方法,而你没有指定要对哪个数组调用它。
正确的写法:
Array.prototype.sum = function () { return this.reduce((prev, item) => prev + item, 0); }
这里的 this.reduce 确保 reduce 是在当前数组实例上执行的,正确累加数组中的元素。
3、关于原型里的constructor属性理解
个人理解:XX.constructor就理解为 XX的构造者,一般都是构造函数

4、如何理解区分原型对象和对象原型?
个人理解:
找定语,原型对象prototype是从构造函数里面去找, 是指构造函数的prototype属性,它是一个对象,定义了由该构造函数创建的实例所共享的属性和方法。
对象原型是从实例身上去找;

"原型对象"(Prototype Object)和"对象原型"(Prototype of Object)虽然听起来相似,但它们在JavaScript中有不同的含义。
为了帮助理解这两个概念,下面我会通俗地解释它们,并通过简单的例子来说明区别。
1. 原型对象(Prototype Object)
概念:
- 原型对象是指构造函数的
prototype属性,它是一个对象,定义了由该构造函数创建的实例所共享的属性和方法。 - 换句话说,当使用构造函数创建一个新对象时,该对象会自动继承构造函数的原型对象中的属性和方法。
通俗解释:
- 可以把原型对象想象成一张“蓝图”或者“模板”。每当你用构造函数创建一个新对象时,这个新对象都会根据这张蓝图去继承一些属性和方法。
举例说明:
// 创建一个构造函数 function Person(name) { this.name = name; } // 给构造函数的原型对象添加一个方法 Person.prototype.sayHello = function() { console.log('Hello, my name is ' + this.name); }; // 用构造函数创建一个实例 const person1 = new Person('Alice'); // 实例person1会继承原型对象中的方法 person1.sayHello(); // 输出:Hello, my name is Alice
在这个例子中:
Person.prototype就是构造函数Person的原型对象,它定义了sayHello方法。- 当我们用
new Person()创建实例person1时,person1就会从Person.prototype继承这个方法。
2. 对象原型(Prototype of Object)
概念:
- 对象原型是指任何对象内部的一个隐式属性
[[Prototype]],它指向该对象的“原型”,即从哪个对象继承属性和方法。 - 在 JavaScript 中,我们可以通过
Object.getPrototypeOf(obj)或者obj.__proto__来访问某个对象的原型(也就是它的[[Prototype]])。
通俗解释:
- 每个对象都有一个“幕后导师”或者“父母”,这个幕后导师就是对象的原型。对象会从它的原型那里继承属性和方法,就像孩子从父母那里继承一些特质一样。
- 对象原型就是对象内部的隐藏链接,它指向另外一个对象(原型对象),这个对象提供继承的功能。
举例说明:
const obj = { a: 1 };
// 获取obj的原型(即对象原型)
console.log(Object.getPrototypeOf(obj)); // 输出:{},默认是Object.prototype
// 定义一个对象,且指定其原型
const newObj = Object.create(obj);
console.log(newObj.a); // 输出:1, newObj从obj继承了属性a
在这个例子中:
obj的原型是Object.prototype,即所有对象都默认继承的原型。newObj是通过Object.create(obj)创建的,newObj的原型是obj,所以它可以访问obj中的属性a。
区别总结:
- **原型对象(Prototype Object)**是构造函数的
prototype属性,它定义了通过构造函数创建的实例对象所共享的属性和方法。所有实例通过构造函数的原型对象进行继承。 - **对象原型(Prototype of Object)**是指某个对象的
[[Prototype]],即它从哪个对象继承而来。对象的原型是指向另一个对象(可能是构造函数的原型对象),这决定了该对象能访问哪些继承的属性和方法。
总结类比:
- 原型对象:是一张蓝图,所有用同一个构造函数创建的对象都依据这张蓝图来“继承”属性和方法。
- 对象原型:是每个对象内部的一个隐式“链”,告诉这个对象它的继承来源是谁,这个来源通常是构造函数的原型对象。
- 对象原型: 是某个具体对象的内部属性,指向其继承的对象,常用
Object.getPrototypeOf()来获取。 - 原型对象:是构造函数的属性,决定了由这个构造函数创建的对象共享的属性和方法。
这就是对象原型和原型对象的区别,你问的“对象原型”实际上是 [[Prototype]],它是每个对象内部的一个属性,指向该对象的原型链上的下一个对象。
6、对象原型([[Prototype]]):是每个 JavaScript 对象(包括实例和函数对象)都有的内部属性,它指向该对象的原型。 那么请问什么是 原型?
原型(Prototype) 是 JavaScript 中用来实现对象继承的一种机制。它本质上是一个对象,作用是为其他对象提供属性和方法。通过原型机制,JavaScript 实现了对象的属性继承,从而能够共享和复用代码。
在每个 JavaScript 对象(除了 null)内部都有一个指向原型对象的隐藏属性,叫做 [[Prototype]](即对象原型)。这个原型本质上就是一个普通的对象,定义了所有通过该原型继承的对象可以访问的属性和方法。
原型的角色
- 原型 是用来实现继承的。JavaScript 中的每个对象都有一个原型对象,它通过原型链(Prototype Chain)来实现属性的查找和继承。
- 当我们访问一个对象的属性时,JavaScript 引擎首先检查对象自身是否有这个属性。如果没有,它会沿着对象的原型链向上查找,直到找到该属性或者查找到
null为止。
原型对象和对象原型
- **原型对象(Prototype Object):**是构造函数的一个属性,用来为所有该构造函数创建的实例对象提供共享的属性和方法。
- **对象原型(
[[Prototype]]):**是每个对象的一个隐藏属性,指向该对象的原型,原型就是另一个对象。我们可以通过Object.getPrototypeOf(obj)或obj.__proto__来获取。
举个例子:
// 定义一个构造函数 function Person(name) { this.name = name; } // 向构造函数的原型对象上添加方法 Person.prototype.sayHello = function() { console.log('Hello, my name is ' + this.name); }; const alice = new Person('Alice'); // 当访问 alice.sayHello 时,JavaScript 会首先检查 alice 对象本身是否有 sayHello 属性。 // 如果没有,它会通过 alice 的 [[Prototype]] (即 Person.prototype)去查找。 alice.sayHello(); // 输出:Hello, my name is Alice // 获取 alice 对象的原型 console.log(Object.getPrototypeOf(alice) === Person.prototype); // 输出:true // 通过 Person.prototype 共享方法 const bob = new Person('Bob'); bob.sayHello(); // 输出:Hello, my name is Bob
什么是原型?
在上面的例子中:
Person.prototype就是原型对象,它为所有Person的实例(例如alice和bob)提供共享的属性和方法。alice.__proto__或者Object.getPrototypeOf(alice)是alice对象的[[Prototype]],它指向Person.prototype。
因此,原型可以理解为一个对象(例如 Person.prototype),为其他对象提供属性和方法。每个对象都通过其 [[Prototype]] 属性与原型对象相关联,形成继承链。
原型链
多个对象的原型可以形成一条“链”,这就是原型链。
通过这条链,当我们访问一个对象的属性时,如果这个对象本身没有这个属性,JavaScript 会沿着原型链逐层查找,直到找到该属性或返回 undefined 为止。
console.log(alice.__proto__); // Person.prototype console.log(alice.__proto__.__proto__); // Object.prototype console.log(alice.__proto__.__proto__.__proto__); // null (Object.prototype 的原型是 null)
关键点
- 原型对象 是一个对象,通常是通过构造函数的
prototype属性创建的,它为实例对象提供共享属性和方法。 - 对象原型(
[[Prototype]]) 是每个对象的内部属性,指向它的原型对象,从而允许对象继承该原型上的属性和方法。

浙公网安备 33010602011771号