JavaScript中的原型和对象机制

1 对象相关的一些语言特性

1.1 一切皆为对象
JavaScript里所有的东西都是对象. 对象是属性的集合. 数字, 字符串, 布尔值等原始值是"伪对象", 它们同样拥有属性, 但是是在栈上分配并按值传递. 而其他的对象是堆上分配并按引用传递.
一个很重要的概念是, 函数也是对象, 能够作为变量的值, 返回值, 参数或者属性的值. 函数对象特殊的地方是能通过"xxx()"语法执行包含在xxx函数对象内的代码. 因为这一特殊性, typeof xxx 将会返回function, 但这只是一种便利设施.

1.2 对象的属性可以动态添加和删除

复制代码
var foo = new Object();
// 为foo对象添加bar属性
foo.bar = "foobar";
alert(foo.bar); //foobar
// 删除foo对象的bar属性
delete foo.bar;
alert(foo.bar); //undefined
复制代码


1.3 除了宿主对象, 其它对象皆由构造函数创建
要有对象, 就先要有创建对象的方法. 
在C++/Java等语言, 这个方法就是实例化XXX类的一个实例xxx.
而在JavaScript的世界里实际没有类的东西, 当然仍然可以用"类"和"实例"等惯用语来描述JavaScript中类似的行为, 但其机制是完全不同的. JavaScript的对象是由构造函数创建的, 每个对象都有constructor属性表示创建该对象的构造函数:

复制代码
function Test() { this.a = "hello"; }
var test = new Test(); // 由Test构造函数创建
alert(test.constructor);

var o = { a: "hello" };
//实际相当于
var o_ = new Object();
o_.a = "hello"; // 由Object构造函数创建
alert(o.constructor);
复制代码

构造函数也是对象, 那构造函数是由什么创建? 内建的Function函数:

function Test(a, b)
{
    alert(a+b);
}
// 相当于:
Test = new Function(["a", "b"], "alert(a+b);");

Function函数又是由什么创建? 实际上Function是本机代码实现的固有对象. 不过为了一致性, Function也有constructor属性, 该属性指向它自己. 接上面的代码:

复制代码
/* 输出 function Function(){
            [native code]
        }
*/
alert(Test.constructor);

alert(Test.constructor.constructor === Test.constructor); // true
alert(Test.constructor === Object.constructor); // true
复制代码


2 原型prototype
2.1 prototype的概念
prototype是构造函数的一个属性, 该属性指向一个对象. 而这个对象将作为该构造函数所创建的所有实例的基引用(base reference), 可以把对象的基引用想像成一个自动创建的隐藏属性. 当访问对象的一个属性时, 首先查找对象本身, 找到则返回; 若不, 则查找基引用指向的对象的属性(如果还找不到实际上还会沿着原型链向上查找,  直至到根). 只要没有被覆盖的话, 对象原型的属性就能在所有的实例中找到.
原型默认为Object的新实例, 由于仍是对象, 故可以给该对象添加新的属性:

复制代码
// prototype默认为new Object(); 为了方便, 记为p_obj
function Person(name) {
    this.name = name;
}

// 为 p_obj 增加 sayName 属性
Person.prototype.sayName = function(){
    alert(this.name);
}

var john = new Person("John"); // john 的 base reference指向p_obj
var eric = new Person("Eric");  // eric 的 base reference也是指向p_obj

// 注意sayName代码中的this将指向实例化后的对象(this绑定)
john.sayName(); // john对象本身没有sayName属性, 于是访问原型对象p_obj的sayName属性
eric.sayName(); // 访问同一个原型对象p_obj的sayName属性


var tmp = Person.prototype;
tmp.boss = "David";
// 于这个运行点, p_obj已经被修改
// 根据上述属性访问流程, 新的修改(boss属性)能反映到所有的实例, 包括已经创建和即将创建的
alert("John's boss is " + john.boss);
alert("Eric's boss is " + eric.boss);


