javascript原型和原型链
一、Javascript数据类型
1、基本数据类型:Number String Boolean Null Undefined
站在用户的角度思考问题,与客户深入沟通,找到文圣网站设计与文圣网站推广的解决方案,凭借多年的经验,让设计与互联网技术结合,创造个性化、用户体验好的作品,建站类型包括:网站设计、成都网站制作、企业官网、英文网站、手机端网站、网站推广、域名注册、网页空间、企业邮箱。业务覆盖文圣地区。
基本数据类型是按值访问的,因为可以直接操作保存在变量中的实际值
var a = 10;
var b = a;
b = 20;
console.log(a); // 10值 b的改变对a没有影响
上面,b获取的是a值得一份拷贝,虽然,两个变量的值相等,但是两个变量保存了两个不同的基本数据类型值。
b只是保存了a复制的一个副本。所以,b的改变,对a没有影响。
2、引用类型数据:也就是对象类型Object type,比如:Object 、Array 、Function 等。
不可以直接访问堆内存空间中的位置和操作堆内存空间,只能操作对象在栈内存中的引用地址
所以,引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址。通过这个引用地址可以快速查找到保存在堆内存中的对象。
var obj1 = new Object();
var obj2 = obj1;
obj2.name = "我有名字了";
console.log(obj1.name); // 我有名字了 obj2的改变影响了obj1,因为obj1,obj2指向同一块内存地址
说明这两个引用数据类型指向了同一个堆内存对象。obj1赋值给onj2,实际上这个堆内存对象在栈内存的引用地址复制了一份给了obj2,
但是实际上他们共同指向了同一个堆内存对象。实际上改变的是堆内存对象。
二、JavaScript 中,万物皆对象!但对象也是有区别的。分为普通对象和函数对象。
凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。
Object 、Function 是 JavaScript 自带的函数对象。Object也是函数!
var o1 = {};
var o2 =new Object();
var o3 = new f1();
function f1(){};
var f2 = function(){};
var f3 = new Function('str','console.log(str)');
console.log(typeof Object); //function
console.log(typeof Function); //function
console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof f3); //function
console.log(typeof o1); //object
console.log(typeof o2); //object
console.log(typeof o3); //object
三、构造函数
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() { alert(this.name) }
}
var person1 = new Person('Zaxlct', 28, 'Software Engineer');
var person2 = new Person('Mick', 23, 'Doctor');
person1 和 person2 都是 Person 的实例
这两个实例都有一个 constructor (构造函数)属性,该属性(是一个指针)指向 Person。即:
console.log(person1.constructor == Person); //true
console.log(person2.constructor == Person); //true
我们要记住两个概念(构造函数,实例):
person1 和 person2 都是 构造函数 Person 的实例
一个公式:
实例的构造函数属性(constructor)指向构造函数。
person1.constructor == Person
四、原型对象 Person.prototype,主要是为了实现继承和共享属性;
function Person(){}
函数是指构造函数,对象or实例是new之后的
每个函数对象都有一个prototype 属性,即Person.prototype,这个属性指向函数的原型对象(一个普通对象)。
【公式一】:每个对象都有 proto属性,但只有函数对象才有 prototype 属性
原型对象,顾名思义,它就是一个普通对象(废话 = =!)。从现在开始你要牢牢记住:
原型对象就是 Person.prototype
它有一个默认的属性:constructor(构造函数属性),这个属性(是一个指针)指向 prototype 属性所在的函数(Person)
即:Person.prototype.constructor == Person
【结论】:原型对象(Person.prototype)是 构造函数(Person)的一个实例。
五、proto
JS 在创建对象(普通对象、函数对象)的时候,该对象都有proto的内置属性,用于指向创建它的构造函数的原型对象。
对象 person1 有一个 proto属性,创建它的构造函数是 Person,构造函数的原型对象是 Person.prototype
即:person1.proto== Person.prototype
person1.proto== person1的构造函数.prototype
【总结】
Person.prototype.constructor == Person;
person1.__proto__ == Person.prototype;
Person.prototype.__proto__== Object.prototype;
//Person.prototype 是一个普通对象,我们无需关注它有哪些属性,只要记住它是一个普通对象。一个普通对象的构造函数 === Object
person1.constructor == Person;
不过,要明确的真正重要的一点就是,这个连接存在于实例(person1)与构造函数(Person)的原型对象(Person.prototype)之间,而不是存在于实例(person1)与构造函数(Person)之间。
六、
//注意这个
function f1(){};
var f2 = function(){};
var f3 = new Function('str','console.log(str)');
console.log(typeof Object); //function
console.log(typeof Function); //function
console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof f3); //function
两个注意事项:
- proto和constructor属性是对象所独有的
- prototype属性是函数所独有的。但是由于JS中函数也是一种对象,所以函数也拥有proto和constructor属性
- JS 在创建对象(普通对象、函数对象)的时候,该对象都有proto的内置属性,用于指向创建它的构造函数的原型对象。
即:person1.proto == person1的构造函数.prototype
1、我们看proto属性:
右边
function Foo(){...};
let f1 = new Foo();
typeof f1; //"object"
typeof Foo; //"function"
Function.__proto__ == Function.prototype; //true
Function.__proto__ == Object.prototype; //false
Foo.__proto__ == Function.prototype; //true,Foo的构造函数是Function
Object.__proto__ == Function.prototype; //true,Object的构造函数是Function
左边:
f1.constructor == Foo; //true,f1的构造函数是Function
f1.__proto__ == Foo.prototype; //true,f1的构造函数是Function
Foo.prototype.__proto__ == Object.prototype; //true Foo.prototype原型对象,整体看成一个普通对象,构造函数是Object
Object.prototype.__proto__ == null;
【总结】第一,这里我们仅留下proto属性,它是对象所独有的,可以看到proto属性都是由一个对象指向一个对象,即指向它们的原型对象(也可以理解为父对象),那么这个属性的作用是什么呢?它的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的proto属性所指向的那个对象(可以理解为父对象)里找,如果父对象也不存在这个属性,则继续往父对象的proto属性所指向的那个对象(可以理解为爷爷对象)里找,如果还没找到,则继续往上找….直到原型链顶端null(可以理解为原始人。。。),此时若还没找到,则返回undefined(可以理解为,再往上就已经不是“人”的范畴了,找不到了,到此为止),由以上这种通过proto属性来连接对象直到null的一条链即为我们所谓的原型链。
原型链和proto有关系,和prototype没关系
2、prototype属性:
每个函数对象都有一个prototype 属性,即Person.prototype,这个属性指向函数的原型对象(一个普通对象)。
原型对象,顾名思义,它就是一个普通对象(废话 = =!)。从现在开始你要牢牢记住:
原型对象就是 Person.prototype
它是函数所独有的,它是从一个函数指向一个对象。它的含义是函数的原型对象,也就是这个函数(其实所有函数都可以作为构造函数)所创建的实例的原型对象,
由此可知:f1.proto=== Foo.prototype,它们两个完全一样。那prototype属性的作用又是什么呢?它的作用就是包含可以由特定类型的所有实例共享的属性和方法,也就是让该函数所实例化的对象们都可以找到公用的属性和方法。
3、看一下constructor属性:
constructor属性也是对象才拥有的,它是从一个对象指向一个函数,含义就是指向该对象的构造函数,每个对象都有构造函数,从图中可以看出Function这个对象比较特殊,它的构造函数就是它自己(因为Function可以看成是一个函数,也可以是一个对象),所有函数最终都是由Function()构造函数得来,所以constructor属性的终点就是Function()。
七、总结一下
我们需要牢记两点:①proto和constructor属性是对象所独有的;② prototype属性是函数所独有的,因为函数也是一种对象,所以函数也拥有proto和constructor属性。
proto属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的proto属性所指向的那个对象(父对象)里找,一直找,直到proto属性的终点null,然后返回undefined,通过proto属性将对象连接起来的这条链路即我们所谓的原型链。
prototype属性的作用就是让该函数所实例化的对象们都可以找到公用的属性和方法,即f1.proto=== Foo.prototype。
- constructor属性的含义就是指向该对象的构造函数,所有函数(此时看成对象了)最终的构造函数都指向Function()。
八、prototype和proto的关系是什么?
首先,要明确几个点:
1.在JS里,万物皆对象。方法(Function)是对象,方法的原型(Function.prototype)是对象。因此,它们都会具有对象共有的特点。
即:对象具有属性proto,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。
2.方法(Function)
方法这个特殊的对象,除了和其他对象一样有上述_proto_属性之外,还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。
function Foo(){...};
let f1 = new Foo();
let f2 = new Foo();
Foo():是构造函数,
Foo.prototype:是原型对象,保存着实例共享的方法,所有构造函数声明的实例(这里是f1,f2)都可以共享这个方法。
同时,该原型对象有一个指针constructor指回构造函数。
即:Foo.prototype.constructor == Foo
比如:Foo.prototype.num = 10; 这个属性num是绑定在Foo.prototype下面的,实例f1下面没有这个属性,但是实例
f1.proto== Foo.prototype,所以,f1通过proto就可以到达Foo.prototype上,寻找Foo.prototype下面是否有这个属性,
假如Foo.prototype下面也没有这个属性,那么通过Foo.prototype.proto== Object.prototype; 假如在Object.prototype上面还没有找到,那么由于Object.prototype.proto==null; 也就是说Object.prototype.proto上面没有大佬了,那么就返回undefined
对于实例f1和f2而言:
f1.proto== Foo.prototype;
f2.proto== Foo.prototype;
f1和f2是Foo这个对象的两个实例,这两个对象也有属性proto,指向构造函数的原型对象,这样子就可以像上面1所说的访问原型对象的所有方法了。
另外:
构造函数Foo()除了是方法,也是对象啊,它也有proto属性,指向谁呢?
指向它的构造函数的原型对象呗。函数的构造函数不就是Function嘛,因此这里的Foo.proto指向了Function.prototype。
其实除了Foo(),Function(), Object()也是一样的道理。
原型对象也是对象啊,它的proto属性,又指向谁呢?
同理,指向它的构造函数的原型对象呗。这里是Object.prototype.
最后,Object.prototype的proto属性指向null。
总结:
1.对象有属性proto,指向该对象的构造函数的原型对象。
2.方法除了有属性proto,还有属性prototype,prototype指向该方法的原型对象
九、
1、hasOwnProperty : 看是不是对象自身下面的属性,属于Object身上的方法
var arr = [];
arr.num = 10;
Array.prototype.num2 = 20;
//alert( arr.hasOwnProperty('num') ); //true
alert( arr.hasOwnProperty('num2') ); //false
2、constructor : 查看对象实例的构造函数
function Aaa(){}
var a1 = new Aaa();
alert( a1.constructor ); //Aaa
可以用来判断某一个实例是否是某一个对象类型
var arr = [];
//下面是两种判断方法
console.log( arr.constructor == Array ); //true
console.log( arr instanceOf Array ); //true
原理:
function Aaa(){}
系统自动加上:Aaa.prototype.constructor = Aaa; //每一个函数定义的时候就自动生成,都会有
这样Aaa.prototype原型对象上就具有constructor这个属性了
对于let a1 = new Aaa();的a1实例来说,根据原型链的关系,a1身上没有constructor属性,利用proto向上查找,a1.proto= Aaa.prototype,
a1就具有了constructor属性,且值为Aaa
即 a1.constructor == Aaa //true
a1.proto.constructor == Aaa //true
3、 instanceof:是运算符,不是面向对象的属性和方法,和for、if、加减乘除等一样都是运算符
判断:对象与构造函数在原型链上是否有关系,是否在同一条原型链上
function Aaa(){
}
var a1 = new Aaa();
//alert( a1 instanceof Object ); //true
var arr = [];
alert( arr instanceof Array ); //true
4、toString
位置:系统对象本身就有这个属性,即系统对象下面是自带的,比如Array下面就有这个属性,不用到Object上面找了
Array.prototype.toString
对于自己写的对象来说,本身下面是没有这个属性的,是通过原型链到Object.prototype下面找到的,注意区别
function Aaa(){}
let a1 = new Aaa();
a1下面也有这个属性,是通过原型链找到的
用法1:把对象转为字符串
var arr = [1,2,3];
alert( arr.toString() ); //'1,2,3'
用法2:数字转十六进制
//var num = 255;
//alert( num.toString(16) ); //'ff'
用法3:利用toString做类型的判断 :
var arr = [];
alert( Object.prototype.toString.call(arr) == '[object Array]' ); // true
5、类型判断,比如判断arr是不是数组类型,可以使用constructor、instanceof、toString判断,使用typeof是判断不出来的
let arr = [];
arr.constructor == Array // true
arr instanceof Array //true
Object.prototype.toString.call(arr) == '[object Array]' //true
本文题目:javascript原型和原型链
文章地址:http://azwzsj.com/article/pchcoo.html