1、原型

[[prototype]]

js中的对象有一个特殊的[[prototype]]内置属性,其实就是对于其他对象的引用,几乎所有的对象在创建时[[prototype]]属性都会被赋予一个非空的值

使用for..in和in操作符都会查找对象的整条原型链

所有普通的[[prototype]]链最终都会指向内置的Object.prototype

2、属性设置与屏蔽

myobject.foo = "bar"

1)如果myobject对象中包含名为foo的普通数据访问属性,这条赋值语句只会修改已有的属性值

2)如果foo不是直接存在于myobject中,[[prototype]]链就会发生遍历,类似[[get]]操作,如果原型链上找不到foo,foo就会直接添加到myobject上

3)如果属性名foo又存在于myobject又出现在[[prototype]]链上层,那么就会发生屏蔽。myobject中包含的foo属性会屏蔽原型链上层的所有foo属性,因为myobject.foo总是会选择原型链中最底层的foo属性

分析一下foo不直接存在于myobject而是存在于原型链上层时myobject.foo = 'bar'会出现三种情况

1、如果在[[prototype]]上层存在名为foo的普通数据访问属性,并且没有被标记为只读(writable:false)那就会直接在myobject中添加一个名为foo的新属性它是屏蔽属性

2、如果在[[prototype]]上层存在foo但是被标记为只读,那么无法修改已有属性或者在myobject上创建屏蔽属性,如果运行在严格模式下代码会抛出一个错误

3、如果在[[prototype]]链上层存在foo并且它是一个setter那就一定会调用这个setter,foo不会被添加到mtobject

如果你希望第二种、第三种情况也能屏蔽foo就不能使用=操作符来赋值,而是使用Object.defineProperty(...)来向myobject添加foo

3、“类”函数

所有函数都会拥有一个公用并且不可枚举的属性,会指向另一个对象

function Foo() {//...
}
var a = new Foo();
object.getPropertyOf(a) === Foo.prototype;

调用Foo()时会创建a,其中一步就是将a内部的[[prototype]]链接到Foo.prototype所指向的对象

new Foo()会生成一个新对象(我们称为a)这个新对象的内部链接[[prototype]]关联的是Foo.prototype对象

new Foo()只是间接完成了我们的目标:一个关联到其他对象的新对象

更直接的方法就是Object.create()

4、关于名称

继承意味着复制操作,js并不会复制对象的属性,相反js会在两个对象之间创建一个关联,这样一个对象就可以通过委托访问另一个对象的属性和函数

5、”构造函数“

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

实际上a本身并没有.constructor属性。

实际上.constructor引用同样被委托给了Foo.prototype

而Foo.prototype.constructor 默认指向Foo

Foo.prototype的constructor属性只是Foo函数在声明时的默认属性,如果你创建了一个对象并替换了函数默认的prototype对象引用,那么新对象并不会自动获得.constructor属性

修复.constructor需要很多手动操作,方法:记住:constructor并不代表被构造

6、构造函数还是调用

实际上Foo函数本身并不是构造函数,然而当你在普通的函数调用前面加上new关键字调用后,就会把这个函数调用变成构造函数调用。

实际上new会劫持所有普通函数并用构造函数的形式来调用它

function nothing(){console.log('aaa');
}
var a = new nothing();//"aaa"
a;//{}

nothing只是一个普通的函数,但是使用new调用时,它就会构造一个对象并赋给a,这看起来像是new的一个副作用

js中对于构造函数最准确地解释是,所有带new的函数调用

函数不是构造函数,当且仅当使用new时,函数会变成构造函数调用

7、(原型)继承

原型风格代码:

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.prrototype.myLabel = function() {return this.label;
}
var a = new Bar("a","obj a")
a.myName();
a.myLabel()

这段代码核心

Bar.prototype = Object.create(Foo.prototype);

调用Object.create()会凭空创建一个“新”对象并把新对象内部的[[Prototype]]关联到指定的对象

换句话说意思是:“创建一个新的Bar.prototype对象并把它关联到Foo.prototype”