// hisCar和sayCar属性将增加到john对象而不是p_obj对象..
john.hisCar = "Audi";
john.sayCar = function(){
    alert(this.name + " has a car of " + this.hisCar);
}
john.sayCar();
// ..因此下一句将错误, 因为eric对象本身和原型p_obj都没有sayName属性
/* eric.sayCar(); */
复制代码


2.2 原型链
除了能修改prototype指向的对象, 还能修改prototype指向哪一个对象, 即为prototype赋予一个不同的对象. 这可以实现一种简单的继承:

复制代码
function Superman() {}
Superman.prototype.sayHello = function(){
    alert("I'm a superman.");
}

function SupermanCan(skill){
    this.skill = skill;
}
// 为prototype赋予Superman的实例..
SupermanCan.prototype = new Superman();
// ..再动态添加新的属性
SupermanCan.prototype.sayMore = function(){
    this.sayHello(); // 调用"父类"的方法
    alert("I can " + this.skill);
}

var david = new SupermanCan("fly");
// output: I'm a superman. I can fly
david.sayMore();
复制代码

如果先实例化出一个对象, 再为构造函数prototype赋予一个不同的对象, 将会: 已经创建的对象的基引用不变, 将来创建的对象的基引用为新的原型对象:

复制代码
var f1 = {echo: function() { alert("sound"); } };
function Foo() {};
var foo = new Foo(); // foo的基引用指向Object实例
Foo.prototype = f1;
/* 未定义, 因为这是"foo对象自己或者基引用指向的对象有echo属性吗?"
   而不是"foo对象自己或者Foo.prototype指向的对象有echo属性吗?" */
alert(foo.echo);

var foo2 = new Foo(); // foo2的基引用指f1对象
foo2.echo(); // output: sound
复制代码

所有的构造函数的prototype都不能为空, 就是说Superman.prototype = null 会被解释引擎无视;  另一方面, Object构造函数也有prototype属性(该属性是只读的, 可以为原型增加属性,但不能赋予不同的对象), 故因此可以有多层的原型链, 但原型链的根必定会是Object.prototype . 这意味着给Object.prototype增加属性影响到所有对象:

复制代码
Object.prototype.echo = function() {
    alert("hello");
}

// echo属性将增加到所有对象固有对象和自定义对象

var arr = new Array();
arr.echo();
Array.echo();

function ObjCons()    {
    this.dummy = "d";
}
var obj = new ObjCons();
obj.echo();
ObjCons.echo();
复制代码


3. 构造函数和new的实质
构造函数是一个地地道道的函数, 一个函数之所以能成为构造函数, 是因为new运算符:

复制代码
this.msg = "window";

function Test()
{
    alert(this.msg);
}

Test(); // window
var test = new Test(); // undefined. 因为test对象没有定义msg属性
复制代码

二者区别在于如何切入对象: Test() 在某个对象(例子中为window)的上下文上执行代码, 即this指向这个对象; new Test()创建一个新对象, 并以这个新的对象为上下文(this指向新对象)执行代码, 然后返回这个新对象. 
假如有个函数:

function Test() {
    var dummy = "have money";
    this.wish = dummy;
    doSomeThing();
    
}

结合以上的所有论述, 可以推测new Test()行为的伪代码表示为:
      创建一个新对象temp;
      temp.constructor = Test;
      temp.(base reference) = Test.prototype; // 这一句先于代码体执行, 意味着构造函数里的this.xxx能访问原型对象的属性xxx
      bind: this = temp; // 将this绑定到temp对象
      // 开始执行函数代码
      var dummy = "have money";
      this.wish = dummy; // 为temp对象添加wish属性
      doSomeThing();
      ....
      // 结束执行函数代码
      return temp;
这个未必会符合内部的二进制实现, 但却能很好地解释了JavaScript的特性.

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

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

相关文章

【 Grey Hack 】记一次被黑经历

