原型
原型是什么
原型是 function 对象的一个属性,它定义了构造函数制造出的对象的公共祖先。 通过该构造函数产生的对象,可以集成该原型的属性和方法 原型也是对象
function Person() {
}
Person.prototype = {};
// 1:prototype是function 的一个属性
// 2:prototype是一个对象
Person.prototype.run= function(){
console.log("person 会 run ")
}
function student() {}
student.prototype = {}
利用原型的特点 和概念,可以提取共有属性
原型的增删改查
增
和操作对象一样 Person.prototype.属性 = 属性值;
构造函数名.prototype.要增加在原型上的属性名 = ‘值’
删
delete Person.prototype.属性
delete 构造函数名.prototype.要删除的原型上的属性名
改
直接再赋值 即可修改
person1.lastName = "li";
构造函数名.prototype.要修改的原型上的属性名 = ‘值’
查
访问属性方法 就近原则
function Person() {
}
Person.prototype = {};
Person.prototype.lastName = "zhang"
let person1 = new Person();
person1.lastName = "wang";
console.log( person1.lastName) ----->wang
原型上方法中this的指向
Person.prototype = {
name = 'a',
sayName : function(){
console.log(this.name);
}
}
function Person(){
this.name = 'b';
}
var person = new Person();
sayName 里面的this指向是,谁调用的这个方法,this指向谁;
所以最终结果person.sayName() 的值为b
而Person.prototype.sayName() 的值为a
对象如何查看对象的构造函数
----constructor
var a = {}
a.constructor
----> ƒ Object() { [native code] }
function Person(){}
var p1 = new Person();
p1.constructor
---------->ƒ Person(){}
var a = 1;
a.constructor
------>ƒ Number() { [native code] }
var a ="str"
a.constructor
------> ƒ String() { [native code] }
function a(){}
a.constructor
------>ƒ Function() { [native code] }
a 是一个函数,函数本质上也是一个对象,它是通过 内置的Function 函数构造的,
它的constructor属性指向它的构造函数Function
function a(){}
a.constructor
----->ƒ Function() { [native code] }
Function.constructor
-------->ƒ Function() { [native code] } 内置对象Function的构造函数是它自己
a.prototype.constructor
ƒ a(){}
function a(){}
a.prototype = {}
a.prototype.constructor
----->ƒ Object() { [native code] }
a.prototype.constructor ={name: "str"}
a.prototype
展开对象:
----> constructor: {name: "str"}
----> __proto__: Object
constructor,我们可以手动改变它的指向哈哈哈
验证:
var a1=new a();
a1.constructor
----->{name: "str"}
constructor是对象身上的属性,用来查看它的构造函数是哪个的
结论: prototype 是 函数身上的属性 是一个对象,函数身上是没有constructor 属性
pertotype 与constructor的关系
pertotype 是一个对象
这个对象身上有一个内置的属性,constructor,
constructor 中文翻译叫 构造器,
constructor 指向的是 该对象的构造函数,即它是谁造出来的
《constructor的定义是要指向原型属性对应的构造函数的》
__proto__
是啥, 啥用
先看下__proto__在哪儿,是个什么东西
function A(){}
var a = new A()
console.log(a)
输出A {}
展开 __proto__: Object
可以看到有一个内置的属性 __proto__:指向一个对象
发现 它是 (实例对象)/对象的一个属性
看下面两张图,来看看这个内置的属性 proto:指向的对象是什么
我们给原型加属性,最后发现给原型加的东西都可以在__proto__ 指向的对象中找到,于是得出结论,它指向的是构造函数的原型。
来看解释吧,
之前说构造函数原理的时候说,第一步会生成一个空的this = {},
其实在new的时候 隐式新建的this对象并不是空的
function A(){
var this = {
__proto__:A.prototype
}
}
var a = new A();
其实在new的时候 隐式新建的this对象并不是空的,而是里面有一个 __proto__属性,指向的是当前函数的原型
___proto___有什么用呢
当你访问 这个对象的属性时,如果你没有这个属性,系统就会通过__proto__ 指向的索引,去找你访问的属性
相当于一个连接的作用
比如 当访问 a.name 的时候,a对象身上没有name 属性,就会去找 ___proto___指向的那个对象(原型) 身上有没有name属性
为什么说 对象访问属性的时候先访问自己,没有还可以访问原型身上的属性呢,就是因为有___proto__
___proto___指向可手动更改
图一
图一 可看得出:___proto___指向可手动更改可手动去改变
图 二
图二 是修改了属性值,所以 输出的是 456
图 三
图三 是换血了啊,
___proto__指向的对象的引用是A.prototype.name = "123";
即便A.prototyp 换了对象, ___proto_\的引用不变
是先new的,再A的prototype 换了,所以 ___proto__指向的对象的引用不变
比如: var arr = [1,2]
var arr1 = arr ;
arr = [1,3];
此时 arr1 仍然是[1,2]
图四
调整下顺序 A的prototype 换了指向后,再new
如下图
原型链
function Grand() {}
Grand.prototype.lastName = "li";
var grand = new Grand();
function Father() {}
Father.prototype = grand;
var father = new Father();
function Son() {}
Son.prototype = father;
var son = new Son();
son.lastName;------>"li"
把各个原型连在一起,就形成了原型链,连接点: ___proto__
son身上没有lastName属性,于是就通过__proto__一层一层往上找,形成的这个链就是原型链 绝大多数对象的最终都会继承自Object.prototype
但不是所有的对象都可以继承,特例:Object.creat()原型;
例如:object.creat(null) ,该对象没有prototype原型;
![]
原型链上 属性的 增删改查
查:
就是一直往下找,找到为止,找不到就返回undefined
增
能给原型链上的任何一个原型增加它的属性吗?
仅限自己能够增加自己原型链上的属性
改
仅限自己能够修改自己原型链上的引用值得属性,原始值类型的属性无法修改
修改自己原型链上的引用值的属性
修改原始值类型的属性
删除
能给原型链上的任何一个原型删除它的属性吗?
仅限自己能够删除自己原型链上的属性
一个额外的知识点
123.toString();
会报错
是因为:
这句代码中把 . 当作浮点了,而不是方法调用的那个点,所以会报错
如果想要调用,可以写如下代码
var num = 123;
num.toString();
[ new Number(123).toString()] ------- 隐式调用
想改变返回的结果,可以重写:
Number.prototype.toString = function(){
//重写返回的自定义内容
return "今天重写了 Number身上的toString()方法 "
}
num.toString()
输出----》【 "今天重写了 Number身上的toString()方法 "】
Number.prototype.__proto__ = Object.prototype;
Object.prototype.toString.call(123)
输出 ---->
"[object Number]"
所以 为了输出更有意义的东西,我们有时会需要重写