每次创建新函数,就会根据规则为该函数创建一个 prototype 属性,该属性是一个指向函数原型对象的指针。并且原型对象都默认拥有一个 constructor 属性,该属性是一个指向那个新建函数的指针。

1、常规原型对象

function Person(){
}
Person.prototype.name = "Tom";
Person.prototype.job = "software engineer";
Person.prototype.age = 29;
Person.prototype.sayName = function (){
console.log(this.name);
}; var p1 = new Person();
var p2 = new Person(); p1.sayName(); // Tom
p2.sayName(); // Tom console.log(p1.sayName == p2.sayName); // true

下图展示了构造函数、原型对象、对象实例的关系

关于[[prototype]],在创建一个实例后,该实例内部将包含一个指向原型对象的指针[[prototype]],这个属性在有的实现中可以通过对象的 __proto__属性访问(有的浏览器或者执行环境不能)。要注意的是该属性是实例与构造函数的原型对象的联系,而不是实例与构造函数之间的联系。

上述两个对象实例 p1 和 p2 自身是没有属性和方法的,但都能调用sayName()方法。这是因为当读取某个属性时,会执行一次搜索,先从对象实例自身开始,如果本身有给定属性,则返回该属性的值;如果没有找到,则继续从它的原型对象中查找,找到则返回,没找到继续从原型对象的原型对象(如果该实例的原型对象有原型对象的话)中查找。找到为止,直至原型链的末端,如果最后还是没找到则报错。

介绍一些方法

function Person(){
}
Person.prototype.name = "Tom";
Person.prototype.job = "software engineer";
Person.prototype.age = 29;
Person.prototype.sayName = function (){
console.log(this.name);
}; var p1 = new Person();
var p2 = new Person(); p1.sayName(); // Tom
p2.sayName(); // Tom console.log(p1.sayName == p2.sayName); // true //判断对象之间是否是原型对象--实例的关系
console.log(Person.prototype.isPrototypeOf(p1)); //true
console.log(Person.prototype.isPrototypeOf(p2)); //true //Object.getPrototypeOf(),返回实例对象的[[prototype]]的值,即原型对象
console.log(Object.getPrototypeOf(p1) == Person.prototype); // true //hasOwnProperty(),继承自Object,检测对象自身是否存在某个属性
console.log(p1.hasOwnProperty("name")); //false // in 操作符,只要能通过对象访问到属性就返回true
console.log("name" in p1); // true //for-in 遍历所有能够访问到的且可枚举的属性
for(var prop in p1){
console.log(prop); //name,job,age,sayName
} // Object.keys(),返回参数对象自身的所有可枚举属性的字符串数组
var keys = Object.keys(Person.prototype);
console.log(keys); //["name","job","age","sayName"] //Object.getOwnPropertyNames(),返回参数对象自身的所有属性的字符串数组,包含不可枚举属性
keys = Object.getOwnPropertyNames(Person.prototype);
console.log(keys); //["constructor","name","job","age","sayName"] p1.name = "Greg"; console.log(p1.name); // Greg --来自实例
console.log(p2.name); // Tom --来自原型 console.log(p1.hasOwnProperty("name")); //true
console.log(p2.hasOwnProperty("name")); //false console.log("name" in p1); // true
console.log("name" in p2); // true console.log(Object.keys(p1)); //["name"]
keys = Object.getOwnPropertyNames(p1);
console.log(keys); ////["name"] delete p1.name;
console.log(p1.name); //Tom --来自原型
console.log(p1.hasOwnProperty("name")); //false

 

2、对象字面量形式的原型

function Person(){
} Person.prototype = {
name : "Tom",
job : "software engineer",
age : 29,
sayName : function (){
console.log(this.name);
}
}; var p1 = new Person();
var p2 = new Person(); p1.sayName(); // Tom
p2.sayName(); // Tom console.log(p1.sayName == p2.sayName); // true
console.log(p1 instanceof Object); //true
console.log(p1 instanceof Person); //true
console.log(p1.constructor == Person); //false
console.log(p1.constructor == Object); //true

对象字面量形式的原型,实际上是完全重写了默认的 prototype 对象,因此 constructor 属性已经是新对象的constructor属性了,指向Object,不再指向Person函数了。

可以在原型重写时加上constructor属性,手动添加属性,会导致它的[[enumerable]]特性设置为true,即设为可枚举的,而默认的原生constructor 属性是不可枚举的。

function Person(){
} Person.prototype = {
//constructor: Person,
name : "Tom",
job : "software engineer",
age : 29,
sayName : function (){
console.log(this.name);
}
};
//可以特别定义为不可枚举
Object.defineProperty(Person.prototype,"constructor",{
enmuerable:false,
value:Person
});

字面量对象重写原型可能会出现一些错误:

function Person(){
} var p1 = new Person(); Person.prototype = {
constructor: Person,
name : "Tom",
job : "software engineer",
age : 29,
sayName : function (){
console.log(this.name);
}
}; var p2 = new Person(); p2.sayName(); // Tom
p1.sayName(); // error : p1.sayName is not a function

上面例子中,先创建 p1 对象,后重写原型,导致 p1 的原型对象不是新的原型对象,所以执行 p1.sayName() 时,从 p1 的原型中找不到 sayName 方法。

