先理清proto、prototype、constructor
首先,我们需要牢记两点:
① proto和constructor属性是对象所独有的;
② prototype属性是函数所独有的。 但是由于JS中函数也是一种对象,所以函数也拥有proto和constructor属性
proto属性都是由一个对象指向一个对象,即指向它们的原型对象(也可以理解为父对象)
__proto__
属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__
属性所指向的那个对象(父对象)里找,一直找,直到__proto__
属性的终点null,再往上找就相当于在null上取值,会报错。通过__proto__
属性将对象连接起来的这条链路即我们所谓的原型链。- constructor属性也是对象才拥有的,它是从一个对象指向一个函数,含义就是指向该对象的构造函数
- prototype属性,它是函数所独有的,它是从一个函数指向一个对象。它的含义是函数的原型对象,也就是用这个构造函数创建的实例的原型对象
每个对象都有构造函数是指每个对象都可以找到其对应的constructor,
这个constructor可能是对象自己本身显式定义的或者通过proto在原型链中找到的
而单从constructor这个属性来讲,只有prototype对象才有。函数创建的对象.__proto__ === 该函数.prototype
,该函数.prototype.constructor===该函数本身
一、prototype[原型对象]
- 大部分函数数据类型的值都具备 prototype(原型/显式原型)属性,属性值本身是一个对象
- 浏览器会默认为prototype开辟一个堆内存,用来存储:
- 可以调用的公共的 属性和方法
- 当前类所属实例proto
- 在浏览器默认开辟的这个堆内存中
- 「原型对象」有一个默认的属性“constructor(构造函数/构造器)”,属性值是当前函数/类本身!!
**fn.prototype.constructor === fn // true**
```javascript function A(){ this.name =name //(该属性,强调私有,不共享) } A.prototype.say = function(){ //定义在原型上的方法(强调复用。需要共享) console.log = (‘hello’) }
- 浏览器会默认为prototype开辟一个堆内存,用来存储:
// 不推荐写法: A.prototype = { say:function(){ console.log = (‘hello’)} } // 因为会丢失constructor属性
```javascript
function Person () {
this.name = 'John';
}
var person = new Person();
Person.prototype = {
say: function() {
console.log('Hello,' + this.name);
}
};
person.say();//person.say is not a function
原文链接:https://blog.csdn.net/kkkkkxiaofei/article/details/46474303
- 内置对象例如Array、Object、Boolean、String、等都可以通过new 实例化 所有都有 prototype这属性 可以用来扩展一些方法和属性;
注意:Math没有prototype 因为:
我们都知道 Boolean、Map 等都可以通过new Boolean() 调用,但是调用 new Math() 会得到 TypeError: Math is not a constructor 因为 Boolean Map 继承自 Function对象,而 Function 对象是有 Construct 的。而 Math只继承了 Object,并没有继承Function。
- 可以看到内置类Array里面的constructor指向了Array
// prototype 是内置类 Array 的一个私有属性???同时是公有的吗
console.log('prototype' in Array); // true
console.log(Array.hasOwnProperty("prototype")); // true
Array.hasOwnProperty("__proto__") //false
var arr = new Array()
arr.hasOwnProperty('__proto__') //false 它不能来自链中的任何对象,因为它特定于这个对象。
// __ proto __ 是一个继承自 Object.prototype 的 setter / getter,它不是拥有属性
关于是否所有函数都有prototype一说
使用Function.prototype.bind创建的函数对象
function abc(){console.log('abc')}
var binded = abc.bind(null)
binded() //abc
console.log(binded.prototype) //undefined
bind
一般的用法是fn.bind(obj)
,然后返回的是绑定obj内容上下文(this指向obj)的fn。如果obj为空的话,则this指向window,如下:因此Function.prototype.bind()
其实就是Function.prototype
于是我现在有了一个疑问Function.prototype到底是不是函数呢Function.prototype instanceof Function //false
typeof Object.prototype //object
Object.prototype.toString.call(Function.prototype) //[object Function]
Function.prototype.bind.call(Function.prototype) //ƒ () { [native code] }
箭头函数也没有
var abc = ()=>{console.log('abc')}
abc() //abc
console.log(abc.prototype) //undefine
函数需要prototype主要是用来做构造函数,构造实例,否则没啥用
- 函数数据类型
- 普通函数(实名或匿名函数)
- 箭头函数
- 构造函数/类
- 生成器函数 Generrator
- 不具备prototype的函数
- 箭头函数
_const fn=()=>{}_
- 基于
ES6
给对象某个成员赋值函数值的快捷操作 ```javascript let obj = { fn1: function () { // 常规写法 具备prototype属性 }, fn2() { // 快捷写法 不具备prototype属性 } };
- 箭头函数
class Fn { fn() {} //这样的也不具备prototype属性 };
<a name="NtZKv"></a>
## 二、__ _proto___ [原型链]
1. 每一个“**对象数据类型**”的值都具备一个**属性**“**__proto__(原型链/隐式原型)**”
1. 属性值指向“**当前对象的 构造函数的 prototype**”
1. 对象上天生具备一个属性:**constructor**,指向类本身
1. 对象数据类型值(**万物皆对象**)
1. 普通对象
1. 特殊对象:数组、正则、日期、Math、Error...
1. 函数对象
1. 实例对象
1. 构造函数**.**prototype
1. 当我们不知道当前对象是谁的实例,那么就是 Object的实例 [ Object就指向null,因为它是基类]
1. **原型链机制 **
1. 首先访问自己的私有属性,如果私有属性中存在,就直接使用私有的
1. 如果访问的成员私有属性中没有,默认惠基于__proto__找到所属类prototype上的属性/方法
1. 如果所属类的prototype也没有,就基于prototype.__prototype__向上查找,一直找到Object.prototype为止
1. 这种**成员访问机制**,被称为“**原型链机制**”
1. 公有私有
1. 公有:原型的属性
1. 私有:自己的属性
<a name="YECiA"></a>
### 方法调用
```javascript
// 几个访问方式
arr.forEach(...) // 正常调用
arr.__proto__.forEach(...) // 直接跳过私有的
Array.prototype.forEach(...) // 直接找原型的
// 三者区别在于forEach方法中的this
// 点前面是谁就是谁
方法执行查找
let arr = [10, 20, 30];
console.log(arr.hasOwnProperty('forEach')); //->false
简称:验证“forEach”是否为arr对象的私有属性
全称:arr按照原型链查找机制,找到的是Object.prototype.hasOwnProperty方法「@A」,并且把找到的@A执行
+ 方法中的this->arr「我们要操作的对象」
+ 传递的实参->“forEach”「我们要验证的属性」
@A方法的作用是,验证“实参”是否为当前“this”的一个私有属性
例一:
直接找到方法(可以改变this指向) ===> Object.prototype.hasOwnProperty.call(arr,'forEach')
例二:
arr.push(100);
内部:Array.prototype.push.call(arr, 100)
案例
function Fn() {
this.x = 100;
this.y = 200;
this.getX = function () {
console.log(this.x);
};
}
Fn.prototype.getX = function () {
console.log(this.x);
};
Fn.prototype.getY = function () {
console.log(this.y);
};
let f1 = new Fn;
let f2 = new Fn;
console.log(f1.getX === f2.getX); // false 两个私有函数 不同堆
console.log(f1.getY === f2.getY); // true 都是原型链的公有函数 相同堆
console.log(f1.__proto__.getY === Fn.prototype.getY); // true 都是原型链的公有函数 相同堆
console.log(f1.__proto__.getX === f2.getX); // false 一个公有,一个私有 不同堆
console.log(f1.getX === Fn.prototype.getX); // false 一个私有,一个公有 不同堆
console.log(f1.constructor); // Fn 获得直属类信息
console.log(Fn.prototype.__proto__.constructor); // Object
// 1. 确定执行的是哪个方法
// 2. 确定方法中的this “点字则”
f1.getX(); // 100 私有的方法 this指向f1
f1.__proto__.getX(); // undefined 公有的方法 this指向f1
f2.getY(); // 200 公有的方法 this指向f2
Fn.prototype.getY(); // undefined 公有的方法 this指向Fn