你不知道的JS5-原型

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/354341.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

enum 定义3个属性_和平精英:合金龙骨有3个隐藏属性,比玛莎“水下无敌”还唬人...

欢迎诸位小伙伴们来到天哥开讲的《和平精英》“精英那点事儿”~接下来呢,咱们聊聊合金龙骨的3个隐藏属性、土豪玩家“自投罗网”以及游戏里的“公主病患者”等有趣的玩家游戏经历与发现~得,废话不多说了,还是各位小伙伴们熟悉的“老配方”&am…

vue-cli项目引用文件/组件/库 的注意事项(一)

vue引入的问题 (1)main.js入口文件引入(项目中所有的页面都会加载main.js,所以用户放全局变量) // Element import ElementUI from ‘element-ui’ import ‘element-ui/lib/theme-chalk/index.css’ Vue.use(ElementUI) (2&am…

java中缓冲区和缓存_Java中的Google协议缓冲区

java中缓冲区和缓存总览 协议缓冲区是一种用于结构化数据的开源编码机制。 它是由Google开发的,旨在实现语言/平台中立且可扩展。 在本文中,我的目的是介绍Java平台上下文中协议缓冲区的基本用法。 Protobuff比XML更快,更简单,并…

三十七 Python分布式爬虫打造搜索引擎Scrapy精讲—将bloomfilter(布隆过滤器)集成到scrapy-redis中...

Python分布式爬虫打造搜索引擎Scrapy精讲—将bloomfilter(布隆过滤器)集成到scrapy-redis中,判断URL是否重复 布隆过滤器(Bloom Filter)详解 基本概念 如果想判断一个元素是不是在一个集合里,一般想到的是将所有元素保存起来,然后通过比较确定…

绩效管理的实际案例:2024年绩效提升重要方法

案例一:目标设定与衡量的艺术 背景:某科技公司每年都会为其全球员工设定年度目标。然而,这些目标往往过于模糊,导致员工不清楚自己需要完成什么。 问题:目标设定不清晰,导致员工感到困惑和不满。 解决方…

array python 交集_模糊数学Python库简介和评测

写在前面模糊数学是国内外许多工学、管理学研究生以上的选修甚至必修课程。但对于非数学专业而言,掌握模糊数学的各种计算方法、了解各种方法的用途(应用场景)其实要比理解模糊数学的“数学”理论要重要得多。目前在Matlab等数学工具中其实也…

使用Hibernate和Spring设置分布式Infinispan缓存

一个非常典型的设置–需要分布式缓存的spring / hibernate应用程序。 但是事实证明,设置并不是那么简单。 您显然需要缓存。 可以使用EhCache,Hazelcast,Infinispan,memcached,Redis,AWS的Elasticache以及…

Element UI 的使用

官方文档: https://element.eleme.io/#/zh-CN/component/installation 一、普通项目引入相关文件,使用elementui插件: (1)引入相关文件 (2)可以直接使用了 vue项目使用elementui 安装 &…

python基础十一之迭代器和生成器

可迭代 内置方法中含有__iter__的数据类型都是可迭代的,只要是可迭代的就可以使用for循环,反之亦然。 print(dir()) # dir()函数可以获取当前数据类型的所有内置方法 返回值是list print(__iter__ in dir([])) # 判断是否含有__iter__内置方法 迭代器…

架构设计器_大厂案例:马蜂窝大交通业务监控报警系统架构设计与实现

部门的业务线越来越多,任何一个线上运行的应用,都可能因为各种各样的原因出现问题:比如业务层面,订单量比上周减少了,流量突然下降了;技术层面的问题,系统出现 ERROR ,接口响应变慢了…

使用mpvue开发小程序

一、安装node.js 1、在官网中安装nodejs最新版本。地址:https://nodejs.org/en/download/,根据自己环境,进行下载安装。 2、安装完成后,进行nodejs版本及npm版本查看。 打开cmd命令行,输入 node -v 和 npm -v&#…

iOS----------UITextField实现过滤选中状态拼音

2018年上班的第二天,就这样背了一个大锅。我们项目中有一个搜索功能,在这一期的版本中,为了增强优化,去除了过滤空格的请求,这样或许能增加很好的用户体验,恰恰相反,偷鸡不成蚀把米。没想到苹果…

ai电磁组属于什么组_RPA+AI 创新案例挑战赛 2020 【专业组】amp;【校园组】优胜名单来也!...

大赛介绍本次大赛由 RPA 产业推进方阵为指导单位,来也科技为主办单位,面向所有来也科技合作伙伴及深圳地区大学生公开报名征集【专业组】&【校园组】参赛案例。RPA 产业推进方阵是在中国人工智能产业发展联盟指导下,由中国信息通信研究院…

GetSystemInfo()

关于“GetSystemInfo()”的详细信息,参考:https://msdn.microsoft.com/en-us/library/windows/desktop/ms724381(vvs.85).aspx Getting Hardware Information 例程:https://msdn.microsoft.com/en-us/library/windows/desktop/ms724423(vvs.8…

具有Spring Boot和Yeoman的单页Angularjs应用程序

我非常感谢yeoman之类的工具,它们提供了一种非常快速的方法来将不同的javascript库组合在一起成为一个一致的应用程序。 Yeoman提供了UI层,如果您需要开发服务层和静态资产的Web层,则打包的一种好方法是使用Spring Boot 。 我知道有像JHipste…

vue项目封装axios请求

目录: 一,src/utils/request.js import axios from axios import { getToken } from /utils/auth import store from /storeconst service axios.create({baseURL: process.env.VUE_APP_BASE_API,withCredentials: true,timeout: 5000,// headers:{ …

自定义函数_python3基础07函数(自定义)

"pythonic生物人"的第43篇分享。详细介绍python中:自定义函数的构建;参数传递;模块中调用函数。目录0、楔子1、自定义函数格式2、编写函数说明文档3、函数参数函数形参和实参区别位置实参关键字实参默认实参让实参可选传递任意数量…

v-for中用elementUI实现分页

html 分页的内容 <el-aside style"width:49%;" v-for"(item, key, index) in AirInfor.slice((currentPage-1) * pagesize, currentPage * pagesize)" :key"index"><p style"margin-bottom: 10px;"><span>区域&a…

curl -windows下接口通讯

1&#xff0c;下载curl -----url命令传输工具2&#xff0c;配置curl环境变量3&#xff0c;在cmd环境中使用举例&#xff1a;curl -G http://xxxxxxx.com&#xff1f;参数使用&#xff1a;curl -G "www.baidu.com" 最原始的批量通讯返回可以将通讯命令保存为bat格式文…

centos7建站php_centos7搭建php服务器

{"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],"search_count":[{"count_phone":6,"count":6}]},"card":[{"des":"云服务器 ECS(Elastic Compute Service)是一…