目录又被搞了版本:Grey Hack v0.7.3618 - Alpha 胆大包天的我黑进游戏内shop的IP后,顺着其上面的日志溯源到不少疑似其他玩家租的服务器,暂时没什么进展 不久后回到桌面才发现自己已经被黑入了 随后我打开日志查看记录 只看清是从我的1222…

【 Grey Hack 】加强版nmap

目录probe使用方法效果routerpcscan使用方法效果版本&#xff1a;Grey Hack v0.7.3618 - Alpha probe if params.len ! 1 or params[0] "-h" or params[0] "--help" then exit(command_info("<b>probe [IP]</b>")) if not is_va…

文档容器iOS网络编程-iCloud文档存储编程实例

在本文中,我们主要绍介文档容器的容内,自我感觉有个不错的建议和大家分享下 iCloud文档存储程编对相键值据数存储而言比较复杂&#xff0c;涉及到自定义文档类、取得iCloud文档录目、找查Ubiquity容器中的文档、保存文档和决解文档冲突等容内。 实例&#xff1a;iCloud文档存储…

CSS3之伪元素选择器和伪类选择器

伪类选择器&#xff0c;和一般的DOM中的元素样式不一样&#xff0c;它并不改变任何DOM内容。只是插入了一些修饰类的元素&#xff0c;这些元素对于用户来说是可见的&#xff0c;但是对于DOM来说不可见。伪类的效果可以通过添加一个实际的类来达到。 a:link|a:visited|a:hover|a…

CSS只是进化的一部分

Bert Bos是一位计算机科学家&#xff0c;他也是CSS的创始人之一。在CSS的发展过程中&#xff0c;Bos是最早与Hkon Wium Lie&#xff08;CSS之父&#xff09;合作的人之一。在1996年&#xff0c;他加入了World Wide Web Consortium&#xff08;W3C&#xff09;负责CSS的开发。他…

【 Grey Hack 】WIFI万能钥匙

目录脚本源码使用方法效果版本&#xff1a;Grey Hack v0.7.3618 - Alpha 脚本源码 computer get_shell.host_computer status "Unknown Error." crypto include_lib("/lib/crypto.so") if not crypto thencrypto include_lib(current_path "/cr…

面向对象编程学习5月7日-5月23日 网络直播yii-外企使用最多的PHP框架

每日一贴,今天的内容关键字为面向对象编程学习 课程说明: -------------------------------------------------------------------------------------------------------------- 9天玩转大型php框架Yii&#xff08;即将开始&#xff09;&#xff08;如何加入费免公然讲堂&#…

PHP 四种基本排序算法的代码实现(2)

2019独角兽企业重金招聘Python工程师标准>>> 许多人都说算法是程序的核心&#xff0c;算法的好坏决定了程序的质量。作为一个初级phper&#xff0c;虽然很少接触到算法方面的东西。但是对于基本的排序算法还是应该掌握的&#xff0c;它是程序开发的必备工具。这里介…

【 Grey Hack 】综合工具 shellOs

目录交互界面基本功能本地攻击攻击本机远程攻击应用程序扫描功能更新IP并扫描深度扫描黑入功能类shell交互界面一些特殊命令bouncerunScanPswvimbuild脚本源码版本&#xff1a;Grey Hack v0.7.3619 - Alpha 交互界面 基本功能 使用cd命令和数字选项切换路径 本地攻击 攻击本…

HIVE 一行转多行输出办法

2019独角兽企业重金招聘Python工程师标准>>> 1.问题描述 hive UDF 格式&#xff1a;oc号1_an号1_次数;oc号2_an号2_次数 转换结果&#xff1a; oc号1 an号1 次数 oc号2 an号2 次数 一行转多行&#xff0c;一行转多列 2.实现思路 第一步分割&#xff1a;split(oc号…

【机器视觉学习笔记】直方图的绘制及直方图均衡化(C++)