下面这两种方式是常见的错误做法:

// 和你想要的机制不一样
Bar.prototype = Foo.prototype;
// 基本上满足你的需求,但是可能会产生一些副作用
Bar.prototype = new Foo();

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

修改对象的[[prototype]]关联方法:

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

Object.create(。。。)需要创建一个新对象然后把旧对象抛弃掉,不能直接修改已有的默认对象

如果忽略掉Object.create()方法带来的轻微性能损失(抛弃的对象需要进行垃圾回收)

8、检查类关系

假设有对象a,如何寻找对象a委托的对象(如果存在的话)

在传统的面向类的环境中,检查一个实例的继承祖先通常被称为内省(或者反射)

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

如何通过内省找出a的“祖先”(委托关联)?

方法一:站在类的角度判断

a intanceof Foo;//true

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

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

可是这个方法只能处理对象(a)和函数(带.prototype引用的Foo)如果你想判断两个对象之间是否通过[[Prototype]]链关联,只用instanceof无法实现

方法二:判断[[Prototype]]反射的方法:

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

isPrototypeOf(...)回答的问题是:在a的整条[[Prototype]]链中是否出现过Foo.prototype
// 非常简单:b是否出现在c的[[Prototype]]链中
b.isPrototypeOf(c)

直接获取一个对象的[[Prototype]]链

ES5中:

Object.getPropertyOf(a)

可以验证一下,这个对象引用是否和我们想的一样

Object.getPropertyOf(a) === Foo.prototype;//true

绝大多数(不是所有!)浏览器也支持一种非标准的方法来访问内部[[Prototype]]属性

a.__proto__ === Foo.prototype;//true

这个奇怪的__proto__属性“神奇的”引用了内部的[[Prototype]]对象,如果你想直接查找(甚至可以通过.__proto__.__proto__...来遍历)原型链的话,这个方法非常有用

9、对象关联

1)创建关联

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,这样可以充分发挥[[prototype]]机制的威力(委托)而且避免不必要的麻烦2)内部委托比直接委托可以可以让API接口设计更加清晰直接委托:
var anotherObject = {cool:function() {console.log("cool");}
}
var myObject = Object.create(anotherObject);
myObject.cool();

内部委托:

var anotherObject = {cool:function() {console.log("cool");}
}
var myObject = Object.create(anotherObject);
myObject.docool = function(){this.cool();//内部委托
}
myObject.docool()//'cool'

如果访问对象中并不存在的一个属性,[[Get]]操作就会查找对象内部[[Prototype]]关联的对象。这个关联关系实际上定义了一条原型链(有点像嵌套的作用域链),在查找属性时会对他进行遍历

 虽然这些js机制和传统的面向类语言中的“类初始化”,“类继承”很相似,但是js中的机制有一个核心区别,就是不会复制,对象之间是通过内部的[[Prototype]]链关联的对象之间的关系不是复制而是委托。

转载于:https://www.cnblogs.com/lu-yangstudent/p/8042019.html

