JavaScript学习笔记(十二) 原型

简介: JavaScript学习笔记(十二) 原型

前言


之前看原型和原型链的时候,总是看得迷迷糊糊的,最近就趁着有空重新整理了一下,其实发现并不难

下面我们一步一步跟着,彻底弄清楚原型和原型链吧


正文


1、原型


  • 每个 实例对象 都有一个 constructor 属性,指向它的构造函数
function Person(name) {
  this.name = name
}
var person = new Person('Steve') // 自定义构造函数
var string = new String('Hello') // 原生的构造函数
console.log(person.constructor === Person)
console.log(string.constructor === String)
/*
 * 执行结果:
 * true
 * true
**/


  • 每个 函数对象(包括构造函数) 都有一个 prototype 属性,指向函数的原型对象
    这个 原型对象constructor 属性,指向函数本身
function Person(name) {
  this.name = name
}
var person = new Person('Steve') // 自定义构造函数
var string = new String('Hello') // 原生的构造函数
console.log(Person.prototype.constructor === Person)
console.log(String.prototype.constructor === String)
/*
 * 执行结果:
 * true
 * true
**/


  • 每个 对象 都有一个 [[prototype]] 私有属性,指向它的构造函数的原型对象,但这个属性是不允许访问的
    某些浏览器(例如 Chrome)提供 __proto__ 属性用于访问 [[prototype]] 私有属性
function Person(name) {
  this.name = name
}
var person = new Person('Steve') // 自定义构造函数
var string = new String('Hello') // 原生的构造函数
console.log(person.__proto__ === Person.prototype)
console.log(string.__proto__ === String.prototype)
console.log(Person.__proto__ === Function.prototype)
console.log(String.__proto__ === Function.prototype)
/*
 * 执行结果:
 * true
 * true
 * true
 * true
**/


  • 构造函数的 constructor 属性都是指向 Function,__proto__ 属性都是指向 Function.prototype
  • 因为构造函数都是通过 new Function 来创建的,它们都是 Function 的实例对象,包括 Function 和 Object


function Person(name) {
  this.name = name
}
console.log(Person.constructor === Function)
console.log(Person.__proto__ === Function.prototype)
console.log(String.constructor === Function)
console.log(String.__proto__ === Function.prototype)
console.log(Function.constructor === Function)
console.log(Function.__proto__ === Function.prototype)
console.log(Object.constructor === Function)
console.log(Object.__proto__ === Function.prototype)
/*
 * 执行结果:
 * true
 * true
 * true
 * true
 * true
 * true
 * true
 * true
**/
  • Object 外,其它构造函数的 prototype 属性的 __proto__ 属性都是指向 Object.prototype
    Objectprototype 属性的 __proto__ 属性指向 null
function Person(name) {
  this.name = name
}
console.log(Person.prototype.__proto__ === Object.prototype)
console.log(String.prototype.__proto__ === Object.prototype)
console.log(Function.prototype.__proto__ === Object.prototype)
console.log(Object.prototype.__proto__ === null)
/*
 * 执行结果:
 * true
 * true
 * true
 * true
**/


最后来一张图片总结一下,虽然看起来有点复杂,但是只要大家找到规律,就会很简单了

建议大家分类来看,注意哪里出现 constructor 属性,哪里出现 prototype 属性,哪里出现 __proto__ 属性


4c2f309aa797a76c93bc59087be88e58_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dzbXJ6eA==,size_16,color_FFFFFF,t_70#pic_center.png


2、原型链


(1)原型链


上面我们说过,所有对象都有 __proto__ 属性,并且这个 __proto__ 属性指向一个原型对象

因为原型对象也是对象,这个原型对象也有 __proto__ 属性,我们把这种关系称为原型链


4d69df25d0722a7f172dcc42fae7434e_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dzbXJ6eA==,size_16,color_FFFFFF,t_70#pic_center.png


(2)属性访问


当需要访问一个对象的属性时,首先从该对象开始查找,如果能够找到,那么到此返回


如果没有找到,就在该对象的 __proto__ 属性指向的原型对象中继续查找,如果能够找到,那么到此返回