如果支持__proto__属性的话,可以在重写原型对象后,添加语句:p1.__proto__ = Person.prototype; 重新建立实例和原型的关联。

js 中的原型prototype的更多相关文章

  1. js中的原型prototype

    var arr1 = new Array(12,34,98,43,38,79,56,1); arr1.sum=function (){ var result = 0; for(var i=0; i&l ...

  2. JS 中的原型 -- prototype、__proto__ 以及原型链

    原文: 1.深入理解javascript原型和闭包——prototype原型 2.三张图搞懂JavaScript的原型对象与原型链 打开浏览器控制台,任意定义一个对象,打印出来后,会发现有最后一定有一 ...

  3. js中的原型、继承的一些想法

    最近看到一个别人写的js类库,突然对js中的原型及继承产生了一些想法,之前也看过其中的一些内容,但是总不是很清晰,这几天利用空闲时间,对这块理解了一下,感觉还是有不通之处,思路上没那么条理,仅作为分享 ...

  4. 谈谈JS中的原型

    不知道大家对JS中的原型理解的怎么样,我想如果大家对JS中的原型对象以及prototype属性十分熟悉的话对后面原型链以及继承的理解会十分的容易,这里想和大家分享自己对其的理解,请先看下面这段代码O( ...

  5. JavaScript中的原型prototype和__proto__的区别及原型链概念

    问题 初学js的同学,总是搞不清楚js中的原型是什么东西,看着控制台打印出来的一串串__proto__,迷惑不已. 例如我定义一个Person,创建一个实例p,并打印实例. function Pers ...

  6. 说一说js中__proto__和prototype以及原型继承的那些事

    在面试中遇到过,问js如何实现继承,其实最好的方式就是构造函数+原型,今天在讨论中,发现自己以前理解上的一些误区,特地写出来,最近都比较忙,等手上的项目做完,可以来做个总结. 先说我以前没有认识到位的 ...

  7. js中__proto__, property, prototype, 对象自身属性方法和原型中的属性方法的区别

    __proto__: 这个属性是实例对象的属性,每个实例对象都有一个__proto__属性,这个属性指向实例化该实例的构造函数的原型对象(prototype). proterty:这个方法是对象的属性 ...

  8. 【JS】中的原型prototype到底是个啥

    一.什么是原型 原型prototype是函数的一个属性,这个属性是一个指针,指向一个对象(原型对象),这个原型对象的用途是包含可以由特定类型的所有实例共享的属性和方法. 函数也是一种对象.它也是属性的 ...

  9. js中constructor和prototype

    在最开始学习js的时候,我们在讲到原型链和构造函数的时候经常会有一个例子 如果我们定义函数如下: function Foo() { /* .. */ } Foo.prototype.bar = fun ...

随机推荐

  1. <转>如何用C++实现自动微分

    作者:李瞬生转摘链接:https://www.zhihu.com/question/48356514/answer/123290631来源:知乎著作权归作者所有. 实现 AD 有两种方式,函数重载与代 ...

  2. hive orc update

    hive-site.xml --><configuration> <!-- WARNING!!! This file is auto generated for documen ...

  3. 2. apache整合tomcat部署集群

    apache只有处理静态事物的能力, 而tomcat的强项就是处理动态的请求,所以apache和tomcat整合相互取长补短,由apache作为入口,如果是请求静态页面或者是静态文件,由apache直 ...

  4. js检查字符串的包含关系

    首先想到的是str.contains(),用的时候发现报错了 正确的判断方法应该用:str.indexof(substring),不包含的话,返回-1.大小写敏感 var rsp = response ...

  5. Crontab 删除N天前日志

    linux是一个很能自动产生文件的系统,日志.邮件.备份等.虽然现在硬盘廉价,我们可以有很多硬盘空间供这些文件浪费,让系统定时清理一些不需要的文件很有一种爽快的事情.不用你去每天惦记着是否需要清理日志 ...

  6. mybatis 异常和注意

    1.  Could not set parameters for mapping like语句出错,因将%%写入到mapper.xml中导致,将%%随同参数一并传入. 例:String userNam ...

  7. LeetCode题解 Permutations II 和 Permutations I ——回溯算法

    这个算法感觉还是很陌生的.算法导论里没有讲这个算法,而数据结构与算法分析只用了一节来阐述.我居然跳过去了..尴尬. 笨方法解决的: 第一题: 给定一个元素不重复的数组,枚举出他们的全排列. 方法1:递 ...

  8. Shell编程:小白初步

    shell类型: shell的历史网络上有一大堆,这里就不介绍了.但是我们的Linux系统上是有许多种shell的我们可以查看:使用命令 vi /etc/passwd 可以查看用户对应的shell(其 ...

  9. 19.Observales

    然后 ng serve看看能不能启动 OK

  10. ArcGIS自定义工具箱-自增字段(可以设置初始值和步长)

    ArcGIS自定义工具箱-自增字段(可以设置初始值和步长) 联系方式:谢老师,135-4855-4328,xiexiaokui#qq.com 目的:字段值初始值为设定值(默认为0),每次增加一个步长( ...