学习javascript面向对象 理解javascript原型和原型链_javascript技巧

先看一张图,梳理梳理。

一、基本概念  
【原型链】每个构造函数都有一个对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么,如果原型对象等于另一个原型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。如果另一个原型又是另一个原型的实例,那么上述关系依然成立。如此层层递进,就构成了实例与原型的链条。
【原型对象】这个对象包含可以由特定类型的所有实例共享的属性和方法。所有引用类型默认都继承了Object,而这个继承也是通过原型链实现的。所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype,这也正是所有自定义类型都会继承toString()、valueOf()方法的原因
【构造函数】构造函数与其他函数的区别在于调用它们的方式不同。一般来说,函数只要通过new操作符来调用,那它就可以作为构造函数;如果不通过new操作符来调用,那它跟普通函数也不会有什么两样。
[注意]用户自定义的函数和javascript中内置的构造函数可以当成构造函数使用
【构造函数的写法】构造函数始终应该以一个大写字母开头,而非构造函数以一个小写字母开头。这个做法借鉴自其他OO语言,主要是为了区别于ECMAScript中的其他函数;因为构造函数本身也是函数,只不过可以用来创建对象而已
【构造函数的三种使用场景】
[a]当作构造函数使用

var person = new Person("Nicholas",29,"software Engineer");
person.sayName();

[b]当作普通函数调用

Person("greg",27,"doctor");//添加到window
window.sayName();//"Greg"

[c]在另一个对象的作用域中调用

var o = new Object();
Person.call(o,"Kristen",25,"Nurse");
o.sayName();//"Kristen"

【prototype属性】只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。
[注意]只有函数才有prototype属性,object没有prototype属性
【constructor属性】在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针
[注意]创建了自定义的构造函数之后,其原型对象默认只会取得constructor属性,至于其他方法则都是从Object继承而来的
【_proto_和[[prototype]]】当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262第5版管这个指针叫[[prototype]]。虽然在脚本中标准的方式访问[[prototype]],但firefox\safari\chrome在每个对象上都支持一个属性_proto_;而在其他实现中,这个属性对脚本则是完全不可见的。这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间
二、基本操作  
【原型链查询】每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性。搜索首先从对象实例本身开始,如果在实例中找到了具有给定名字的属性,则返回该属性的值;如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性,如果找到了这个属性,则返回该属性的值。
【添加实例属性】当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性;换句话说,添加这个属性只会阻止我们访问原型中的那个属性,但不会修改那个属性,即使将这个属性设置为null,也只会在实例中设置这个属性,而不会恢复其指向原型的连接。不过,使用delete操作符则可以完全删除实例属性,从而让我们能够重新访问原型中的属性。
【原型的动态性】由于在原型中查找值的过程是一次搜索,因此我们对原型对象所做的任何修改都能立即从实例上反映出来,即使是先创建了实例后修改原型也照样如此。
[注意]不推荐在产品化的程序中修改原生对象的原型

function Person(){};
var friend = new Person();
Person.prototype.sayHi = function(){
  alert('hi');
}
friend.sayHi();//"hi"

【重写原型】调用构造函数时会为实例添加一个指向最初原型的[[prototype]]指针,而把原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系。实例中的指针仅指向原型,而不指向构造函数。
三、基本方法  
[1]isPrototypeOf():判断实例对象和原型对象是否存在于同一原型链中,只要是原型链中出现过的原型,都可以说是该原型链所派生的实例的原型

function Person(){};
var person1 = new Person();
var person2 = new Object();
console.log(Person.prototype.isPrototypeOf(person1));//true
console.log(Object.prototype.isPrototypeOf(person1));//true
console.log(Person.prototype.isPrototypeOf(person2));//false
console.log(Object.prototype.isPrototypeOf(person2));//true

[2]ECMAScript5新增方法Object.getPrototypeOf():这个方法返回[[Prototype]]的值

function Person(){};
var person1 = new Person();
var person2 = new Object();
console.log(Object.getPrototypeOf(person1)); //Person{}
console.log(Object.getPrototypeOf(person1) === Person.prototype); //true
console.log(Object.getPrototypeOf(person1) === Object.prototype); //false
console.log(Object.getPrototypeOf(person2)); //Object{}

[3]hasOwnProperty():检测一个属性是否存在于实例中