你不知道的JS5-原型相关推荐

  1. 《你不知道的Javascript--上卷 学习总结》(原型)

    [[Prototype]] 1.Javascript中的对象有一个特殊的[[Prototype]]内置属性,其实就是对于其他对象的引用.几乎所有的对象在创建时[[Prototype]] 属性都会被赋予 ...

  2. 《你不知道的JavaScript》整理(四)——原型

    一.[[Prototype]] JavaScript中的对象有一个特殊的[[Prototype]]内置属性,其实就是对于其他对象的引用. var myObject = {a: 2 }; myObjec ...

  3. 你不知道的Javascript之原型

    原型链: 如果要访问对象中并不存在的属性,[get]操作,就会查找对象内部prototype的关联对象,如果后者也没有就会继续查找它的prototype 这个关联在定义上叫"原型链" ...

  4. 读书笔记-你不知道的JS上-混入与原型

    继承 mixin混合继承 function mixin(obj1, obj2) {for (var key in obj2) {//重复不复制if (!(key in obj1)) {obj1[key ...

  5. 你不知道的原型和原型链

  6. 对象----《你不知道的JS》

    最近在拜读<你不知道的js>,而此篇是对于<你不知道的js>中对象部分的笔记整理,希望能有效的梳理,并且深入理解对象 一.语法 对象两种定义形式:声明(文字)形式.构造形式 声 ...

  7. javascript面向对象系列第一篇——构造函数和原型对象

    前面的话 一般地,javascript使用构造函数和原型对象来进行面向对象编程,它们的表现与其他面向对象编程语言中的类相似又不同.本文将详细介绍如何用构造函数和原型对象来创建对象 构造函数 构造函数是 ...

  8. 翻译连载 | JavaScript轻量级函数式编程-第7章: 闭包vs对象 |《你不知道的JS》姊妹篇...

    原文地址:Functional-Light-JS 原文作者:Kyle Simpson-<You-Dont-Know-JS>作者 关于译者:这是一个流淌着沪江血液的纯粹工程:认真,是 HTM ...

  9. 创业公司产品经理如何画好原型图

    对于创业公司的产品经理来说,一般身兼交互设计,所以输出的原型图一方面要给研发作为需求说明,一方面是为了让UI更有效率的输出. 画原型的工具我一直使用的是axure,因为用习惯了,上手比较顺,而我对于原 ...

  10. 的函数原型_JS基础函数、对象和原型、原型链的关系

    JS的原型.原型链一直是比较难理解的内容,不少初学者甚至有一定经验的老鸟都不一定能完全说清楚,更多的"很可能"是一知半解,而这部分内容又是JS的核心内容,想要技术进阶的话肯定不能对 ...

最新文章

  1. Nature综述:肠道微生物在人类代谢健康与疾病中的作用
  2. 通过DNS通道传输的交互式PowerShell脚本
  3. 实战SSM_O2O商铺_02数据模型设计及实体类的创建
  4. batocera_旧电脑变身影音游戏主机,来自法国大神的batocera系统
  5. windows编译libevent时报告“缺少print_winsock_errors.obj”的解决
  6. 通过select选项动态异步加载内容
  7. 理想更新“货车并线预警”遭用户吐槽 李想:仍在优化
  8. 【干货】推荐系统的商业价值:如何量化?怎么提升?
  9. dqn系列梳理_讲人话系列——DQN初探之2048
  10. 【图像融合】基于matlab curvelet变换图像融合(评价指标)【含Matlab源码 781期】
  11. 第二节 中国的行政区划
  12. Android下DLAN中DMS模块的实现
  13. 计算机密码输入正确,Win10输入正确密码却提示“密码不正确”如何解决
  14. Nodejs 获取本机IP地址
  15. 深度学习:将新闻报道按照不同话题性质进行分类
  16. photoshop CS5免费破解完整版下载,详细安装教程,无需注册【PS序列号】
  17. linux 打开相机工具cheese/guvcview
  18. Adodb 官方介绍
  19. R 语言 4.2.2安装 WGCNA
  20. linux自动网络对时

热门文章

  1. 【安卓开发】Android初级开发(okhttp3发送带header与带参数的GET请求)
  2. C++ 11 深度学习(六)智能指针综述
  3. 【开源项目】向Nginx-RTMP服务器推流
  4. C++后端向JS前端转换
  5. 3皮卡丘眨眼代码_活见久,皮卡丘居然是一门编程语言
  6. 计算机网络教学方式探讨论文,学生老师论文,关于关于高中计算机网络教学效率提升相关参考文献资料-免费论文范文...
  7. 10鼎信诺为什么安装不了_鼎信诺审计软件一周常见问题(4.134.17)
  8. dataframe 选择输出_使用 Python 实现机器学习特征选择的 4 种方法
  9. python输入的方式有几种_Python读取键盘输入的2种方法
  10. html实体转化字符串 php_php将字符串转为HTML的实体引用的一个类