js回忆录(4) -- 对象,构造函数
1.对象 && 构造函数
js是一门基于对象的语言,里边所有的数据类型都可以当对象使唤(当然null和undefined除外),当我们在v8引擎里声明一个对象时会发现每个对象属性里边都有这个东西:

在说明这个属性之前需要先说明一点就是,声明一个对象和new Object 生成对象的结果是一样的,即,所有对象都是Object的实例,每一个实例都会继承它的构造函数上的prototype的属性,而上面的_proto_就是指向这个原型对象的,也就是说:
实例._proto_ = 构造函数.prototype
每个对象上查找属性时要走的流程大体是,查查自己有没有,查查自己的构造函数的prototype上有没有,再查查构造函数的prototype的构造函数的prototype上有没有,依次查找,如此变成了原型链。普通对象上关于原型只有一个_proto_ 属性指向它的构造函数的原型(原型对象),而在一个函数对象上则多了一个prototype属性,这个属性就是用于继承,创建子类共有的属性,方法的比较重要的一个属性。
函数初始化之后原型对象上有constructor和_proto_两个属性,一个指向这个函数一个指向它自己的构造函数的prototype,一般来说是Object.prototype。
构造函数实在是js里边一个有趣的东西,一个函数是不是构造函数不是取决于它的定义,而是取决于它的调用方式。构造函数不需要return语句 ,甚至调用的时候都不需要(),这一点就比较像php了。生成的实例对象私有属性由构造函数定义,共有属性由构造函数的prototype定义。
2.关于JS里的继承
继承其实是一个面向对象的编程语言的概念,JS天生的短板,一般面试的时候回答继承时怎么做,就只是简单的 子类.prototype = 父类.prototype,好了合格了,但是从实际出发,事情远远没有这么简单,首先是constructor的属性得改,然后得考虑到JS引用类型的特性,然后得留下子类已经定义的属性,防止被父类覆盖,所以一个合理的做法是深拷贝,
function inherit( sub,sup ){
let temp = deepCopy(sup.prototype);//深拷贝父类prototype
for( let key in temp ){
if( sub.prototype[key] !==null || sub.prototype[key] !== undefined){//子类中如果已经存在对应属性,则不作操作
}else{
sub.prototype[key] = temp[key]
}
}
function deepCopy(obj){
let result;
if(JSON){
result = JSON.parse(JSON.stringify(obj))
}else{
for( let key in obj ){
result[key] = typeof( obj[key] ) !== 'object'? obj[key] : deepCopy(obj[key])
}
}
return result
}
}
如果已经确定子类中没有要保留的属性,可以用一下司徒正美大佬的继承方法,这是他的anu框架里边的源码的一个方法,很妙啊,我做了适当删减。
function inherit(SubClass, SupClass) {
function Bridge() {}
Bridge.prototype = SupClass.prototype;
var fn = SubClass.prototype = new Bridge();
fn.constructor = SubClass;
}
----------------------------------------2018-5-15更新-----------------------------------------------------------------
本来以为前面几个继承已经实现的差不多了,然而前几天和某位大佬讨论一番之后,却发现上边那个继承的实现方式并不是很完美,首先,js基于原型链的继承其一是出于性能考虑的,如果采用上面我深拷贝的那种方式实现的话,相当于是将父类的共有方法又拷贝了一份,不是很完美,然后这几天结合自己的思考和es6提供的一些方法,可以使用下面的方式更新,方法1:
function parent(){}
function son(){}
Object.setPrototypeOf(son.prototype,parent.prototype);
Object.setPrototypeOf 方法可以设置一个对象的原型对象,进而通过这种方式实现继承。第二种方法是改变__proto__指向,即:
son.prototype.__proto__ = parent.prototype;
然而,以上两种方式mdn都不是很推荐,具体原因可以看看上边setPrototypeOf的链接,这样做的后果就是牵涉到性能问题了,而比较推荐的方法是使用Object.create这个es5就有的方法:
function parent(){}
function son(){}
son.prototype = Object.create( parent.prototype )
Object.create的第一个参数即为新创造的对象的原型对象。
因此通过这种方法实现继承,不光保证了性能,也可以动态的继承父类的公有属性。
js回忆录(4) -- 对象,构造函数的更多相关文章
- js面向对象(对象/类/工厂模式/构造函数/公有和原型)
https://www.cnblogs.com/sandraryan/ 什么是对象 js中一切都是对象(有行为和特征).js允许自定义对象,也提供了内建对象(string date math等) 对象 ...
- js工厂函数创建对象与对象构造函数的理解
工厂函数,顾名思义,就是通过一个"工厂的加工" 来创建一个对象的函数 //工厂函数 function createPerson(name,sex){ sex = sex == '男' ? '女' : ...
- 程序猿都没对象,JS竟然有对象?
现在做项目基本是套用框架,不论是网上的前端还是后端框架,也会寻找一些封装好的插件拿来即用,但还是希望拿来时最好自己过后再回过头了解里面的原理,学习里面优秀的东西,不论代码封装性,还是小到命名. 好吧, ...
- 浅解析js中的对象
浅解析js中的对象 原文网址:http://www.cnblogs.com/foodoir/p/5971686.html,转载请注明出处. 前面的话: 说到对象,我首先想到的是每到过年过节见长辈的时候 ...
- 170104、js内置对象与原生对象
内置对象与原生对象 内置(Build-in)对象与原生(Naitve)对象的区别在于:前者总是在引擎初始化阶段就被创建好的对象,是后者的一个子集:而后者包括了一些在运行过程中动态创建的对象. 原生对象 ...
- JavaScript学习12 JS中定义对象的几种方式
JavaScript学习12 JS中定义对象的几种方式 JavaScript中没有类的概念,只有对象. 在JavaScript中定义对象可以采用以下几种方式: 1.基于已有对象扩充其属性和方法 2.工 ...
- js object(对象)
http://www.cnblogs.com/pingchuanxin/p/5773326.html Object(对象)是在所有的编程语言中都十分重要的一个概念,对于事物我们可以把他们看作是一个对象 ...
- JavaScript学习12 JS中定义对象的几种方式【转】
avaScript学习12 JS中定义对象的几种方式 转自: http://www.cnblogs.com/mengdd/p/3697255.html JavaScript中没有类的概念,只有对象. ...
- JS中有关对象的继承以及实例化、浅拷贝深拷贝的奥秘
一.属性的归属问题 JS对象中定义的属性和方法如果不是挂在原型链上的方法和属性(直接通过如类似x的方式进行定义)都只是在该对象上,对原型链上的没有影响.对于所有实例共用的方法可直接定义在原型链上这样实 ...
- Js中Map对象的使用
Js中Map对象的使用 1.定义 键/值对的集合. 2.语法 mapObj = new Map() 3.备注 集合中的键和值可以是任何类型.如果使用现有密钥向集合添加值,则新值会替换旧值. 4.属性 ...
随机推荐
- Qt编写安防视频监控系统31-onvif设备搜索
一.前言 做视频监控系统,绕不过onvif这玩意,这玩意主要就是为了统一一个大概的标准,能够对各个厂家的监控设备进行常用的一些操作,比如搜索.获取信息.云台控制.事件订阅.抓拍图片等,如果没有这个规范 ...
- elementPlus 问题总结
第一次搞,遇上很多弱智问题,记录一下 安装elementPlus $ npm install element-plus --save 全局引入 import ElementPlus from 'ele ...
- spark (四) RDD概念
目录 1. RDD基本概念 1.1 弹性 1.2 分布式 1.3 数据集 1.4 数据抽象 1.5 不可变 1.6 可分区.并行计算 2. WordCount为例,看RDD特性 3. RDD的五大属性 ...
- 老生常谈——分布式限流:部分Sentinal源码解读
基础知识 HTTP CODE = 429 "请求过多" A. 限流的类型 服务端 客户端 限流的标的 IP 用户 ... 基本要求 准确限制过量的请求. 低延时.限流器不能拖慢HT ...
- 记一次 contentInsetAdjustmentBehavior 引发的bug
注:本文同步发布于微信公众号:stringwu的互联网杂谈记一次 contentInsetAdjustmentBehavior 引发的bug 1 背景 项目中使用到了UILable来展示相关的文本内容 ...
- weixueyuan-Nginx负载均衡7
https://www.weixueyuan.net/nginx/load_balanc/ Nginx负载均衡模块简述 Nginx 负载均衡是由代理模块和上游(upstream)模块共同实现的,Ngi ...
- layui table表格单元格动态合并,并设置隔行变色
layui table表格单元格动态合并,并设置隔行变色,此代码只针对嵌套数组只有一层的时候有效,多个数组嵌套还在冥想当中!! 需求描述 我们知道在layui插件官方平台有个可以无限极单元格合并的模块 ...
- 一个基于 Roslyn 和 AvalonEdit 的跨平台 C# 编辑器
前言 今天大姚给大家分享一个基于 Roslyn 和 AvalonEdit 开源.轻量.跨平台的 C# 编辑器:RoslynPad. Roslyn介绍 Roslyn是一个强大的.NET编译器实现,为C# ...
- C 将十进制数转换成二~十六进制数中的任意一种
问题:将一个十进制整数转换成二~十六进制数中的任意一种进制数 代码: #include <stdio.h> #include <stdlib.h> int b; int i = ...
- 面向对象-下(复习:关键字static、单例模式、main()的使用说明、类的结构代码块、属性的赋值顺序、关键字final)
一.关键字:static static:静态的1.可以用来修饰的结构:主要用来修饰类的内部结构属性.方法.代码块.内部类2.static修饰属性:静态变量(或类变量) 2.1 属性,是否使用stati ...