[[Prototype]]机制

[[Prototype]]是对象内部的隐试属性,指向一个内部的链接,这个链接的作用是:如果在对象上没有找到需要的属性或者方法引用,引擎就 会继续在 [[Prototype]] 关联的对象上进行查找。同理,如果在后者中也没有找到需要的 引用就会继续查找它的 [[Prototype]],以此类推。这一系列对象的链接被称为“原型链”。

function Foo() { // ...
}
var a = new Foo();
Object.getPrototypeOf( a ) === Foo.prototype; // true

调用new Foo()时会创建对象a,其中一步就是将a内部的 [[Prototype]] 链接到 Foo.prototype 所指向的对象。new Foo()只是间接完成:一个关联到其他对象的新对象。

function Foo() { /* .. */ }
Foo.prototype = { /* .. */ }; // 创建一个新原型对象
var a1 = new Foo();
a1.constructor === Foo; // false!
a1.constructor === Object; // true!

a1 并不是由Foo构造,a1对象仅仅是委托 [[Prototype]] 链上的 Foo. prototype,在Foo. prototype并没有找到constructor,于是会在原型链上查找直到找到为止.constructor 并不是一个不可变属性。它是不可枚举

原型继承编码风格

function Foo(name) {
this.name = name;
}
Foo.prototype.myName = function() {
return this.name;
};
function Bar(name,label) {
Foo.call( this, name );
this.label = label;
}
// 创建一个新的 Bar.prototype 对象并关联到 Foo.prototype
Bar.prototype = Object.create( Foo.prototype );
// 现在没有 Bar.prototype.constructor 了
// 如果需要这个属性的话可能需要手动修复一下它
Bar.prototype.myLabel = function() {
return this.label;
};
var a = new Bar( "a", "obj a" );
a.myName(); // "a"
a.myLabel(); // "obj a"

Object.create( Foo.prototype );会创建一个“新”对象,并把新对象内部的 [[Prototype]] 指向 Foo.prototype

对象关联编码风格

Task = {
setID: function(ID) { this.id = ID; },
outputID: function() { console.log( this.id ); }
};
// 让XYZ委托Task
XYZ = Object.create( Task );
XYZ.prepareTask = function(ID,Label) { this.setID( ID );
this.label = Label;
};
XYZ.outputTaskDetails = function() { this.outputID();
console.log( this.label ); };
// ABC = Object.create( Task ); // ABC ... = ...

XYZ = Object.create( Task ); 会返回一个新对象赋值给XYZ,这个新对象的原型指向Task,对XYZ进行操作不会改变Task,并且XYZ可以使用Task的一些方法属性,相比于原型继承模式,对象关联设计模式更为简洁

常见错误做法:

Bar.prototype = Foo.prototype;
// 基本上满足,但是可能会产生一些副作用
Bar.prototype = new Foo();

1.Bar.prototype = Foo.prototype 并不会创建一个关联到 Bar.prototype的新对象,它只 是 让 Bar.prototype 直 接 引 用 Foo.prototype对 象。 因 此 当 你 执 行 类 似 Bar.prototype. myLabel = ... 的赋值语句时会直接修改 Foo.prototype 对象本身。

2.Bar.prototype = new Foo()的确会创建一个关联到 Bar.prototype 的新对象。但是它使用 了 Foo(..)的“构造函数调用”,如果函数 Foo有一些副作用(比如写日志、修改状态、注册到其他对象、给 this 添加数据属性,等等),就会影响到 Bar()的“后代"。

// ES6 之前需要抛弃默认的 Bar.prototype
Bar.ptototype = Object.create( Foo.prototype );
// ES6 开始可以直接修改现有的Bar.prototype
Object.setPrototypeOf( Bar.prototype, Foo.prototype );

ES6 添加了辅助函数 Object.setPrototypeOf(..),可以用标准并且可靠的方法来修 改关联。

instanceof 操作符

function Foo() { // ...
}
Foo.prototype.blah = ...;
var a = new Foo();
a instanceof Foo; // true

instanceof 操作符的左操作数是一个普通的对象,右操作数是一个函数。instanceof 回答

的问题是:在 a 的整条 [[Prototype]] 链中是否有指向 Foo.prototype 的对象?

isPrototypeOf(..)

isPrototypeOf(..) 函数可以处理两个对象之间是否通过[[Prototype]] 链关联

Foo.prototype.isPrototypeOf( a ); // true

isPrototypeOf(..) 回答的问题是:在 a 的整 条 [[Prototype]] 链中是否出现过 Foo.prototype ?

获取对象的原型链

获取一个对象的 [[Prototype]] 链。在 ES5 中,标准的方法是: Object.getPrototypeOf( a );

绝大多数浏览器也支持一种非标准的方法来访问内部 [[Prototype]] 属性:

a.__proto__ === Foo.prototype; // true .__proto__并不存在于你正在使用的对象中 ,和其他的常用函数(.toString()、.isPrototypeOf(..),等等)一样,存在于内置的 Object.prototype中。

.__proto__的实现

Object.defineProperty( Object.prototype, "__proto__", {
get: function() {
return Object.getPrototypeOf( this );
},
set: function(o) {
// ES6 中的 setPrototypeOf(..)
Object.setPrototypeOf( this, o );
return o;
}
});

创建对象方法 Object.create()

var foo = {
something: function() {
console.log( "Tell me something good..." );
}
};
var bar = Object.create( foo );
bar.something(); // Tell me something good...

Object.create(..)创建一个新对象(bar)并把它关联到我们指定的对象(foo)

Object.create(null) 会创 建 一 个 拥 有 空( 或 者 说 null)[[Prototype]] 链接的对象

实现Object.create()

if (!Object.create) {
Object.create = function(o) {
function F(){}
F.prototype = o;
return new F();
};
}

总结

  • 类是一种语言的设计模式,而javaScript中模拟类的继承是通过原型机制实现的,其本质和类继承是不一样的,类继承是复制,而javaScript中对象之间的关系不是复制而是委托

  • [[Prototype]] 机制就是指对象中的一个内部链接引用 另一个对象。

  • 如果在第一个对象上没有找到需要的属性或者方法引用,引擎就会继续在 [[Prototype]] 关联的对象上进行查找。同理,如果在后者中也没有找到需要的引用就会继续查找它的 [[Prototype]],以此类推。这一系列对象的链接被称为“原型链”。

  • JavaScript 中这个机制的本质就是对象之间的关联关系

  • 关于ES6的class语法糖是一种语法糖,低层还是基于原型模型,这种语法糖更适用于那些有面向对象设计思维的开发者