function Person(){
  Person.prototype.name = 'Nicholas';
}
var person1 = new Person();
//不存在实例中,但存在原型中
console.log(person1.hasOwnProperty("name"));//false
//不存在实例中,也不存在原型中
console.log(person1.hasOwnProperty("no"));//false
person1.name = 'Greg';
console.log(person1.name);//'Greg'
console.log(person1.hasOwnProperty('name'));//true
delete person1.name;
console.log(person1.name);//"Nicholas"
console.log(person1.hasOwnProperty('name'));//false

[4]ECMAScript5的Object.getOwnPropertyDescriptor():只能用于取得实例属性的描述符,要取得原型属性的描述符,必须直接在原型对象上调用Object.getOwnPropertyDescription()方法

function Person(){
  Person.prototype.name = 'Nicholas';
}
var person1 = new Person();
person1.name = 'cook';
console.log(Object.getOwnPropertyDescriptor(person1,"name"));//Object {value: "cook", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(Person.prototype,"name"));//Object {value: "Nicholas", writable: true, enumerable: true, configurable: true}

[5]in操作符:在通过对象能够访问给定属性时返回true,无论该属性存在于实例还是原型中

function Person(){}
var person1 = new Person();
person1.name = 'cook';
console.log("name" in person1);//true
console.log("name" in Person.prototype);//false
var person2 = new Person();
Person.prototype.name = 'cook';
console.log("name" in person2);//true
console.log("name" in Person.prototype);//true

[6]同时使用hasOwnProperty()方法和in操作符,来确定属性是否存在于实例中

//hasOwnProperty()返回false,且in操作符返回true,则函数返回true,判定是原型中的属性
function hasPrototypeProperty(object,name){
  return !object.hasOwnProperty(name) && (name in object);
}
function Person(){
  Person.prototype.name = 'Nicholas';
}
var person1 = new Person();
console.log(hasPrototypeProperty(person1,'name'));//true
person1.name = 'cook';
console.log(hasPrototypeProperty(person1,'name'));//false
delete person1.name;
console.log(hasPrototypeProperty(person1,'name'));//true
delete Person.prototype.name;
console.log(hasPrototypeProperty(person1,'name'));//false

[7]ECMAScript5的Object.keys()方法:接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组
[注意]一定要先new出实例对象再使用该方法,否则为空

function Person(){
  Person.prototype.name = 'Nicholas';
  Person.prototype.age = 29;
  Person.prototype.job = 'Software Engineer';
  Person.prototype.sayName = function(){
    alert(this.name);
  }
};
var keys = Object.keys(Person.prototype);
console.log(keys);//[]
var p1 = new Person();
p1.name = "Rob";
p1.age = 31;
var keys = Object.keys(Person.prototype);
console.log(keys);//["name","age","job","sayName"]
var p1Keys = Object.keys(p1);
console.log(p1Keys);//["name","age"]

[8]ECMAScript5的Object.getOwnPropertyNames()方法:接收一个对象作为参数,返回一个包含所有属性的字符串数组
[注意]一定要先new出实例对象再使用该方法,否则只有constructor

function Person(){
  Person.prototype.name = 'Nicholas';
  Person.prototype.age = 29;
  Person.prototype.job = 'Software Engineer';
  Person.prototype.sayName = function(){
    alert(this.name);
  }
};
var keys = Object.getOwnPropertyNames(Person.prototype);
console.log(keys);//["constructor"]
var p1 = new Person();
var keys = Object.getOwnPropertyNames(Person.prototype);
console.log(keys);//["constructor", "name", "age", "job", "sayName"]

希望本文所述对大家学习javascript程序设计有所帮助。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索javascript
, 原型
原型链
,以便于您获取更多的相关知识。

时间: 2024-09-13 17:06:20

学习javascript面向对象 理解javascript原型和原型链_javascript技巧的相关文章

学习javascript面向对象 理解javascript对象_javascript技巧

一.编程思想 面向过程:以过程为中心,自顶向下逐步细化,程序看成一系列函数调用的集合 面向对象:对象作为程序的基本单元,程序分解为数据和相关操作二.类.对象类:对具有相同特性和特征事物的抽象描述 对象:某种类型对应的具体事物三.面向对象的三大特性 封装:隐藏实现细节,实现代码模块化 继承:扩展已存在的代码模块,实现代码重用  多态:接口的不同实现方式,实现接口重用四.对象定义:无序属性的集合,其属性可以包含基本值.对象或者函数 //简单的对象实例 var person = new Object(

JavaScript面向对象之私有静态变量实例分析_javascript技巧

本文实例分析了JavaScript面向对象之私有静态变量.分享给大家供大家参考,具体如下: 大家知道,私有实例变量的原理是根据作用域. 私有实例变量是在Javascript的function内部用var关键字实现,只在function内部有效. 仿照这个,提出私有静态变量的解决方案: <script language="javascript" type="text/javascript"> var JSClass = (function() { var

学习javascript面向对象 掌握创建对象的9种方式_javascript技巧

本文为大家分享了javascript创建对象的9种方式,供大家参考,具体内容如下 [1]使用Object构造函数 [缺点]使用同一个接口创建很多对象,会产生大量重复代码 var person = new Object(); person.name = "Nicholas"; person.age = 29; person.job = "Software Engineer"; person.sayName = function(){ alert(this.name);

javascript面向对象之Javascript 继承_js面向对象

上几节讲了 JavaScript 面向对象之命名空间 . javascript 面向对象的JavaScript类 . JavaScript 面向对象的之私有成员和公开成员 与 Javascript 面向对象之重载,大家可以先看上面的再继续往下看. 在JavaScript中实现继承可以有多种方法,下面说两种常见的. 一,call 继承,先看代码: 先定义一个"人"类 复制代码 代码如下: //人类 Person=function(){ this.name="草泥马";

跟我学习javascript的prototype原型和原型链_javascript技巧

用过JavaScript的同学们肯定都对prototype如雷贯耳,但是这究竟是个什么东西却让初学者莫衷一是,只知道函数都会有一个prototype属性,可以为其添加函数供实例访问,其它的就不清楚了,最近看了一些 JavaScript高级程序设计,终于揭开了其神秘面纱. 每个函数都有一个prototype属性,这个属性是指向一个对象的引用,这个对象称为原型对象,原型对象包含函数实例共享的方法和属性,也就是说将函数用作构造函数调用(使用new操作符调用)的时候,新创建的对象会从原型对象上继承属性和

深入理解JavaScript系列(6) 强大的原型和原型链_javascript技巧

前言 JavaScript 不包含传统的类继承模型,而是使用 prototypal 原型模型. 虽然这经常被当作是 JavaScript 的缺点被提及,其实基于原型的继承模型比传统的类继承还要强大.实现传统的类继承模型是很简单,但是实现 JavaScript 中的原型继承则要困难的多. 由于 JavaScript 是唯一一个被广泛使用的基于原型继承的语言,所以理解两种继承模式的差异是需要一定时间的,今天我们就来了解一下原型和原型链. 原型 10年前,我刚学习JavaScript的时候,一般都是用

深入理解JavaScript作用域和作用域链_javascript技巧

作用域是JavaScript最重要的概念之一,想要学好JavaScript就需要理解JavaScript作用域和作用域链的工作原理.今天这篇文章对JavaScript作用域和作用域链作简单的介绍,希望能帮助大家更好的学习JavaScript. JavaScript作用域 任何程序设计语言都有作用域的概念,简单的说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期.在JavaScript中,变量的作用域有全局作用域和局部作用域两种. 1. 全局作用域(Global Sc

深入理解关于javascript中apply()和call()方法的区别_javascript技巧

如果没接触过动态语言,以编译型语言的思维方式去理解javaScript将会有种神奇而怪异的感觉,因为意识上往往不可能的事偏偏就发生了,甚至觉得不可理喻.如果在学JavaScript这自由而变幻无穷的语言过程中遇到这种感觉,那么就从现在形始,请放下的您的"偏见",因为这对您来说绝对是一片新大陆,让JavaScrip慢慢融化以前一套凝固的编程意识,注入新的生机! 好,言归正传,先理解JavaScrtipt动态变换运行时上下文特性,这种特性主要就体现在apply, call两个方法的运用上.

深入理解JavaScript系列(4) 立即调用的函数表达式_javascript技巧

前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下"自执行"这个叫法,本文对这个功能的叫法也不一定完全对,主要是看个人如何理解,因为有的人说立即调用,有的人说自动执行,所以你完全可以按照你自己的理解来取一个名字,不过我听很多人都叫它为"自执行",但作者后面说了很多,来说服大家称呼为"立即调用的函数表达式". 本文英文原文地址:http://benalman