本文将为您提供关于java入门笔记二:javascript中的原型链的详细介绍,我们还将为您解释javascript中的原型和原型链的相关知识,同时,我们还将为您提供关于JavaScirpt中的原型,
本文将为您提供关于java入门笔记二:javascript中的原型链的详细介绍,我们还将为您解释javascript中的原型和原型链的相关知识,同时,我们还将为您提供关于JavaScirpt中的原型,原型对象和原型链、JavaScript...原型与继承中的原型链...、JavaScript中的原型与原型链、JavaScript中的原型与原型链详解的实用信息。
本文目录一览:- java入门笔记二:javascript中的原型链(javascript中的原型和原型链)
- JavaScirpt中的原型,原型对象和原型链
- JavaScript...原型与继承中的原型链...
- JavaScript中的原型与原型链
- JavaScript中的原型与原型链详解
java入门笔记二:javascript中的原型链(javascript中的原型和原型链)
本周开始学习JavaScript,相比于之前学习的java,差别不是一点点大。一直很喜欢java语言的严谨性,创建任何东西之前都要先定义其类型,而且定义什么类型就只能做什么类型,从一而终。如此的好处在于,提高语言的可理解性和程序的可调式性。相对之下,js(JavaScript的简称,下文都以此代替,因为我懒,就酱!)就太任性了,变量类型不用定义就可以直接用,想在何时定义都可以,而且一个变量可以定义不同类型,什么时候换类型都可以,这样随意虽然对于敲代码来说很方便,但是随意创建会增加日后重新阅读时的理解难度,所以建议一切还是尽量保证统一规则,多做注释,给日后阅读代码的他人和自己图个便利。不过所幸数据类型和基本语句、算法跟java都一样,所以掌握java后再入门js不是什么难事。话不多说,直接进入正题。
js里面有一个强大的游戏规则,叫“一切皆对象”。创建的变量是对象,类的实例化是对象,函数(方法)是对象,就连类本身也可以做对象。比如下面的代码:
var Person=function (name) {
this.name=name;
}
Person.prototype={
show:function () {
alert("@@@@@");
}
var p1=new Person("alice");
p1.show();
首先定义的Person是函数对象,但是又作为类在其prototype(原型,下文详解)中增加函数,最后作为类创建了实例化对象p1,p1作为Person类的对象,可以调用其prototype中的方法(原型功能,下文详解)。
下面介绍原型,每个类都有两个固定属性:prototype和_proto_,所有的实例化对象都有一个固定的属性:_proto_,可以把prototype理解成类中的共享库,类往里面添加东西它的实例化对象就可以直接访问。
举个例子,代码如下:
var Person=function (name) {
this.name=name;
}
Person.prototype.age=10;
Person.prototype.show=function () {
alert("我的名字是:"+this.name);
}
Person.phone="1388888888";
var p1=new Person("孙悟空");
var p2=new Person("唐僧");
p1.age=44;
我们新建一个Person类,并实例化了两个对象p1和p2,通过Person.prototype往Person的原型中添加属性和函数,那么Person的原型中的所有“资源”就可以供它的实例化对象直接引用,几者之间的关系如下图:
Person的prototype指向Person的原型,原型中的constructor指向Person类,Person类的实例化对象p1,p2中的_proto_指向Person的原型。name是Person类的共同属性,在其构造函数中存在的,name存在于Person及其实例化对象中,prototype里并没有,phone是Person作为对象时添加的,所以类实例化对象中并没有此属性。一般情况下,p1和p2可以直接访问prototype中的成员,如:p1.show()或者p1._proto_.show(),这两者是等价的,但是若p1中定义了和prototype相同的成员,比如上述代码中的age,则结果就不同了,p1.age=44,p1._proto_.age=10。
js里有一个对象挂的超类Object,函数挂的超类Function,那么他们跟一般类及类的原型又是什么关系呢?请见下图:
所以js中的原型就是环环相连,有链接的就可以直接访问其成员,我们称为原型链。原型链有很多好处,比如可以用于继承,也就是直接将父类作为子类的原型,这样所有子类的实例化对象都可以访问父类的成员了:
var Father=function (name,phone) {
this.name=name;
this.phone=phone;
}
var Son=function (age) {
this.age=age;
}
Son.prototype=new Father("孙悟空","138888888");//将父类作为子类的原型链
var s=new Son(500);
Last but not least,以上只是我在JavaScript入门学习中的一点浅层整理,今后深入学习后再来补充,谢谢阅读!
JavaScirpt中的原型,原型对象和原型链
一.什么是原型呢?
二.什么是原型对象呢?
- 我们创建每一个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象(即原型对象).而这个对象的用途是包含
- 使用原型对象的好处是可以让所有的对象实例(实例对象)共享他包含的所有的属性和方法
- 需要特别注意的是原型对象的理解,只要创建一个函数,该函数就会创建一个prototype(原型)属性,这个属性指向函数的原型对象
三.原型对象和原型的关系?
- 这是每一个JavaScript对象(除了 null )都具有的一个属性,叫__proto__,这个属性会指向该对象的原型。
-
当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性即__proto__),指向构造函数的原型对象
constructor是什么呢?
- 在默认情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针即(Person.prototype.constructor指向Person),而通过这个构造函数,我们可以继续为原型对象添加起他属性和方法
通过一张图片展示他们之间的关系
代码示例:
//创建一个构造函数,并在构造函数的原型上添加一个name属性
function Person(){
}
Person.prototype.name = "kebi"
var person1 = new Person();
console.log(person1.name) //kebi
var perso2 = new Person();
console.log(person2.name) //kebi
console.log(person.__proto__ === Person.prototype); // true 他两个的关系也是完全相等的
console.log(Person.prototype.constructor == Person) // true
// 顺便学习一个ES5的方法,可以获得对象的原型 console.log(Object.getPrototypeOf(person) === Person.prototype) // true
//b.isPrototypeOf(a) 这个方法的意思是,a对象是否指向b对象
Person.prototype.isPrototypeOf(person1) //true 因为person1中有一个__proto__属相指向原型对象(Person.prototype)
Person.prototype.isPrototypeOf(person2) //true 同理
总结一下prototype和__proto__到底是什么关系呢?
- 函数对象的prototype属性, 可以称之为显式原型属性(简称: 显式原型)
- 实例对象的__proto__属性, 可以称之为隐式原型属性(简称: 隐式原型)
- 原型对象: 也就是prototype属性和_proto__属性指向的对象
四.什么是原型链?
1.原型的搜索机制
当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。
代码例子:
function Person() {
}
Person.prototype.name = ''heyushuo'';
var person = new Person();
person.name = ''kebi'';
console.log(person.name) // kebi
delete person.name;
console.log(person.name) //heyushuo
在这个例子中,我们给实例对象 person 添加了 name 属性,当我们打印 person.name 的时候,结果自然为 kebi。
但是当我们删除了 person 的 name 属性时,读取 person.name,从 person 对象中找不到 name 属性就会从 person 的原型也就是 person.__proto__ ,也就是 Person.prototype中查找 (原型对象中),幸运的是我们找到了 name 属性,结果为 heyushuo。
但是万一还没有找到呢?原型的原型又是什么呢? ( 肯定需要一环一环地前行到原型链的末端才会停下来)
最顶层为默认的原型
所有的函数的默认原型都是Object的实例,所以默认原型都会包含一个内部指针,指向Object.prototype(默认原型的原型对象),这也真是所有自定义类型都会继承toString()/valueOf等默认的方法的根本原因.一直查到最顶层才算一个完整的原型链
如图所示: 蓝色线为完整的原型链
参考:Javascript:高级程序设计
javascript深入之从原型到原型链(感觉原型和原型对象未分清楚)
JavaScript...原型与继承中的原型链...
原型
原型是什么
在JavaScript中 函数是一个包含属性和方法的Function类型的对象 而原型(Prototype)就是Function类型对象的一个属性
在函数定义时就包含了prototype属性 它的初始值是一个空对象 在JavaScript中并没有定义函数的原型类型 所以原型可以是任何类型
原型是用于保存对象的共享属性和方法的 原型的属性和方法并不会影响函数本身的属性和方法
// Function类型的属性 -> 所有函数都具有的属性
console.log(Function.prototype);
// 定义函数
function fn(){
console.log(''this is function'');
}
// 原型的默认值是空对象
console.log(fn.prototype);
// 函数包含构造函数 -> 所有引用类型其实都是构造函数
console.log(Number.prototype);
console.log(Object.prototype);
var result = Object.getOwnPropertyDescriptor(Object.prototype, ''constructor'');
console.log(result);
获取原型
function fn(){
console.log(''this is function'');
}
// 使用访问对象的属性语法结构
console.log(fn.prototype);
console.log(fn[''prototype'']);
// Object类型提供getPrototypeOf()方法
console.log(Object.getPrototypeOf(fn));
为原型新增属性或者方法
function fn(){
console.log(''this is function'');
}
// 变量proto也是一个空对象
// var proto = fn.prototype;
// 新增属性或方法
// proto.name = ''张三'';
fn.prototype.name = ''张三'';
console.log(fn.prototype);
// defineProperty()
Object.defineProperty(fn.prototype, ''age'', {
value : 28,
enumerable : true
});
console.log(fn.prototype);
构造函数的原型
// 定义构造函数
function Hero(){
this.name = ''张三'';
this.sayMe = function(){
console.log(''this is function'');
}
}
// 操作构造函数Hero的原型
Hero.prototype.age = 28;
// 利用构造函数来创建对象
var hero = new Hero();
console.log(hero);
// 为构造函数的原型新增的属性 -> 构造函数创建的对象中依旧可以访问
console.log(hero.age);// 28
// 对象hero中不存在age属性
var result = Object.getOwnPropertyDescriptor(hero, ''age'');
console.log(result);
原型属性
自有属性与原型属性
自有属性:通过对象的引用添加的属性 其他对象可能无此属性 即使有 也是彼此独立的属性
原型属性:从原型对象中继承来的属性 一旦原型对象中属性值改变 所有继承该原型的对象属性均改变
// 定义构造函数
function Hero(name){
// 构造函数本身的属性 -> 自有属性
this.name = name;
this.sayMe = function(){
console.log(''this is function'');
}
}
// 通过构造函数Hero的prototype新增属性或方法
// 通过原型所定义的属性 -> 原型属性
Hero.prototype.age = 28;
/*
通过构造函数Hero创建对象时
* 不仅具有构造函数的自有属性
* 还具有构造函数的原型属性
*/
var hero = new Hero(''张三'');
console.log(hero.name);// 张三
console.log(hero.age);// 18
var hero2 = new Hero(''李四'');
console.log(hero2.name);// 李四
console.log(hero2.age);// 28
// 为对象hero新增age属性
// hero.age = 80;
// console.log(hero.age);// 80
//
// console.log(hero);
//
// console.log(hero2.age);// 28
Hero.prototype.age = 80;
console.log(hero.age);
console.log(hero2.age);
重写属性
通过构造函数或对象的自有属性可以重写原型的属性
// 定义构造函数
function Hero(){
this.name = ''张三'';
}
// 构造函数的原型
Hero.prototype.name = ''李四'';
// 构造函数创建对象
var hero = new Hero();
// 自有属性与原型属性同名时,默认访问的是自有属性 -> 自有属性的优先级别高于原型属性
console.log(hero.name);// 张三
// 删除对象的属性
delete hero.name;
// 重新访问对象的属性
console.log(hero.name);// 李四
检测原型属性
function Hero(){
//this.name = ''张三'';// 自有属性
}
//Hero.prototype.name = ''李四'';
var hero = new Hero();
/*
Object.hasOwnProperty(prop)方法
* 作用 - 判断当前指定属性是否为自有属性
* 参数
* prop - 表示指定属性名称
* 返回值 - 布尔值
* true - 表示存在指定的自有属性
* false - 表示不存在指定的自有属性
*/
// console.log(hero.hasOwnProperty(''name''));// true
/*
使用in关键字检测对象的属性
* 作用 - 判断对象中是否存在指定属性(自有属性或原型属性)
* 返回值 - 布尔值
* true - 表示存在指定的属性
* false - 表示不存在指定的属性
*/
console.log(''name'' in hero);
操作原型的方式
// 定义构造函数
function Hero(){}
// 通过构造函数的原型新增属性或方法
// 1.利用对象.属性或方法的方式新增属性或方法
Hero.prototype.name = ''张三'';
Hero.prototype.sayMe = function(){
console.log(''this is function'');
}
// 2.将原型重新赋值为一个新对象
Hero.prototype = {
name : ''张三'',
sayMe : function(){
console.log(''this is function'');
}
}
// 通过构造函数创建对象
var hero = new Hero();
console.log(hero.name);
hero.sayMe();
显式原型与隐式原型
// 定义构造函数
function Hero(){
this.name = ''张三'';
}
// 通过构造函数的原型新增属性或方法
Hero.prototype.age = 28;
// 通过构造函数创建对象
var hero = new Hero();
console.log(hero.name);// 对象调用自有属性
console.log(hero.age);// 对象调用原型属性
/*
所有对象其实也具有原型
* 注意 - 对象的原型(__proto__)并非是函数的原型(prototype)
* 区分
* 将函数的原型 -> 显式原型
* 将对象的原型 -> 隐式原型
* 对象的原型
* 不能用于真实开发工作,仅用于逻辑测试
*/
console.log(hero.prototype);// undefined 表示对象中不存在该属性
console.log(hero.__proto__);
isPrototypeOf()方法
每个对象中都会具有一个isPrototypeOf()方法 该方法用来判断一个对象是否是另一个对象的原型
// 通过初始化器方式定义对象
var obj = {
name : ''张三''
}
//定义构造函数
function Hero(){}
//将对象obj赋值给构造函数Hero的原型
Hero.prototype = obj;
//通过构造函数创建对象
var hero = new Hero();
//判断指定对象是否是另一个对象的原型
var result = obj.isPrototypeOf(hero);
console.log(result);
扩展内置对象
JavaScript中的内置对象有些也具有prototype属性 利用内置对象的prototype属性可以为内置对象扩展属性或方法
通过原型扩展内置对象的属性和方法非常灵活 根据个性化要求制定Java Script语言的具体内容
Object.prototype.sayMe = function(){
console.log(''this is sayMe function'');
}
// 通过Object构造函数创建对象
var obj = new Object();
obj.sayMe();
Array.prototype.inArray = function(color){
// this - 表示当前的数组
for(var i = 0, len = this.length; i < len; i++){
if(this[i] === color){
return true;
}
}
return false;
}
var arr = ["red", "green", "blue"];
console.log(arr.inArray("red")); //true
console.log(arr.inArray("yellow")); //false
继承
原型链是什么
构造函数或构造器具有prototype属性 对象具有__proto__属性 这就是之前学习的原型
如果构造函数或对象A A的原型指向构造函数或对象B B的原型在指向构造函数或对象C 以此类推 最终的构造函数或对象的原型指向Object的原型 由此形成一条链状结构 被称之为原型链
按照上述的描述 在B中定义的属性或方法 可以直接在A中使用并不需要定义 这就是继承 它允许每个对象来访问其原型链上的任何属性或方法
// 原型链
function A(){
this.a = ''a'';
}
// 通过构造函数创建对象
var a = new A();
function B(){
this.b = ''b'';
}
// 将B的原型指向对象a
B.prototype = a;
// 通过构造函数创建对象
var b = new B();
console.log(b.b);// b
console.log(b.a);// a
function C(){
this.c = ''c'';
}
// 将C的原型指向对象b
C.prototype = b;
// 通过构造函数创建对象
var c = new C();
console.log(c.c);// c
console.log(c.b);// b
console.log(c.a);// a
只继承于原型
处于对效率的考虑 尽可能地将属性和方法添加到原型上
1.不要为继承关系单独创建新对象
2.尽量减少运行时的方法搜索
// 原型链
function A(){
// 将自有属性改写为原型属性
// this.a = ''a'';
}
A.prototype.a = ''a'';
function B(){
// this.b = ''b'';
}
// 将B的原型指向
B.prototype = A.prototype;
B.prototype.b = ''b'';
/*B.prototype = {
b : ''b''
}*/
function C(){
this.c = ''c'';
}
// 将C的原型指向
C.prototype = B.prototype;
var c = new C();
console.log(c.c);// c
console.log(c.b);
console.log(c.a);// a
原型链实现继承的问题
// 原型链
function A(){
// 将自有属性改写为原型属性
// this.a = ''a'';
}
A.prototype.a = ''a'';
function B(){
// this.b = ''b'';
}
// 将B的原型指向
B.prototype = A.prototype;
B.prototype.b = ''b'';
function C(){
// this.c = ''c'';
}
// 将C的原型指向
C.prototype = B.prototype;
C.prototype.c = ''c'';
var c = new C();
console.log(c.c);// c
console.log(c.b);// b
console.log(c.a);// a
var a = new A();
console.log(a.a);
console.log(a.b);
console.log(a.c);
var b = new B();
console.log(b.a);
console.log(b.b);
console.log(b.c);
JavaScript中的原型与原型链
前言
作为前端高频面试题之一,相信很多小伙伴都有遇到过这个问题。那么你是否清楚完整的了解它呢?
国际惯例,让我们先抛出问题:
- 什么是原型、原型链
- 它们有什么特点
- 它们能做什么
- 怎么确定它们的关系
或许你已经有答案,或许你开始有点疑惑,无论是 get
新技能或是简单的温习一次,让我们一起去探究一番吧
如果文章中有出现纰漏、错误之处,还请看到的小伙伴多多指教,先行谢过
以下↓
原型
JavaScript
是基于原型的我们创建的每个函数都有一个
prototype(原型)
属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
简单来说,就是当我们创建一个函数的时候,系统就会自动分配一个 prototype
属性,可以用来存储可以让所有实例共享的属性和方法
用一张图来表示就更加清晰了:
图解:
- 每一个构造函数都拥有一个
prototype
属性,这个属性指向一个对象,也就是原型对象 - 原型对象默认拥有一个
constructor
属性,指向指向它的那个构造函数 - 每个对象都拥有一个隐藏的属性
__proto__
,指向它的原型对象
function Person(){}
var p = new Person();
p.__proto__ === Person.prototype // true
Person.prototype.constructor === Person // true
那么,原型对象都有哪些特点呢
原型特点
function Person(){}
Person.prototype.name = ''tt'';
Person.prototype.age = 18;
Person.prototype.sayHi = function() {
alert(''Hi'');
}
var person1 = new Person();
var person2 = new Person();
person1.name = ''oo'';
person1.name // oo
person1.age // 18
perosn1.sayHi() // Hi
person2.age // 18
person2.sayHi() // Hi
从这段代码我们不难看出:
- 实例可以共享原型上面的属性和方法
- 实例自身的属性会屏蔽原型上面的同名属性,实例上面没有的属性会去原型上面找
既然原型也是对象,那我们可不可以重写这个对象呢?答案是肯定的
function Person() {}
Person.prototype = {
name: ''tt'',
age: 18,
sayHi() {
console.log(''Hi'');
}
}
var p = new Person()
只是当我们在重写原型链的时候需要注意以下的问题:
function Person(){}
var p = new Person();
Person.prototype = {
name: ''tt'',
age: 18
}
Person.prototype.constructor === Person // false
p.name // undefined
一图胜过千言万语
- 在已经创建了实例的情况下重写原型,会切断现有实例与新原型之间的联系
- 重写原型对象,会导致原型对象的
constructor
属性指向Object
,导致原型链关系混乱,所以我们应该在重写原型对象的时候指定constructor
(instanceof
仍然会返回正确的值)
Person.prototype = {
constructor: Person
}
注意:以这种方式重设 constructor
属性会导致它的 Enumerable
特性被设置成 true
(默认为false
)
既然现在我们知道了什么是 prototype(原型)
以及它的特点,那么原型链又是什么呢?
原型链
JavaScript
中所有的对象都是由它的原型对象继承而来。而原型对象自身也是一个对象,它也有自己的原型对象,这样层层上溯,就形成了一个类似链表的结构,这就是原型链
同样的,我们使用一张图来描述
- 所有原型链的终点都是
Object
函数的prototype
属性 -
Objec.prototype
指向的原型对象同样拥有原型,不过它的原型是null
,而null
则没有原型
清楚了原型链的概念,我们就能更清楚地知道属性的查找规则,比如前面的 p
实例属性.如果自身和原型链上都不存在这个属性,那么属性最终的值就是 undefined
,如果是方法就会抛出错误
class类
ES6
提供了Class(类)
这个概念,作为对象的模板,通过class
关键字,可以定义类
为什么会提到 class
:
ES6
的 class
可以看作只是一个语法糖,它的绝大部分功能,ES5
都可以做到,新的 class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return ''('' + this.x + '', '' + this.y + '')'';
}
}
// 可以这么改写
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return ''('' + this.x + '', '' + this.y + '')'';
};
class
里面定义的方法,其实都是定义在构造函数的原型上面实现实例共享,属性定义在构造函数中,所以 ES6
中的类完全可以看作构造函数的另一种写法
除去 class
类中的一些行为可能与 ES5
存在一些不同,本质上都是通过原型、原型链去定义方法、实现共享。所以,还是文章开始那句话 JavaScript是基于原型的
更多 class
问题,参考这里
关系判断
instanceof
最常用的确定原型指向关系的关键字,检测的是原型,但是只能用来判断两个对象是否属于实例关系, 而不能判断一个对象实例具体属于哪种类型
function Person(){}
var p = new Person();
p instanceof Person // true
p instanceof Object // true
hasOwnProperty
通过使用 hasOwnProperty
可以确定访问的属性是来自于实例还是原型对象
function Person() {}
Person.prototype = {
name: ''tt''
}
var p = new Person();
p.age = 15;
p.hasOwnProperty(''age'') // true
p.hasOwnProperty(''name'') // false
原型链的问题
由于原型链的存在,我们可以让很多实例去共享原型上面的方法和属性,方便了我们的很多操作。但是原型链并非是十分完美的
function Person(){}
Person.prototype.arr = [1, 2, 3, 4];
var person1 = new Person();
var person2 = new Person();
person1.arr.push(5)
person2.arr // [1, 2, 3, 4, 5]
引用类型,变量保存的就是一个内存中的一个指针。所以,当原型上面的属性是一个引用类型的值时,我们通过其中某一个实例对原型属性的更改,结果会反映在所有实例上面,这也是原型 共享
属性造成的最大问题
另一个问题就是我们在创建子类型(比如上面的 p
)时,没有办法向超类型( Person
)的构造函数中传递参数
后记
鉴于原型的特点和存在的问题,所以我们在实际开发中一般不会单独使用原型链。一般会使用构造函数和原型相配合的模式,当然这也就牵扯出了 JavaScript
中另一个有意思的领域:继承
那么,什么又是继承呢
且听下回分解
感兴趣的小伙伴可以 点击这里 ,也可以扫描下方二维码关注我的微信公众号,查看更多前端小片段,欢迎 star
关注
参考文档
JavaScript高级程序设计
ECMAScript6入门
JavaScript中的原型与原型链详解
本文主要和大家分享javascript中的原型与原型链详解,说原型的时候,一般都是在说原型属性prototype。
一.介绍
1.函数的prototype属性
*所有的函数都有一个prototype属性,它默认指向一个object空对象(即称为原型对象)
*原型对象中有一个属性constructor,它指向函数对象
立即学习“Java免费学习笔记(深入)”;
2.原型对象有什么作用?----->给原型对象添加属性(一般都是添加方法)
*作用:函数的所有实例对象自动拥有原型中的属性(方法)
//*所有的函数都有一个prototype属性,它默认指向一个object空对象(即称为原型对象) console.log(Date.prototype)//系统内置的,如Date函数 //输出的是object {} 里面有很多属性与方法,这些是后来增加的, function Fn () { } console.log(Fn.prototype)//这是我们自定义的函数 有constructor //*原型对象中有一个属性constructor,它指向函数对象 console.log(Fn.prototype.constructor===Fn); //输出的函数 Fn.prototype.constructor是引用变量 Fn也是引用变量 Fn.prototype.test=function (){ console.log('test()') } Fn.prototype.test();//可以这样用,但是一般不是这样 //一般都是先实例化,然后调用函数 var fn=new Fn(); fn.test();
3.显式原型与隐式原型
*所有的函数function 都有一个prototype属性,即为显式原型
*所有的实例对象都有一个__proto__,可称为隐式原型
*对象的隐式原型的值为其对应构造函数的显式原型的值
3.1 显式原型与隐式原型问题
(1).prototype属性是什么时候加上,它的值是多少?
在定义函数(函数对象被创建)时,Js 引擎自动添加的。默认值是一个空的object实例对象<br/>
(注意:定义函数时,内部执行:Fn.prototype={} Fn.prototype.constructor===Fn)
(2).__proto__属性是什么时候加上,它的值是多少?
在创建实例对象时,Js 引擎自动添加的。值为构造函数的prototype属性值
(注意:定义函数时,内部执行:this.__proto__=Fn.prototype(是new出来的实例化对象))<br/>
3.2总结
a.函数的prototype属性:在定义函数(函数对象被创建)时,Js 引擎自动添加的,默认值是一个空object对象
b.对象的__proto__属性:创建实例对象时,Js 引擎自动添加的,默认值为构造函数的prototype属性值
c.程序员能直接操作显式原型,但不能直接操作隐式原型(es6之前)
function Fn() {//内部执行Fn.prototype={} Fn.prototype.constructor===Fn // body... } //每个函数function 都有一个prototype属性,即为显式原型 console.log(Fn.prototype) //每个实例对象都有一个__proto__,可称为隐式原型 var fn=new Fn();//内部执行:this.__proto__=Fn.prototype(是new出来的实例化对象) console.log(fn.__proto__) //对象的隐式原型的值为其对应构造函数的显式原型的值 console.log(Fn.prototype===fn.__proto__);//true
4.原型链
4.1别名,隐式原型链(因为是沿着隐式原型查找的)<br/>
4.2原型链其实是访问(或是查找)一个对象的属性时一个流程,
*先在自身属性中查找,找到返回
*如果没有,再沿着__proto__这条链向上查找,找到返回
*如果最终没找到,返回underfined
4.3作用是:查找对象的属性(方法)
<br/>
分析:{}是一个new Object的实例化对象,所以就延伸到Object=0x345这边去(有一个Object的函数,就是创建Object函数对象)
4.4总结:
*每个对象都有tostring()方法<br/> *fn.test3值为undefined。undefined当函数使用,会报错<br/> *函数对象有显示原型属性,实例化对象有隐式原型属性<br/> *方法尽量放在原型里面
4.5构造函数,原型,实例对象的关系
//构造函数function Person(n){this.name = n;} //构造函数对应原型对象Person.prototype.sayHi = function(){alert("大家好,我是" + this.name);} //实例var p1 = new Person("张三");
a.①构造函数 和 实例之间的关系:
实例通过new 关键字调用构造函数被创造。<br/>如:var dog1 = new Dog();<br/><br/>②构造函数 和 原型对象对象之间的关系:<br/>原型对象,可以通过 构造函数名.prototype 获取到。<br/>原型对象中的 constructor 属性会指向构造函数。<br/> Dog.prototype;<br/> <br/><br/>③实例和原型对象之间的关系:<br/>实例对象中的 __proto__ 属性会指向 原型对象。<br/>
<br/>
b.构造函数,原型,实例对象的关系图<br/>
(1)
(2)
<br/>
console.log(Object.prototype)//Object {} console.log(Object.__proto__)//function () {} console.log(Object.__proto__===Date.__proto__)//true console.log(Function.prototype===Function.__proto__)//true console.log(Object.prototype===Object.__proto__)//false
<br/>总结:
*实例对象的隐式原型等于构造函数的显式原型<br/>*任何函数都是Function 的实例,包括Function是它本身的实例化,但是不包括实例化对象(如var b=new fn(),其中b就不是Function的实例)
*通过对象.xxx查找属性时,它是引着隐式原型链(__proto__)的原型链去找,一直找到Object的原型对象的隐式原型(__proto__=null)
1.实例就是通过构造函数创建的。实例一创造出来就具有constructor属性(指向构造函数)和__proto__属性(指向原型对象),<br/>2.构造函数中有一个prototype属性,这个属性是一个指针,指向它的原型对象。<br/>3.原型对象内部也有一个指针(constructor属性)指向构造函数:Person.prototype.constructor = Person;<br/>4.实例可以访问原型对象上定义的属性和方法。
5.属性问题
给对象属性赋值,是不会查找原型链的
function Person(name,age) { this.name=name; this.age=age; } Person.prototype.setName=function(name){ this.name=name; } Person.prototype.sex='男'; //首先来看 name,age都是自身函数有,sex是原型链上的 var p1=new Person('Tom','12'); p1.setName('jack'); console.log(p1.name,p1.age,p1.sex);//jack 12 男 p1.sex='女';//给对象属性赋值,是不会查找原型链的 console.log(p1.name,p1.age,p1.sex);//jack 12 女 var p2=new Person('Bob','21'); console.log(p2.name,p2.age,p2.sex);//jack 12 男
6.instanceof探索
6.1instanceof是如何判断的?
表达式:A(看着实例) instanceof B(看着构造函数)
如果B函数的显示原型对象在A对象的原型链上,返回true,否则返回false
<br/>
function Foo() { } var f1=new Foo(); console.log(f1 instanceof Foo);//true console.log(f1 instanceof Object);//true console.log(Object instanceof Foo);//false console.log(Object instanceof Function);//true console.log(Object instanceof Object);//true console.log(Function instanceof Object);//true console.log(Function instanceof Function);//true
<br/><br/>
<br/>
6.2Function是通过new自己产生的实例
7.题目
/* *查找对象属性是查找对象的原型链,查找原型链是根据隐式原型链 *隐式原型是由实例决定的 */ var A=function(){ } A.prototype.n=1; var b=new A(); A.prototype={//显示原型 n:2,//给显示原型重新赋值,只会影响后面创建的对象 m:3, } //A.prototype.m=5; //给原型对象添加属性,对前后创建对象都有影响 console.log(b.n,b.m,c.n,c.m);//1 5 1 5 var c=new A(); console.log(b.n,b.m,c.n,c.m);//1 undefined 2 3 //题目2 var F=function(){} Object.prototype.a=function(){ console.log('a()') } Function.prototype.a=function(){ console.log('a()') } var f=new F(); f.a();//true f.b();//f.b is not a function F.a();//true F.b();//true
总结:
*查找对象属性是查找对象的原型链,查找原型链是根据隐式原型链*隐式原型是由实例决定的 A.prototype={//显示原型 n:2,//给显示原型重新赋值,只会影响后面创建的对象 m:3, } console.log(b.n,b.m,c.n,c.m);//1 undefined 2 3 A.prototype.m=5;给原型对象添加属性,对前后创建对象都有影响 console.log(b.n,b.m,c.n,c.m);//1 5 1 5
相关推荐:
JavaScript原型与原型链的详细分析
以上就是JavaScript中的原型与原型链详解的详细内容,更多请关注php中文网其它相关文章!
关于java入门笔记二:javascript中的原型链和javascript中的原型和原型链的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于JavaScirpt中的原型,原型对象和原型链、JavaScript...原型与继承中的原型链...、JavaScript中的原型与原型链、JavaScript中的原型与原型链详解的相关信息,请在本站寻找。
本文标签: