JS 构造函数,原型对象和实例对象

JS 构造函数,原型对象和实例对象

直接看一幅图:


构造函数,原型对象和实例对象的关系图.png

看来这张图和图片上的代码,对这些概念有了一个基本的了解,在看看下面的一段代码:

function Person (name) {
  this.name = name;
}
Person.prototype.sex = 'boy';
Person.prototype.sayWords = function(des) {
  console.log(des+' say words:', this.name,this.sex);
}
let p1 = new Person('p1');

// code 1
p1.sayWords('p1-des1');
console.log("Person实例对象:p1(改变前):",p1);
console.log("Person原型对象:p1.__proto__:",Object.getPrototypeOf(p1));

// code 2
console.log("----------------------")
p1.name = 'p1-1001';
p1.sex = 'girl';

p1.sayWords('p1-des2');

console.log("Person实例对象:p1(改变后):",p1);
console.log("Person原型对象:p1.__proto__:",Object.getPrototypeOf(p1));

结果如下图:


image.png

加了code 2部分代码后:


image.png

从结果从可以看出,下面两句代码:
p1.name = 'p1-1001';
p1.sex = 'girl';
并没有修改prototype原型对象里面的属性sex的值,原型对象里面属性sex依然是sex:"boy";这两句代码只是对实例对象本身做了修改,把实例对象的name值改为“girl",并且添加了一个sex属性。
从这里就看出来了,写在Person()构造函数内部的那些属性或方法在new操作的过程中赋值给了实例对象p1的,所以构造函数内部的属性方法都是当前实例对象所私有的。

new操作的时候,除了会指向构造函数里面的代码并返回一个实例对象(就是构造函数里面的哪个this)外,还会把构造函数的作用域赋值给创建的实例对象,所以构造函数里面的this.xx = ‘xxx' 都是给实例对象添加属性并赋值,好比这样:

function PersonFn () {
let o = new Object();
o.a = 'aaa';
o.b = 'bbb';
return o;
}

每次执行PersonFn 都会生成一个全新的对象o。

那么code 1那段代码,p1实例对象是怎么拿到原型对象的sex属性的呢?或者说实例对象是怎么访问到原型对象的属性和方法的呢?
答案就是原型链。
当我们new一个函数的时候,这个函数就从一个普通函数变成了构造函数,并且会返回一个实例对象,函数中的this自动指向了这个实例对象,所以构造函数中的方法和属性,用面向对象的语言来说,构造函数里面的属性方法都是实例对象自己的私有成员,上面也说过了;同时实例对象还会有一个隐藏属性叫做[[prototype]]或proto,这个属性指向的就是原型对象,这个隐藏属性就是实现原型链的关键。
还以code 1代码段为例子,p1对象{”name":"p1",proto:原型对象地址},里面更本没有sex这个属性,也没有sayWords这个方法,如果是一般的对象比如:

var px = {};
px.a;
px.fn();

这样的一段代码肯定会报错的,px.a是undefined,px.fn()没这个方法,直接报错。
但是实例对象不会,当代码执行到p1.sayWords()的时候,如果实例对象自己没有这个方法,代码就会通过proto属性,像攀爬锁链一样,继续往上走,走到Person原型对象,原型对象这里是有这个方法的,于是就调用原型对象的这个方法。
再想想,如果Person原型对象也没找到想要的属性方法呢?仔细看看Person原型对象,它也有一个proto属性,这个属性指向的是Object函数的原型对象,同理,代码依然会顺着Person原型对象的proto属性找到Object原型对象,如果Object原型对象也没找到,那么就会报错,因为Object是所有函数的父类,也锁链的最顶层,找不到只能报错了。
说起原型链,又想到作用域链。
作用域链也是类似的,比如:

<script>
var x = 0;

function a (){
   x++;
}

a();
</script>

这是一段很简单的代码,如果a函数的作用域中没有变量x,代码就会继续往上层作用域查找,直到找到变量x或者一直找到顶层作用域,即window对象,如果window对象中也没有要查找的变量,就会报错。

再说个方法:某个对象.hasOwnProperty("属性"),判断某个对象下面是否有某个属性,如果属性是原型对象里面的或者属性不存在,都会返回false。

最后,再看一段代码:

function Person (name) {
  this.name = name;
}
Person.prototype.sex = 'boy';
Person.prototype.friendsArr = ['tom','lucy'];
Person.prototype.looksLikeObj = {
  hair: "long black",
  eyes: "blue"
};
Person.prototype.sayWords = function(des) {
  console.log(des+' say words:', this.name,this.sex, this.looksLikeObj, this.friendsArr);
}
let p1 = new Person('p1');
p1.sayWords('p1-des1');
console.log("Person实例对象:p1(改变前):",p1);
console.log("Person原型对象:p1.__proto__:",Object.getPrototypeOf(p1));

console.log("----------------------")
p1.name = 'p1-1001';
p1.sex = 'girl';
p1.friendsArr.push('lilei');
p1.looksLikeObj['cloth'] = "skirt";

// p1.xyz['a'] = 'xyza'; // xyz对象不存在,Cannot set property 'a' of undefined

p1.sayWords('p1-des2');

console.log("Person实例对象:p1(改变后):",p1);
console.log("Person原型对象:p1.__proto__:",Object.getPrototypeOf(p1));

结果截图:


image.png

对比一下,如果通过实例对象设置一个引用类型的值,如果实例对象本身不存在该属性,而原型对象存在,它会直接修改共享的公共原型对象,从而影响到其他实例对象。
所以,除非你需要这样的效果,否则,尽量不要将引用类型的属性设置在原型对象中,可以考虑放到构造函数中设置引用类型的属性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,636评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,890评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,680评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,766评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,665评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,045评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,515评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,182评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,334评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,274评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,319评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,002评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,599评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,675评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,917评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,309评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,885评论 2 341