目录概念直方图定义直方图均衡化为什么要选用累积分布函数如何运用累积分布函数使得直方图均衡化C 源码直方图均衡化绘制直方图主函数效果完整源码平台&#xff1a;Windows 10 20H2 Visual Studio 2015 OpenCV 4.5.3 本文综合自直方图计算和程序员-图哥——图像处理之直方图均…

C/C++ 如何劫持别人家的命令||函数||程序(只能对于window而言)

要实现下面程序&#xff0c;首先我们需要三个文件 detours.h &#xff0c;detours.lib &#xff0c;detver.h&#xff08;可以去网上下载&#xff09; 1. 首先让我们看看&#xff0c;一个最简单的C程序&#xff0c;如何劫持system函数. 1 #include<stdio.h>2 #include<…

【机器视觉学习笔记】伽马变换(C++)

目录概念C源码变换函数主函数效果完整源码平台&#xff1a;Windows 10 20H2 Visual Studio 2015 OpenCV 4.5.3 本文内容节选自《数字图像处理》第三版 C源码修改自C数字图像处理&#xff08;1&#xff09;-伽马变换 —— 图像大师 概念 C源码 变换函数 //函数名&#xff1…

Linux文件查找之find秘笈

前言Linux的基本特点之一是一切皆文件&#xff0c;在系统管理过程中难免会需要查找特定类型的文件&#xff0c;那么问题来了&#xff1a;如何进行有效且准确的查找呢&#xff1f;本文将对Linux系统中的文件查找工具及用法进行详细讲解。常用工具对比常用的文件查找工具主要有lo…

【机器视觉学习笔记】大津法/Otsu最大类间方差法 最佳阈值处理(C++)

目录概念C源码OtsuThreshold主函数效果完整源码平台&#xff1a;Windows 10 20H2 Visual Studio 2015 OpenCV 4.5.3 本文所用源码修改自C opencv 图片二值化最佳阈值确定&#xff08;大津法,OTSU算法)——Sharon Liu 概念 Otsu算法&#xff0c;也叫最大类间方差法&#xff0…

HTML 页面源代码布局介绍

此介绍以google首页源代码截图为例&#xff1a; 从上到下依次介绍&#xff1a; 1.<!DOCTYPE html> 此标签可告知浏览器文档使用哪种 HTML 或 XHTML 规范。 XHTML规范&#xff1a;必须小写&#xff0c;有开始结束标签&#xff0c;属性也用双引号。 HTML规范&#xff1a;不…

Python对Protobuf进行序列化与反序列化

Python Protobuf1.了解Protobuf&#xff1a;1.1 Protobuf语法介绍&#xff1a;2. Python使用Protobuf&#xff1a;(windows平台上)1.了解Protobuf&#xff1a; 我们在使用protobuf之前首先要了解protobuf&#xff0c;那么什么是protobuf呢&#xff1f; 官方的解释是&#xff…

sql server management studio 查询的临时文件路径

C:\Users\你的登录名称\Documents\SQL Server Management Studio\Backup FilesC:\Users\你的登录名称\AppData\Local\Temp\sql server management studio 非正常关闭时自动保存的路径在sql server management studio 里创建的“新建查询”且没有手动保存的路径转载于:https://w…

K210 / Openmv实现 大津法/Otsu最大类间方差法 自适应二值化

目录源码效果平台&#xff1a;K210 固件版本&#xff1a;maixpy_v0.6.2_54_g897214100_openmv_kmodel_v4_with_ide_support.bin OpenMv库自带Otsu算法: 源码 # Otsu.py - By: Royic - 周三 9月 22 2021import sensor, imagesensor.reset() sensor.set_pixformat(sensor.GRAY…

第一章:OpenCV入门

第一章&#xff1a;OpenCV入门 OpenCV是一个开源的计算机视觉库&#xff0c;1999年有英特尔的Gary Bradski启动。OpenCV库由C和C语言编写&#xff0c;涵盖计算机视觉各个领域内的500多个函数&#xff0c;可以在多个操作系统上运行。它旨在提供一个简洁而又高效的接口&#xff…