【你不知道的javaScript 上卷 笔记7】javaScript中对象的[[Prototype]]机制的更多相关文章

  1. 你不知道的JavaScript上卷笔记

    你不知道的JavaScript上卷笔记 前言 You don't know JavaScript是github上一个系列文章   初看到这一标题的时候,感觉怎么老外也搞标题党,用这种冲突性比较强的题目 ...

  2. 【你不知道的javaScript 上卷 笔记6】javaScript中的对象相关内容

    一.创建一个对象的语法 var myObj = { key: value // ... };//字面量 var myObj = new Object(); //new myObj.key = valu ...

  3. 【你不知道的javaScript 上卷 笔记3】javaScript中的声明提升表现

    console.log( a ); var a = 2; 执行输出undefined a = 2; var a; console.log( a ); 执行输出2 说明:javaScript 运行时在编 ...

  4. Javascript学习笔记1 javascript的特点

    ..对于网页而言,Javascript无处不在,对于英语不好的人它简直是噩梦般的存在,但形式所逼,今天开始着手学习!希望自己能坚持下去.从什么地方着手,我的目标是从大处着眼,从应用着眼,不抠细节,反正 ...

  5. 1.2(JavaScript学习笔记)JavaScript HTML DOM

    一.DOM DOM全称为document object model(文档对象模型). 此处的文档指当前HTML文档,对象指HTML标签. 当网页被加载时,浏览器会创建页面的文档对象模型. 下面结合具体 ...

  6. Javascript学习笔记3 Javascript与BOM简介

    什么是BOM BOM是browser object model的缩写,简称浏览器对象模型 BOM提供了独立于内容而与浏览器窗口进行交互的对象 由于BOM主要用于管理窗口与窗口之间的通讯,因此其核心对象 ...

  7. JavaScript学习笔记(4)——JavaScript语法之变量

    一.变量可以使用短名称(比如 x 和 y),也可以使用描述性更好的名称(比如 age, sum, totalvolume). 变量必须以字母开头 变量也能以 $ 和 _ 符号开头(不过我们不推荐这么做 ...

  8. 【你不知道的javaScript 上卷 笔记5】javaScript中的this词法

    function foo() { console.log( a ); } function bar() { var a = 3; foo(); } var a = 2; bar(); 上面这段代码为什 ...

  9. 【你不知道的javaScript 上卷 笔记4】javaScript 中闭包的一些运用

    什么是闭包 闭包是javaScript语言的一种特性,在 javaScript 中以函数作为承接单元.当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行. fun ...

随机推荐

  1. ## springboot 下策略模式的简单使用

    1.灵魂三问 接手前人(已跑路)项目快乐否? 前人项目不写注释懵逼否? 一个方法中一堆if/else,且业务判断条件用简单数字(或英文字母),不带注释,想打人否?     所以,对于上述三个问题,我写 ...

  2. tomcat 多端口 多容器 多域名 配置

    先强调一个原则: server下面可以有多个service,用于配置不同监听端口 service下面可以有多个Host,用于配置该端口下的不同域名 Host里可以包含多个Context,用于配置该端口 ...

  3. crul 命令访问公网 dns解析错误 程序报错

    今天机房几台服务器都无法访问公网接口,原因是——解析公网域名出错,具体情况如下 ping  公网ip或者域名  都没有问题 curl 公网域名 出错 curl -4  访问公网域名没有问题 综合分析 ...

  4. ES[7.6.x]学习笔记(一)Elasticsearch的安装与启动

    Elasticsearch是一个非常好用的搜索引擎,和Solr一样,他们都是基于倒排索引的.今天我们就看一看Elasticsearch如何进行安装. 下载和安装 今天我们的目的是搭建一个有3个节点的E ...

  5. 「C++ 」借来的资源,何如还的潇洒?

    前言 本文的内容将专门对付内存管理,培养起有借有还的好习惯,方可消除资源管理的问题. 正文 所谓的资源就是,一旦用了它,将来必须还给系统.如果不是这样,糟糕的事情就会发生. C++ 程序内常见的资源: ...

  6. 进阶之路 | 奇妙的Drawable之旅

    前言 本文已经收录到我的Github个人博客,欢迎大佬们光临寒舍: 我的GIthub博客 学习清单: Drawable简介 Drawable分类 自定义Drawable 一.为什么要学习Drawabl ...

  7. golang单元测试简述

      Golang中内置了对单元测试的支持,不需要像Java一样引入第三方Jar才能进行测试,下面将分别介绍Golang所支持的几种测试: 一.测试类型   Golang中单元测试有功能测试.基准测试. ...

  8. Django csrf校验

    引入: 通常,钓鱼网站本质是本质搭建一个跟正常网站一模一样的页面,用户在该页面上完成转账功能 转账的请求确实是朝着正常网站的服务端提交,唯一不同的在于收款账户人不同. 如果想模拟一个钓鱼网站,就可是给 ...

  9. postgresql开篇

    postgresql 作为官方号称的最先进的开源数据库,从今天(2020-1-19)起开始系统的学习一下,记录自己学习的点点滴滴.

  10. 【python基础语法】多重循环嵌套,函数(第6天课堂笔记)

    1.什么是函数?函数有什么作用? 函数都是有特定功能的,都是由一些有特定功能的进行封装完成的 2.已经学过了哪些内置函数?分别有什么作用? print:输出 input:输入 type:查询数据类型 ...