作为自己学习时的笔记,不做过多解释:
几点笔记:
- 函数是对象,对象是通过函数创建出来的
原型分为两种:
- 显示原型:prototype ,是每个函数function/函数对象独有的属性
- 隐式原型:__proto__ ,是每个对象都有的属性
原型和原型链:
- 原型:可以把函数看作一个类,那么原型就是所有类都有的属性,在这里存储可以公共使用的统一的方法
- 原型链:每个对象都有__proto__ ,这个属性指向该对象的 prototype ,然后这个 prototype 原型对象也会有自己的__proto__ 最终层层向上会找到最顶级对象 Object 的 prototype ,这个过程联系起来被称为原型链。【原型链最终的指向--> Object.prototype.__proto__ === null】
js 里面有两个最顶层的概念:
- 最顶层的构造器: Function
- 最顶层的对象:Object
首先需要先了解“构造函数”
function Person(name, gender){ //声明一个构造函数
this.name = name
this.gender = gender
this.say = function(){
console.log(`我是${name},是一个${gender}生...`);
}
}
const personFun = new Person('张嘀嗒', '男')
personFun.say() // 我是张嘀嗒,是一个男生...
每个构造函数的实例对象(personFun)都能通过 constructor 来找到构造函数(Person)本身
console.log('通过constructor找到实例的构造函数',personFun.constructor === Person);//true
此时我们可以使用函数对象的 prototype 属性来给构造函数预定义属性,prototype 可以理解为就是构造函数的原型对象
function Car(){
Car.prototype.name = '奔驰'
Car.prototype.color = '白色'
Car.prototype.say = function(){
console.log(`我的牌子是${this.name},颜色是${this.color}`);
}
}
const carFun = new Car()
carFun.say() // 我的牌子是奔驰,颜色是白色
我们用更简洁直观的方式讲解函数的 prototype 属性:
- 原型对象就是一个普通对象,用法也是和普通对象一样
- 构造函数的原型对象里面的方法是共有的方法,所有对应的 new 出来的实例对象都能调用原型对象里面的方法
- prototype 里面保存着可以被实例共享的方法,此外里面还会有一个 constructor 的属性指向该原型对象的构造函数
用法示例:
function Dog(){}
Dog.prototype = {
name: '旺财',
color: '黑白灰',
say(){
console.log(`原型对象:我的名字是${this.name},颜色是${this.color}`);
}
}
const dogFun = new Dog()
dogFun.say() // 原型对象:我的名字是旺财,颜色是黑白灰
在一般情况下,所有的原型对象 prototype 都有一个自带的 constructor 属性,
- constructor 是一个指针,指向该 prototype 属性所在的函数 [Person, Car, Dog]
- 也就是说 Person.prototype.constructor == Person
- 此时,我们可以看到在最上面构造函数那里,构造函数的实例对象也有 constructor 属性
- 由此可以引申出--> Person.prototype.constructor === personFun.constructor === Person
- 关于为什么实例对象会直接有 constructor 属性,而且为什么和原型对象的指向是一样的,可以理解为在创建示例对象的时候执行了如下示例(帮助理解,不能运行):
--->const personFun = new Person()
--->Person.prototype = personFun
js 在新建对象的时候(包括函数对象和普通对象),都会内置一个 proto 的内置属性用于指向 创建该对象的构造函数的原型对象,所以:
console.log('__proto__指向该对象的构造函数的原型对象', personFun.__proto__ === Person.prototype); // true
console.log('__proto__指向该对象的构造函数的原型对象2', personFun.__proto__.constructor === Person.prototype.constructor === Person); // true
所以得出以下结论:
* __proto__是什么?
* 因为 personFun.__proto__ === personFun.prototype === Person
* 所以 __proto__ 指向 构造函数的原型对象 prototype,可称为隐式原型
*
* 一点区别:
* 对象数据都有 __proto__属性指向该对象的构造函数的原型对象
* 函数对象既有 __proto__ 指向该实例对象的改造函数的原型对象,还有 prototype 属性(原型对象本身)直接指向原型对象
代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//构造函数
function Person(name, gender){
this.name = name
this.gender = gender
this.say = function(){
console.log(`我是${name},是一个${gender}生...`);
}
}
const personFun = new Person('张嘀嗒', '男')
personFun.say() // 我是张嘀嗒,是一个男生...
//每个构造函数的实例对象都能通过 constructor 来找到构造函数本身
console.log('通过constructor找到实例的构造函数',personFun.constructor === Person);
//利用函数对象的 prototype 属性给构造函数预定义属性,prototype ---> 原型对象
function Car(){
Car.prototype.name = '奔驰'
Car.prototype.color = '白色'
Car.prototype.say = function(){
console.log(`我的牌子是${this.name},颜色是${this.color}`);
}
}
const carFun = new Car()
carFun.say() // 我的牌子是奔驰,颜色是白色
/**
* 用更简洁直观的方式讲解函数的 prototype 属性 ---> 原型对象就是一个普通对象,用法也是和普通对象一样
* 构造函数的原型对象里面的方法是共有的方法,所有对应的 new 出来的实例对象都能调用原型对象里面的方法
* prototype 里面保存着可以被实例共享的方法,此外里面还会有一个 constructor 的属性指向该原型对象的构造函数
* */
function Dog(){}
Dog.prototype = {
name: '旺财',
color: '黑白灰',
say(){
console.log(`原型对象:我的名字是${this.name},颜色是${this.color}`);
}
}
const dogFun = new Dog()
dogFun.say() // 原型对象:我的名字是旺财,颜色是黑白灰
/**
* 在一般情况下,所有的原型对象 prototype 都有一个自带的 constructor 属性,
* constructor 是一个指针,指向该 prototype 属性所在的函数 [Person, Car, Dog]
* 也就是说 Person.prototype.constructor == Person
* 此时,我们可以看到在最上面构造函数那里,构造函数的实例对象也有 constructor 属性
* 由此可以引申出--> Person.prototype.constructor === personFun.constructor === Person
* 关于为什么实例对象会直接有 constructor 属性,而且为什么和原型对象的指向是一样的,可以理解为在创建示例对象的时候执行了如下示例(帮助理解,不能运行):
* --->const personFun = new Person()
* --->Person.prototype = personFun
* */
//js 在新建对象的时候(包括函数对象和普通对象),都会内置一个 __proto__ 的内置属性用于指向 创建该对象的构造函数的原型对象,所以:
console.log('__proto__指向该对象的构造函数的原型对象', personFun.__proto__ === Person.prototype); // true
console.log('__proto__指向该对象的构造函数的原型对象2', personFun.__proto__.constructor === Person.prototype.constructor === Person); // true
/**
* 所以得出以下结论:
* __proto__是什么?
* 因为 personFun.__proto__ === personFun.prototype === Person
* 所以 __proto__ 指向 构造函数的原型对象 prototype,可称为隐式原型
*
* 一点区别:
* 对象数据都有 __proto__属性指向该对象的构造函数的原型对象
* 函数对象既有 __proto__ 指向该实例对象的改造函数的原型对象,还有 prototype 属性(原型对象本身)直接指向原型对象
*
*/
let num = Number.constructor === Function
console.log(num);
</script>
</body>
</html>
图示:
图解:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。