JavaScript对象的property属性详解
JavaScript对象的property属性详解:https://www.jb51.net/article/48594.htm
JS原型与原型链终极详解_proto_、prototype及constructor:https://blog.csdn.net/bluesky1215/article/details/54891147
一. 普通对象与函数对象
JavaScript 中,万物皆对象!但对象也是有区别的。分为普通对象和函数对象,Object ,Function 是JS自带的函数对象。下面举例说明
function f1(){};
var f2 = function(){};
var f3 = new Function('str','console.log(str)');
var o3 = new f1();
var o1 = {};
var o2 =new Object();
console.log(typeof Object); //function
console.log(typeof Function); //function
console.log(typeof o1); //object
console.log(typeof o2); //object
console.log(typeof o3); //object
console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof f3); //function
在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,归根结底都是通过 new Function()的方式进行创建的。Function Object 也都是通过 New Function()创建的。
二. 原型对象
在JavaScript 中,每当定义一个对象(函数)时候,对象中都会包含一些预定义的属性。其中函数对象的一个属性就是原型对象 prototype。注:普通对象没有prototype,但有__proto__属性。
原型对象其实就是普通对象(Function.prototype除外,它是函数对象,但它很特殊,他没有prototype属性(前面说道函数对象都有prototype属性))。看下面的例子:
function f1(){};
console.log(f1.prototype) //f1{}
console.log(typeof f1. prototype) //Object
console.log(typeof Function.prototype) // Function,这个特殊
console.log(typeof Object.prototype) // Object
console.log(typeof Function.prototype.prototype) //undefined
从这句console.log(f1.prototype) //f1 {} 的输出就结果可以看出,f1.prototype就是f1的一个实例对象。就是在f1创建的时候,创建了一个它的实例对象并赋值给它的prototype,基本过程如下:
var temp = new f1();
f1. prototype = temp;
所以,Function.prototype为什么是函数对象就迎刃而解了,上文提到凡是new Function ()产生的对象都是函数对象,所以temp1是函数对象。
var temp1 = new Function ();
Function.prototype = temp1;
那原型对象是用来做什么的呢?主要作用是用于继承。举了例子:
var person = function(name){
this.name = name
};
person.prototype.getName = function(){
return this.name;
}
var zjh = new person(‘zhangjiahao’);
zjh.getName(); //zhangjiahao
从这个例子可以看出,通过给person.prototype设置了一个函数对象的属性,那有person实例(例中:zjh)出来的普通对象就继承了这个属性。具体是怎么实现的继承,就要讲到下面的原型链了。
三.原型链
JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它的函数对象的原型对象prototype。以上面的例子为例:
console.log(zjh.__proto__ === person.prototype) //true
同样,person.prototype对象也有__proto__属性,它指向创建它的函数对象(Object)的prototype
console.log(person.prototype.__proto__ === Object.prototype) //true
继续,Object.prototype对象也有__proto__属性,但它比较特殊,为null
console.log(Object.prototype.__proto__) //null
我们把这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫做原型链。如下图:
四.内存结构图
为了更加深入和直观的进行理解,下面我们画一下上面的内存结构图:
画图约定:
疑点解释:
1.Object.__proto__ === Function.prototype // true
Object是函数对象,是通过new Function()创建,所以Object.__proto__指向Function.prototype。
2.Function.__proto__ === Function.prototype // true
Function 也是对象函数,也是通过new Function()创建,所以Function.__proto__指向Function.prototype。
自己是由自己创建的,好像不符合逻辑,但仔细想想,现实世界也有些类似,你是怎么来的,你妈生的,你妈怎么来的,你姥姥生的,……类人猿进化来的,那类人猿从哪来,一直追溯下去……,就是无,(NULL生万物)
正如《道德经》里所说“无,名天地之始”。
3.Function.prototype.__proto__ === Object.prototype //true
其实这一点我也有点困惑,不过也可以试着解释一下。
Function.prototype是个函数对象,理论上他的__proto__应该指向 Function.prototype,就是他自己,自己指向自己,没有意义。
JS一直强调万物皆对象,函数对象也是对象,给他认个祖宗,指向Object.prototype。Object.prototype.__proto__ === null,保证原型链能够正常结束。
五.constructor
原型对象prototype中都有个预定义的constructor属性,用来引用它的函数对象。这是一种循环引用
person.prototype.constructor === person //true
Function.prototype.constructor === Function //true
Object.prototype.constructor === Object //true
完善下上面的内存结构图:
有两点需要注意:
(1)注意Object.constructor===Function;//true 本身Object就是Function函数构造出来的
(2)如何查找一个对象的constructor,就是在该对象的原型链上寻找碰到的第一个constructor属性所指向的对象
六.总结
1.原型和原型链是JS实现继承的一种模型。
2.原型链的形成是真正是靠__proto__ 而非prototype
要深入理解这句话,我们再举个例子,看看前面你真的理解了吗?
var animal = function(){};
var dog = function(){};
animal.price = 2000;//
dog.prototype = animal;
var tidy = new dog();
console.log(dog.price) //undefined
console.log(tidy.price) // 2000
为什么呢?画一下内存图:
这说明什么问题呢,执行dog.price的时候,发现没有price这个属性,虽然prototype指向的animal有这个属性,但它并没有去沿着这个“链”去寻找。同样,执行tidy.price的时候,也没有这个属性,但是__proto__指向了animal,它会沿着这个链去寻找,animal中有price属性,所以tidy.price输出2000。由此得出,原型链的真正形成是靠的__proro__,而不是prototype。
因此,如果在这样指定dog.__proto__ = animal。那dog.price = 2000。
最后打个比喻,虽然不是很确切,但可能对原型的理解有些帮助。
父亲(函数对象),先生了一个大儿子(prototype),也就是你大哥,父亲给你大哥买了好多的玩具,当你出生的时候,你们之间的亲情纽带(__proto__)会让你自然而然的拥有了你大哥的玩具。同样,你也先生个大儿子,又给他买了好多的玩具,当你再生儿子的时候,你的小儿子会自然拥有你大儿子的所有玩具。至于他们会不会打架,这不是我们的事了。
所以说,你是从你大哥那继承的,印证了那句“长兄如父”啊!
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
在谈原型链之前,我们首先要了解自定义函数与 Function 之间是什么关系,而构造函数、原型和实例之间又存在什么千丝万缕的关系呢?其实,所有的函数都是 Function 的实例。在构造函数上都有一个原型属性 prototype,该属性也是一个对象;那么在原型对象上有一个 constructor 属性,该属性指向的就是构造函数;而实例对象上有一个 _proto_ 属性,该属性也指向原型对象,并且该属性不是标准属性,不可以用在编程中,该属性用于浏览器内部使用。
1 // _proto_
2 在函数里有一个属性prototype
3 由该函数创建的对象默认会连接到该属性上
4 //prototype 与 _proto_ 的关系
5 _proto_是站在对象角度来说的
6 prototype 是站在构造函数角度来说的
下面,我们来看图说话。
了解这些之后,我们再来讨论什么是原型链。说白了,其实就是有限的实例对象和原型之间组成有限链,就是用来实现共享属性和继承的。下面,我们看代码说话。
1 var obj = new Object();
2 对象是有原型对象的
3 原型对象也有原型对象
4 obj._proto_._proto_._proto_
5 原型对象也有原型对象,对象的原型对象一直往上找,会找到一个null
6 // 原型链示例
7 var arr = [];
8 arr -> Array.prototype ->Object.prototype -> null
9 var o = new Object();
10 o -> Object.prototype -> null;
function Foo1(){
this.name1 = '1';
}
function Foo2(){
this.name2 = '2';
}
Foo2.prototype = new Foo1();
function Foo3(){
this.name = '3';
}
Foo3.prototype = new Foo2();
var foo3 = new Foo3();
console.dir(foo3);
接下来就是继承问题了。
2、继承
1)原型继承
1 function Animal(name){
2 this.name = name;
3 }
4 function Tiger(color){
5 this.color = color;
6 }
7 // var tiger = new Tiger('yellow');
8 // console.log(tiger.color);
9 // console.log(tiger.name); //undefined
10 // Tiger.prototype = new Animal('老虎'); //一种方式
11 Object.prototype.name = '大老虎'; //第二种方式
12 var tiger = new Tiger('yellow');
13 console.log(tiger.color);
14 console.log(tiger.name);
2)ES5 提供了Object.create() 方法来实现继承
1 ————做兼容
2 //shim垫片
3 function create(obj){
4 if(Object.create){
5 return Object.create(obj);
6 }else{
7 function Foo(){}
8 Foo.prototype = obj;
9 return new Foo();
10 }
11 }
这种方法是ES5的新特性,其实就是复制继承。
1 var obj = {};
2 obj.extend = function(obj){
3 for(var k in obj){
4 this[k] = obj[k];
5 }
6 }
1 function Animal(name){
2 this.name = name;
3 }
4 function Mouse(nickname){
5 Animal.call(this,'老鼠');
6 this.nickname = nickname;
7 }
8 var m = new Mouse('杰瑞');
9 console.log(m.name);
10 console.log(m.nickname);
存在的问题:可以解决原型继承当中传参问题,但是父类型当中的原型对象上的成员(属性和方法)不能被继承到
1 function Person(name){
2 this.name = name;
3 }
4 Person.prototype.showName = function(){
5 console.log(this.name);
6 }
7 function Student(name,age){
8 Person.call(this,name);
9 this.age = age;
10 }
11 Student.prototype = new Person();
12 Student.prototype.contructor = Student;
13 Student.prototype.showAge = function(){
14 console.log(this.age);
15 }
16 var stu = new Student('张三',12);
17 stu.showName();
18 stu.showAge();
【原型继承+借用构造函数继承】它的特点就是属性每个实例一份,方法共享
【小结】套用一句很粗暴的话,所谓原型链就是找妈的一种行为方式,就可以理解为人是人他妈生的,妖是妖他妈生的。原型链的核心其实就只有一个:属性共享和独立的控制,当你的对象实例需要独立的属性,所有做法的本质都是在对象实例里面创建属性。若不考虑太多,你大可以在Person里面直接定义你所需要独立的属性来覆盖掉原型的属性。总之,使用原型继承的时候,要对于原型中的属性要特别注意,因为他们都是牵一发而动全身的存在。现在最常用的方法是组合模式。
1、原型链
1)构造函数、原型和实例的关系
①prototype是构造函数的属性
②_proto_是实例对象的属性
——这两者都指向同一个对象
【总结】i)函数也是对象,对象不一定是函数;
ii)对象的本质:无序的键值对集合;键值对当中的值可以是任意数据类型的值
iii)对象就是一个容器,这个容器当中放的是(属性和方法)
3)属性搜索
①在访问对象的某个成员的时候会先在对象中找是否存在
②如果当前对象中没有就在构造函数的原型对象中找
③如果原型对象中没有找到就到原型对象的原型上找
④知道Object的原型对象的原型是null为止
2、Function
——所有函数都是Function的实例
①本地对象:独立于宿主环境(浏览器)的对象——包括Object、Array、Date、RegExp、Function、Error、Number、String、Boolean
②内置对象——包括Math、Global(window,在js中就是全局变量),使用的时候不需要new
③宿主对象——包括自定义对象、DOM、BOM
转载:http://www.108js.com/article/article1/10201.html?id=1092
转载:http://www.cnblogs.com/DF-fzh/p/5619319.html
JavaScript对象的property属性详解的更多相关文章
- asp.net中C#对象与方法 属性详解
C#对象与方法 一.相关概念: 1.对象:现实世界中的实体 2. 类:具有相似属性和方法的对象的集合 3.面向对象程序设计的特点:封装 继承 多态 二.类的定义与语法 1.定义类: 修饰符 类名称 ...
- [Objective-c 基础 - 3.3] @property属性详解
ARC 自动引用计数 ARC不是垃圾回收,而是编译器自动插入代码来减少程序员的代码输入和失误. 同时比垃圾和效率要高,因为其不影响运行时间,相当于自己管理内存. 总是通过属性来 ...
- JavaScript RegExp.$1...$9 属性详解
RegExp.$1...$9属性用于返回正则表达式模式中某个子表达式匹配的文本. 正则表达式中每个小括号内的部分表达式就是一个子表达式. 该属性是RegExp全局对象的一个只读属性,所有主流浏览器均支 ...
- arguments对象的callee属性详解
在函数内部,有两个特殊的对象:arguments和this. argument对象有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数.请看下面这个非常经典的阶乘函 ...
- javascript 节点属性详解
javascript 节点属性详解 根据 DOM,html 文档中的每个成分都是一个节点 DOM 是这样规定的:整个文档是一个文档节点每个 html 标签是一个元素节点包含在于 html 元素中的文本 ...
- Javascript中prototype属性详解 (存)
Javascript中prototype属性详解 在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不 ...
- 007-Scala类的属性和对象私有字段实战详解
007-Scala类的属性和对象私有字段实战详解 Scala类的使用实战 变量里的类必须赋初值 def函数时如果没参数可不带括号 2.不需要加Public声明 getter与setter实战 gett ...
- CorelDRAW中如何复制对象属性详解
复制对象属性是一种比较特殊.重要的复制方法,它可以方便而快捷地将指定对象中的轮廓笔.轮廓色.填充和文本属性通过复制的方法应用到所选对象中.本教程将详解CorelDRAW中如何复制对象属性. Corel ...
- java使用POI操作XWPFDocument中的XWPFRun(文本)对象的属性详解
java使用POI操作XWPFDocument中的XWPFRun(文本)对象的属性详解 我用的是office word 2016版 XWPFRun是XWPFDocument中的一段文本对象(就是一段文 ...
随机推荐
- .net core 简单集成JWT报No authenticationScheme was specified, and there was no DefaultChallengeScheme found错误
#region JWT 认证 services .AddAuthentication(JwtBearerDefaults.AuthenticationScheme) //.AddCustomAuth( ...
- linux 日常学习
杀掉进程 ps aux |grep caddy axy5418+ 14186 0.0 1.7 117032 10372 ? Sl 02:17 0:00 caddy axy5418+ 14332 0.0 ...
- matlab批量修改变量的名称
使用matlab做实验的时候,保存的文件里面的变量名都是一样的 ,所以希望能够把变量名全部都重命名.我举个个例子,假设我一堆文件,文件名分别是gds1,gds2,gds2,-.. 但是实际上load进 ...
- ajax_封装函数_步骤1
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...
- LuaLuaMemorySnapshotDump-master
https://codeload.github.com/yaukeywang/LuaMemorySnapshotDump/zip/master
- 2018-11-3-git-分支改名
title author date CreateTime categories git 分支改名 lindexi 2018-11-3 12:49:9 +0800 2018-2-13 17:23:3 + ...
- 系统调用system_call处理过程
原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 作者:严哲璟 linux的系 ...
- center os7 安装mysql
安装mariadb MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可.开发这个分支的原因之一是:甲骨文公司收购了MySQL后,有将MySQL闭源的潜在风险, ...
- ftp 上传文件时报 cant open output connection for file "ftp://129.28.149.240/shop/web/index.html". Reason: "550 Permission denied.".
原因:没有写入权限 修改权限即可 vsftpd.conf vim /etc/vsftpd.conf write_enable=YES #加入这句
- Python常用内置函数整理(lambda,reduce,zip,filter,map)
匿名函数lambda lambda argument1,argument2,...argumentN :expression using arguments 1.lambda是一个表达式,而不是一个语 ...