这里是修真院前端小课堂,每篇分享文从
【背景介绍】【知识剖析】【常见问题】【解决方案】【编码实战】【扩展思考】【更多讨论】【参考文献】
八个方面深度解析前端知识/技能。
本篇分享的是:【简述原型链是什么,有什么用处?】
简述原型链是什么,有什么用处?若想访问一个对象的原型,应该使用什么方法?
开场语:
大家好,我是IT修真院上海分院的王刚,一枚正直纯洁善良的前端程序员,
今天给大家分享一下,修真院官网JS任务2,深度思考中的知识点——
简述原型链是什么,有什么用处?若想访问一个对象的原型,应该使用什么方法?
(1)背景介绍:
JavaScript本身不提供类实现。 (在ES2015/ES6中引入了class关键字,但是只是语法糖,JavaScript 仍然是基于原型的)。 通过原型这种机制,JavaScript 中的对象从其他对象继承功能特性。
我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。那么,prototype就是通过调用构造函数而创建的那个对象实例的原型对象。
使用原型的好处是可以让对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中添加定义对象信息,而是可以直接将这些信息添加到原型中。使用构造函数的主要问题就是每个方法都要在每个实例中创建一遍。
在JavaScript中,一共有两种类型的值,原始值和对象值。每个对象都有一个内部属性 prototype ,我们通常称之为原型。原型的值可以是一个对象,也可以是null。如果它的值是一个对象,则这个对象也一定有自己的原型。这样就形成了一条线性的链,我们称之为原型链。
(2)知识剖析:
PROTOTYPE属性
每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。那么,prototype就是通过调用构造函数而创建的那个对象实例的原型对象。
函数可以用来作为构造函数来使用。另外只有函数才有prototype属性并且可以访问到,但是对象实例不具有该属性,只有一个内部的不可访问的__proto__属性。__proto__是对象中一个指向相关原型的神秘链接。__proto__是不对外公开的,也就是说是个私有属性.
var Browser = function(){};
Browser.prototype.run = function(){
alert("这是原型对象");
}
var Bro = new Browser();
Bro.run();
当我们调用Bro.run()方法时,由于Bro中没有这个方法,所以,他就会去他的__proto__中去找,也就是Browser.prototype,所以最终执行了该run()方法。(在这里,函数首字母大写的都代表构造函数,以用来区分普通函数)
当调用构造函数创建一个实例的时候,实例内部将包含一个内部指针(__proto__)指向构造函数的prototype,这个连接存在于实例和构造函数的prototype之间,而不是实例与构造函数之间。
function Person(name){ //构造函数
this.name=name;
}
Person.prototype.printName=function() //原型对象
{
alert(this.name);
}
var person1=new Person('Byron');//实例化对象
console.log(person1.__proto__);//Person
console.log(person1.constructor);//指向构造函数
console.log(Person.prototype);//指向原型对象Person
var person2=new Person('Frank');
Person的实例person1中包含了name属性,同时自动生成一个__proto__属性,该属性指向Person的prototype,可以访问到prototype内定义的printName方法
构造函数、实例和原型对象
每个JavaScript函数都有prototype属性,这个属性引用了一个对象,这个对象就是原型对象。原型对象初始化的时候是空的,我们可以在里面自定义任何属性和方法,这些方法和属性都将被该构造函数所创建的对象继承。
实例就是通过构造函数创建的。实例一创造出来就具有constructor属性(指向构造函数)和__proto__属性(指向原型对象),
构造函数中有一个prototype属性,这个属性是一个指针,指向它的原型对象。
原型对象内部也有一个指针(constructor属性)指向构造函数:Person.prototype.constructor = Person;
实例可以访问原型对象上定义的属性和方法。
在这里person1和person2就是实例,prototype是他们的原型对象。
function Animal(name) //基类构造函数
{
this.name = name;//设置对象属性
}
Animal.prototype.behavior = function() //给基类构造函数的prototype添加behavior方法
{
alert("this is a "+this.name);
}
var Dog = new Animal("dog");//创建Dog对象
var Cat = new Animal("cat");//创建Cat对象
Dog.behavior();//通过Dog对象直接调用behavior方法
Cat.behavior();//output "this is a cat"
alert(Dog.behavior==Cat.behavior);//output true;
可以从程序运行结果看出,构造函数的prototype上定义的方法确实可以通过对象直接调用到,而且代码是共享的。
原型链
当从一个对象那里调取属性或方法时,如果该对象自身不存在这样的属性或方法,就会去自己关联的prototype对象那里寻找,如果prototype没有,就会去prototype关联的前辈prototype那里寻找,如果再没有则继续查找Prototype.Prototype引用的对象,依次类推,直到Prototype.….Prototype为undefined(Object的Prototype就是undefined)从而形成了所谓的“原型链”。
function Father(){ //被继承的函数叫做超类型(父类,基类)
this.name = "Jack";
}
function Son(){ //继承的函数叫做子类型(子类,派生类)
this.age = 10;
}
//通过原型链继承,赋值给子类型的原型属性
//new Father()会将father构造里的信息和原型里的信息都交给Son
Son.prototype = new Father();//Son继承了Father,通过原型,形成链条
var son = new Son();
alert(son.name);//弹出 Jack
(3)常见问题:
__proto__属性和prototype属性的区别
(4)解决方案:
prototype是function对象中专有的属性。
__proto__是普通对象的隐式属性,在new的时候,会指向prototype所指的对象;
__ptoto__实际上是某个实体对象的属性,而prototype则是属于构造函数的属性。__ptoto__只能在学习或调试的环境下使用。
(5)编码实战:
(6)拓展思考:
Function 也是构造函数? 所以function.__proto__指向Function.prototype?
Function是构造函数,所有函数都是Function的实例,所有函数的__proto__的都是指向Object的原型对象
(7)参考文献:
1.JavaScript高级程序设计
2.head first JavaScript
(8)更多讨论:
1、若想访问一个对象的原型,应该使用什么方法?
a. obj.__proto__
b. obj.constructor.prototype
c. Object.getPrototypeOf(obj)
上面三种方法之中,前两种都不是很可靠。最新的ES6标准规定,
__proto__属性只有浏览器才需要部署,其他环境可以不部署。
而obj.constructor.prototype在手动改变原型对象时,可能会失效。
2、[[prototype]]这个属性能访问到吗?
这个实例的内部属性,是一个指针指向构造函数的原型对象,我们是访问不到这个属性的。
只能通过__proto__方法原型对象。
3、构造函数用来生成对象的过程是什么样的?
a、隐式创建一个对象
b、将构造函数的作用域指向这个对象(this)指向这个对象
c、执行构造函数里面的代码
d、返回这个对象
(9)鸣谢:
感谢顾配如,周能师兄,此教程是在他们之前技术分享的基础上完善而成。
(10)结束语:
PPT链接 视频链接
今天的分享就到这里啦,欢迎大家点赞、转发、留言、拍砖~
------------------------------------------------------------------------------------------------------------
“我们相信人人都可以成为一个工程师,现在开始,找个师兄,带你入门,学习的路上不再迷茫。
技能树.IT修真院