web前端练习22----js中的原型对象prototype,原型链(重要)
Posted zhaihaohao1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了web前端练习22----js中的原型对象prototype,原型链(重要)相关的知识,希望对你有一定的参考价值。
原型对象 原理解析:
我们创建的每一个函数,解析器都会向函数中添加一个属性 prototype
这个属性对应着一个对象,就是原型对象。
如果函数作为普通函数,调用 prototype 没有任何作用
当函数以构造函数的形式调用时,它所创建的对象都会有一个隐含的属性 __proto__,
我们可以通过 __proto__ 来访问原型对象
原型对象就相当于一个公共区域,同一个构造函数的实例都能访问到这个原型对象
我们可以将对象共有的内容,统一设置到原型对象中
创建构造函数时,可以将对象共有的属性和方法,统一添加到构造函数的原型对象中,
这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了
当我们访问对象的一个属性或者方法时,他会先在对象自身中寻找,如果有则直接使用,
如果没有则会去原型对象中寻找,如果有则直接使用。
如果原型对象中也没有,则会在原型对象的原型对象中寻找,一层一层往上找,直到找到Object的原型对象,
如果没有,就没有这个属性或方法
图解:
下面写一些具体例子:
拿到原型对象:
// 拿到原型对象:
function method1()
// 构造函数
function Person()
// 原型对象
let yuanxing = Person.prototype;
// 实例化对象
let person1 = new Person();
// 通过对象找到原型对象 person1.__proto__
console.log(yuanxing == person1.__proto__);
// 任何对象都可以找到原型对象 person2.__proto__
let person2 = new Person();
console.log(yuanxing == person2.__proto__);
调用对象属性和方法,先在自身找,自身没有在原型对象中找
//调用对象属性和方法,先在自身找,自身没有在原型对象中找
function method2()
// 构造函数
function Person()
// 向原型对象中添加属性和方法
Person.prototype.name = 'zhh';
Person.prototype.method = function (args)
console.log('原型对象的方法>>>' + args);
// 调用对象属性和方法,先在自身找,自身没有在原型对象中找
let person1 = new Person();
let person2 = new Person();
console.log(person1.name = 'peson1');
person1.method('person1调用');
console.log(person2.name = 'perso2');
person2.method('person2调用');
原型对象也是对象,所以它也有原型(就是原型对象的原型对象)
当我们使用一个对象的属性或方法时,会先在自身找,
自身有,则直接使用
自身没有,则去原型对象中寻找,如果原型对象中有,则使用
如果原型对象中也没有,则去 原型对象的原型对象 中去寻找。
以此类推向上寻找,直到找到Object的原型对象,Object 的原型对象,没有原型对象,
如果依然没找到则返回 unedfined
function method3()
// 构造函数
function Person()
let person = new Person();
// person 对象中没有 toLocaleString() ; 调用的是原型对象中的方法
person.toLocaleString();
// 下面查找 toLocaleString() 在哪一级的原型对象里面
// hasOwnProperty() 对象自身是否含有某个属性或方法
// person 中是否有 toLocaleString 方法
console.log(person.hasOwnProperty('toLocaleString'));
// person的原型对象中是否有 toLocaleString 方法
console.log(person.__proto__.hasOwnProperty('toLocaleString'));
// person的原型对象的原型对象中是否有 toLocaleString 方法
// 打印结果是true
// 说明person.toLocaleString()调用的是person.__proto__.__proto__中的toLocaleString方法
console.log(person.__proto__.__proto__.hasOwnProperty('toLocaleString'));
OK,讲完了
下面是一个综合的例子:
<script>
// 构造函数
function Person()
// 拿到原型对象,原型对象是一个公共区域
// 构造函数的实例,都能访问到里面的属性和方法
let yuanxing = Person.prototype;
// 原型里面添加属性和方法
yuanxing.name = 'zhh';
yuanxing.say = function ()
console.log('原型对象中的方法');
// 实例化对象
let person1 = new Person();
// 调属性,先在自身找,自身没有在原型对象里找
console.log(person1.name);
// 调方法,先在自身找,自身没有在原型对象里找
person1.say();
// 调属性或方法,自身没有,原型对象中也没有,一层一层往上找
console.log(person1.toLocaleString());
</script>
下面对原型对象进行深层次的解析
1、原型对象在堆栈存储
看下面一段代码:
<script>
// 创建函数时内部语句
// this.prototype = ;
function Dog()
this.test1 = function()
console.log('test1方法');
// 拿到原型对象,并给原型对象添加方法
Dog.prototype.test2 = function()
console.log('test2方法');
// 实例化对象时内部语句
// this.__proto__=Dog.prototype
var dog = new Dog();
dog.test1();
dog.test2();
console.log(dog.toString());
dog.test3();
</script>
上面代码,堆栈是示意图,(很重要,这个图比上面Person示意图要详细)
2、构造函数和原型对象的相互指向
构造函数对象的 prototype 属性,指向原型对象
原型对象中的 constructor 指向构造函数对象
看下面一段代码:
<script>
// 构造函数和原型对象的相互指向
// 构造函数
function Type()
// 拿到原型对象,
// 构造函数对象的 prototype 属性,指向原型对象
// 原型对象就是一个 Object 的实例
let yuanxing = Type.prototype;
yuanxing.name = function() ;
// 原型对象中的 constructor 指向构造函数对象
console.log(yuanxing.constructor == Type);
</script>
图解:
3、几个重要概念和结论
I、两个概念:
1.显式原型对象 函数对象.prototype
2.隐式原型对象 实例对象.__proto__
II、Function 和Object 的三个重要结论
1、函数的原型对象都是Object的实例(但Object除外)
2、所有的函数对象都是 Function 的实例 (Function 是他自己的实例)
3、Object 的原型对象是原型链的尽头
上面3个结论的验证:
1、函数的原型对象都是Object的实例(但Object除外)
/*
* 1、函数的原型对象都是Object的实例(但Object除外)
*/
// Person的原型对象,是Object 实例
console.log(Person.prototype instanceof Object);
// Object的原型对象不是Object 实例
console.log(Object.prototype instanceof Object);
// Function的原型对象,是 Object 实例
console.log(Function.prototype instanceof Object);
2所有的函数对象都是 Function 的实例 (Function 是他自己的实例)
/*
* 2所有的函数对象都是 Function 的实例 (Function 是他自己的实例)
*/
// 例如:Dog函数对象,内部就是 new Function()得到的
// 所以 Dog 就是 Function 的实例
function Dog()
// 实例化对象
let dog = new Dog();
// 对象中添加方法
dog.method = function()
console.log('对象中添加方法');
dog.method();
// 上面的代码可以写成这样
// Dog是构造函数对象
let Dog = new Function();
// 实例化对象
let dog = new Dog();
// 对象中添加方法
dog.method = function()
console.log('对象中添加的方法2');
dog.method();
// Function是自己的实例
// Function.prototype 的Function是函数对象
// Function.__proto__ 的Function是实例对象
console.log(Function.prototype == Function.__proto__);
3.Object 的原型对象是原型链的尽头
/*
* 3.Object 的原型对象是原型链的尽头
*/
console.log(Object.prototype.__proto__);
根据上面的三条结论验证 instanceof 判断时原型链的指向
例子1:
// 案例1
function Foo()
let foo = new Foo();
console.log(foo instanceof Foo);
console.log(foo instanceof Object);
console.log(foo instanceof Foo); 结果是true,示意图如下:
console.log(foo instanceof Object);结果true,示意图如下:
例子2
// 案例2
console.log(Object instanceof Function);
console.log(Object instanceof Object);
console.log(Function instanceof Function);
console.log(Function instanceof Object);
function Fooo()
console.log(Object instanceof Fooo);
console.log(Object instanceof Function); 结果true,示意图如下:
console.log(Object instanceof Object);结果是true,示意图如下:
console.log(Function instanceof Function);结果是true,示意图如下:
console.log(Function instanceof Object);结果是true,示意图如下:
function Fooo()
console.log(Object instanceof Fooo);结果是 false 结果如下:
OK,原型对象全部讲完了
参考视频
http://www.gulixueyuan.com/my/course/58
http://www.gulixueyuan.com/course/194
js继承机制的设计思想
http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html
以上是关于web前端练习22----js中的原型对象prototype,原型链(重要)的主要内容,如果未能解决你的问题,请参考以下文章
web前端面试题JavaScript第一弹,个人整理部分面试题汇总
web前端练习20----es6新语法7,生成器对象 Generator
好程序员web前端教程分享前端javascript练习题之promise