如果没有找到,那么一直往上查找原型对象,直至 __proto__ 属性指向 null,也就是原型链的顶端


若原型链上的所有原型对象都没有该属性,则返回 undefined


function Person(name) { this.name = name }
Person.prototype.getName = function() { return this.name }
var person = new Person('Steve')
var name = person.getName() // 在 Person.prototype 中找到
var description = person.toString() // 在 Object.prototype 中找到
var age = person.age // 在原型链中无法找到
console.log(name)
console.log(description)
console.log(age)
/*
 * 执行结果:
 * Steven
 * [object Object]
 * undefined
**/


(3)属性检测


  • in 操作符:检测属性是否在对象的原型链上
  • hasOwnProperty 方法:检测属性是否来自对象本身
function Person(name) { this.name = name }
Person.prototype.getName = function() { return this.name }
var person = new Person('Steve')
console.log('age' in person)
console.log('name' in person)
console.log('getName' in person)
console.log('toString' in person)
console.log(person.hasOwnProperty('age'))
console.log(person.hasOwnProperty('name'))
console.log(person.hasOwnProperty('getName'))
console.log(person.hasOwnProperty('toString'))
/*
 * 执行结果:
 * false
 * true
 * true
 * true
 * false
 * true
 * false
 * false
**/


3、为什么要使用原型


JavaScript 中的继承是基于原型的,原型的作用在于不同实例对象之间可以共享数据,节省内存

function Person(name) { this.name = name }
Person.prototype.getName = function() { return this.name }
var person1 = new Person('Steve')
var person2 = new Person('Steven')
// 不同实例对象 person1 和 person2 都可以使用在 Person.prototype 上定义的 getName(共享数据)
// 从而避免在每个实例对象上都要重复定义 getName(节约内存)
var name1 = person1.getName()
var name2 = person2.getName()
console.log(name1)
console.log(name2)
/*
 * 执行结果:
 * Steve
 * Steven
**/


目录
相关文章
|
20天前
|
JavaScript 前端开发
js开发:请解释原型继承和类继承的区别。
JavaScript中的原型继承和类继承用于共享对象属性和方法。原型继承通过原型链实现共享,节省内存,但不支持私有属性。
19 0
|
20天前
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(三)
深入JS面向对象(原型-继承)
32 0
|
20天前
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(一)
深入JS面向对象(原型-继承)
35 0
|
20天前
|
存储 JavaScript 前端开发
构造函数和原型的结合应用:轻松搞定JS的面向对象编程(三)
构造函数和原型的结合应用:轻松搞定JS的面向对象编程
|
20天前
|
存储 JavaScript 前端开发
构造函数和原型的结合应用:轻松搞定JS的面向对象编程(二)
构造函数和原型的结合应用:轻松搞定JS的面向对象编程
|
20天前
|
JavaScript
JS数组增删方法的原理,使用原型定义
JS数组增删方法的原理,使用原型定义
|
15天前
|
JavaScript 前端开发
前端 JS 经典:原型和原型链
前端 JS 经典:原型和原型链
21 0
|
18天前
|
前端开发 JavaScript
前端 js 经典:原型对象和原型链
前端 js 经典:原型对象和原型链
25 1
|
20天前
|
JavaScript 前端开发
在JavaScript中,函数原型(Function Prototype)是一个特殊的对象
【5月更文挑战第11天】JavaScript中的函数原型是一个特殊对象,它为所有函数实例提供共享的方法和属性。每个函数在创建时都有一个`prototype`属性,指向原型对象。利用原型,我们可以向所有实例添加方法和属性,实现继承。例如,我们定义一个`Person`函数,向其原型添加`greet`方法,然后创建实例`john`和`jane`,它们都能调用这个方法。尽管可以直接在原型上添加方法,但推荐在构造函数内部定义以封装数据和逻辑。
22 2
|
20天前
|
移动开发 JavaScript 前端开发
webgl学习笔记3_javascript的HTML DOM
webgl学习笔记3_javascript的HTML DOM
20 0
webgl学习笔记3_javascript的HTML DOM