JavaScript Oriented[探究面向对象的JavaScript高级语言特性]

JavaScript Oriented

探究面向对象的JavaScript高级语言特性

Prologue . JavaScript Introduce

1.  JS

Abstract

JavaScript是由Netscape公司工程师Brendan Eich研发的脚本语言,经过推广和流行,兼容ECMA-262标准,至今用于描述HTML网页行为。(前端验证,检测,响应,触发,控制等动态行为)

Knowledge Tree

2.     About Document

本文涉及到的概念有JavaScript概述,对象类型系统,原型链,作用域链以及上下文this,闭包,命名空间以及面向对象的高级语言特性应用。

JavaScript知识点庞杂且个人能力和学习时间有限,希望得到有心者更多的鼓励与启发。

Chapter one . Type Family

1.  That’s all Object things?

从面向对象角度理解,JS确实一切皆对象。但是JS是函数式编程,从面向过程角度可以理解为一切皆函数,这可能是JavaScript魅力所在。本文叫做面向JavaScript,偏向从面向对象角度理解。

如何理解“一切皆对象”。一般来说我们会从对象构造器和原型链解释,本文后文中有详细概述,这里不作初步探讨。

2.     Begin from GLOBAL

这里我们从JS最特殊的内置对象GLOBAL开始。


介绍


GLOBAL是ECMAScript5规范中两个内置对象其中之一,表示全局对象。


作用


任何不属于JavaScript其他对象的属性和方法都属于GLOBAL。


实现


JavaScript对其并没有明确的实现。浏览器将GLOBAL作为宿主对象Window的一部分实现。

JSEngine的起始阶段就是实例化一个Window对象。

这也解释了(this === window) == true;


属性


预定义对象


Object Array Function Boolean String Number Date RegExp Error EvalError RangeError ReferenceError SyntaxError TypeError URIError(作为函数原型的构造器)


全局属性


undefined NaN Infinity …


全局函数


编解码


decodeURI()/decodeURIComponent()/encodeURI()/

encodeURIComponent()/escape()/unescape()


转换


getClass()/Number()/String()/parseFloat()/parseInt()


判断


isFinite()/isNaN()


执行


eval()


用户定义


如var _temp_val = {}; // window._temp_val = {};全局变量混乱问题


Tips:全局属性可以直接使用而不用[window. ] Object,同时除了用户定义以为的属性不能delete

在JS引擎启动并实例化window对象时,JS原生对象和浏览器对象全部作为预定义对象放置在window中。

当我们需要新建对象时,首先对象原型将会依据这些预定义对象被构建。

举个小栗砸:(这里有一些构造器和原型链的应用,对后面章节的梳理有帮助。)

var window.namespaceA = [];//声明命名空间

namespaceA.A = {…};//声明函数,JS引擎加载时将A.prototype丢到堆内存

var a = Object.create(A.prototype,{ …args });

JS引擎行为

Object() = window.Object.prototype.constructor;//Object构造函数

Function() = window.Function.prototype.constructor;//Function构造函数

A() = window.namespaceA.A.prototype.constructor; // A构造函数

a = new A({ …args});//以A对象为原型实例化引用a

a.[[prototype]] = A.prototype;

3. We Are Family

该图总结并参考了ECMAScript5规范,如有错误请指出。

部分对象请参考W3C教程:http://www.w3school.com.cn/jsref/index.asp

Chapter two . User Object

这一篇章进入对象的讲解,讲述在当前JS执行环境executable code(ECStack)中,如何创建一个原型实例对象。分配内存,形成作用域链与原型链。改变执行控制权并返回对象。

总结:this new a object by prototype chain in ECStack, then this got return and leave ECStack.

1.     Context – ECStack

JS引擎执行过程是JS对象的生命周期的交替的过程,JS引擎解析执行。当执行子函数时,会将引擎操作的控制权让给子函数。子函数本身就是一个函数上下文。

window.ECStack = [];//模拟执行环境,实际的执行环境包含window全局上下文

备注:与执行上下文相关的作用域和参数对象在new小节讲解。

执行环境ECStack内存时序结构图如图所示。

2.     WHAT – object

ECMAScript5规范丰富了用户自定义Object对象,提供了Object对象的属性特性。

参考W3C教程:http://www.w3school.com.cn/js/pro_js_referencetypes.asp

备注: JSON对象拓展,使用JSON. Stringify(/*Object*/)和JSON.parse(/*String*/)进行对象序列化,有时依赖引用对象的toJSON()方法。

3.     TYPE – prototype chain

JS是元解释型语言,当JS引擎执行JS代码时,会分析语法结构,并将得到的对象结构放置在堆内存中,称为原型。内存中的所有对象都包含一个属性[[prototype]]指针指向堆内存的原型,FireFox,Chrome等浏览器将该属性定义为__proto__可显示调用。

酱:Foo.__proto__ à Foo.prototype

同时原型对象存在原型,形成一条原型链。当JS引擎实例化window对象构造全局上下文this时,堆内存中生成如下原型链:

图中每一个矩形都是一个原型对象。每个原型对象都有自己的构造器函数。

酱:Foo.prototype.constructor == Foo();//注意这里是函数,只是JS允许写成Foo。

我将JAVA与JavaScript做类比,虽然这样可能不太妥当。


JavaScript概念


Java概念


预定义对象,如Object


API对象,如java.lang.Object


内核


JVM


内核初始化window时,原型对象Object.prototype加载到堆内存中


JVM启动后,类信息Object.class加载到方法区中。


Object()//Object.prototype. constructor构造函数


Object构造函数


var obj = new Object();


Object obj = new Object();


obj.__proto__ == Object.prototype


obj.getClass() == Object.class;

Constructor构造函数概念是一个动态概念,意味着运行时内核中的原型对象才包含构造函数。理解预定义对象,原型对象,原型对象构造函数和实例化对象后,需要引申一个概念:如何判定对象类型。


关键字


类型


返回值


说明


typeof


一元运算符


字符串


基本类型undefined string number Boolean

引用类型object 函数类型 function。

不返回null的原因:object JS类型值是存在32 BIT 单元里,32位有1-3位表示TYPE TAG,其它位表示真实值。object的标记位为000。而null标记位为00,最终体现的类型还是object..


instanceof


二元运算符


布尔值


判断除undefined null一个变量是否某个对象的实例,就是看该对象是否在该变量的原型链上。


constructor


函数


构造函数


var temp = obj.constructor.toString();

temp.replace(/^function (\w+)\(\).+$/,‘$1‘);


prototype


对象


原型类型


Object.prototype.toString.call(obj).slice(8,-1).toLowerCase();

这时候我们可以把本节原型链内存结构图补齐啦:

当查询对象的属性时,若该对象不存在该属性,则在该对象的原型链中向上查找对象原型是否存在该属性。若存在,则返回该属性,若直到原型为null时仍未找到该属性,返回undefined。

javascript找属性就是找最近的,找不着就找他爹。

4.     WHO – this

this是当前执行环境上下文的一个属性。JavaScript是单线程的,意味着JS内核执行JS代码切换上下文,this就会改变。若JS执行到代码片段A,说明包含片段A的上一级内容B正在被加载/实例化,那么B就是this。

ECStack = { VO : {…}, this : thisValue};

初始状态

当浏览器加载请求页面时,卸载原始事件,解析并渲染HTML,驱动当前事件并绑定当前窗口对象。每个窗口都有自己的全局对象,当页面被加载后,window对象实例化并绑定this。

function main(){
                window = new Window();

this.call(window);//扩展this环境对象,其实只有函数对象才有call方法

|

无状态

这一块并没有过多的代码演示。个人有两点理解。

  1. A调用方法a,则a方法内的this为A。
  2. 若A中没有a方法,则a方法内的this为A原型链上包含方法a最近的原型对象B。

function Foo () {}

Foo.prototype.foo = "bar";

Foo.prototype.logFoo = function () { eval("console.log(this.foo)");
//logs "bar" }

var foo = new Foo ();

foo.logFoo();//foo调用logFoo方法,只有foo原型有logFoo方法,所以Foo.prototype为this

备注:判断a是否是A的自由属性,使用hasOwnProperty方法。

备注:可以使用with,apply,call,bind方法连接this环境上下文,实现属性继承,这里不作过多说明。

5.    
DO – new

Introduce

new关键词实例化一个对象。对象实例化过程,对this的不断赋值,构造参数对象arguments,并维护实例对象的constructor属性。

Step

举个栗砸。使用构造函数自定义对象:

1 function A(/* number*/ id, /*
string*/name){ this.id = id; this.name = name;}

2 var a = new A(1);//a.__proto__ =
A.prototype

分解步骤如下:

  1. 执行1行时,加载A对象构造函数并放入内存,构造原型链

A.prototype.constructor=
A(){…};

A() = new Function();

Function() = new
Object();

  1. 执行2行时,使用构造函数实例化a,并将A.prototype作用域给实例a

Var a = new A();

A.call(a, _args);//_args.id
=1;

  1. 执行内存中构造函数A.prototype.constructor前,构造参数对象arguments对象

arguments = A.prototype.slice.call(_args);;//传入参数

arguments.callee ==
this;//参数对象调用者为当前函数体

备注:arguments.length表示实际传参数,arguments.callee.length表示期望传参数

  1. 执行内存中构造函数A.prototype.constructor时,根据参数赋值,继承原型链中的属性方法。

a.id = arguments[1];//值为1

a.name = arguments[2];//值为undefined

a.constructor = A.prototype.constructor
= A(){…};//继承

  1. 返回值

return a;

Ways


新建对象方法


描述


备注


使用JS内存中内置对象的构造方法


var str = new
String(“str”);


只能实例化内置对象


使用JSON字面量


var o = {‘name’
:‘sapphire’};


方便快捷的方式


工厂模式


自定义函数中创建对象并返回


抽象方式


构造函数模式


function
Foo(_args){…};

var foo = new
Foo(_args);


常用方式

方法无法共享


原型模式


function
Foo(id){Foo.prototype.id = id};


切断已存在实例与原型对象关系

属性共享


组合模式


function
Foo(){…};

Foo.prototype = {fun
: function(){}};


构造函数模式构造属性

原型模式构造方法

6.    
RESULT – return

当构造函数无特殊声明return返回值时,返回实例化对象。

Chapter three . closure

函数闭包是一种技术,尤其被Lambdas语言广泛应用。Java中可以使用匿名函数的方式模拟闭包。

1.    
Introduce

闭包 = 闭包函数 + 一组自由变量与名称绑定存储区映射,实现函数外部访问函数内部变量的技术。

原理:如果一个函数包含内部函数,那么它们都可以看到其中声明的变量;这些变量被称为‘自由’变量。然而,这些变量可以被内部函数捕获,从高阶函数中return实现‘越狱’,以供以后使用。唯一需要注意的是,捕获函数必须在外部函数内定义。函数内没有任何局部声明之前(既不是被传入,也不是局部声明)使用的变量就是被捕获的变量。

备注:Javascript中20%以上的博客是关于闭包概念的,这里不再赘述。

弊端:应用时需分析函数变量,检查闭包是否会互相产生干扰,检查闭包的实例是否相同。

利端:闭包函数实例化时只执行一次,将不需要暴露在外层环境的变量封装在内部,减少了外部变量。

Chapter four . inherit

在ECMAScript中,只支持实现继承而不支持签名继承(接口继承)实现继承基本是通过原型链继承。


继承方式


示例


原型链继承


Sub.prototype = new
Super();


构造函数继承


function Sub(){
Super.call(this);}


组合继承


原型式继承


Object.create(prototype)

Chapter five . namespace

以上我们接触了全局变量和this的概念,前端JS开发中,不规范的命名规则会导致JS全局变量混乱甚至冲突。

下面这段代码示例规范变量命名空间

var
GLOBAL = {};

GLOBAL.namespace
= function(str){

  var arr = str.split(‘.‘);

  var start = 0;

  if(arr[0] == ‘GLOBAL‘){ start = 1; }

  for(var i = start; i < arr.length; i++){

    GLOBAL[arr[i]] = GLOBAL[arr[i]] || {};

    GLOBAL = o[arr[i]];

  }

};

假设a变量完成A功能中A1子功能。b变量完成A功能中A2子功能。c变量完成B功能。那么

GLOBAL.namespace(‘A.A1);
A.A1.a = …;

GLOBAL.namespace(‘A.A2);
A.A2.b = …;

GLOBAL.namespace(‘A.A1);
B.c = …;

同时,

尽量在匿名函数中声明变量而非全局环境中。

为代码添加更多注释。

Chapter six . reference

火狐开发者JS文档

https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript

IBM开发者社区

http://www.ibm.com/developerworks/cn/web/

有关ECMA-262个人站点

http://dmitrysoshnikov.com/

时间: 2024-11-08 19:05:57

JavaScript Oriented[探究面向对象的JavaScript高级语言特性]的相关文章

全面理解面向对象的JavaScript

转载:http://justcoding.iteye.com/blog/2019293 原文:http://www.ibm.com/developerworks/cn/web/1304_zengyz_jsoo/index.html?ca=drs-#major6 前言 当今 JavaScript 大行其道,各种应用对其依赖日深.web 程序员已逐渐习惯使用各种优秀的 JavaScript 框架快速开发 Web 应用,从而忽略了对原生 JavaScript 的学习和深入理解.所以,经常出现的情况是,

深入全面理解面向对象的 JavaScript

深入全面理解面向对象的 JavaScript (原著: 曾 滢, 软件工程师, IBM,2013 年 4 月 17 日) JavaScript 函数式脚本语言特性以及其看似随意的编写风格,导致长期以来人们对这一门语言的误解,即认为 JavaScript 不是一门面向对象的语言,或者只是部分具备一些面向对象的特征.本文将回归面向对象本意,从对语言感悟的角度阐述为什么 JavaScript 是一门彻底的面向对象的语言,以及如何正确地使用这一特性. 前言 当今 JavaScript 大行其道,各种应用

转载:全面理解面向对象的 JavaScript

来源:DeveloperWorks – 曾滢著 简介: JavaScript 函数式脚本语言特性以及其看似随意的编写风格,导致长期以来人们对这一门语言的误解,即认为 JavaScript 不是一门面向对象的语言,或者只是部分具备一些面向对象的特征.本文将回归面向对象本意,从对语言感悟的角度阐述为什么 JavaScript 是一门彻底的面向对象的语言,以及如何正确地使用这一特性. 前言 当今 JavaScript 大行其道,各种应用对其依赖日深.web 程序员已逐渐习惯使用各种优秀的 JavaSc

IT忍者神龟之理解回顾面向对象的 JavaScript

JavaScript 函数式脚本语言特性以及其看似随意的编写风格,导致长期以来人们对这一门语言的误解,即认为 JavaScript 不是一门面向对象的语言,或者只是部分具备一些面向对象的特征.本文将回归面向对象本意,从对语言感悟的角度阐述为什么 JavaScript 是一门彻底的面向对象的语言,以及如何正确地使用这一特性. 适合阅读人群 当今 JavaScript 大行其道,各种应用对其依赖日深.web 程序员已逐渐习惯使用各种优秀的 JavaScript 框架快速开发 Web 应用,从而忽略了

如何理解并学习javascript中的面向对象(OOP) [转]

如果你想让你的javascript代码变得更加优美,性能更加卓越.或者,你想像jQuery的作者一样,写出属于自己优秀的类库(哪怕是基于 jquery的插件).那么,你请务必要学习javascript面向对象,否则你无法更灵活的使用javascript这门语言. 什么事闭包?到底什么是原型?(知道闭包和原型的,就算得上是javascript的高手了.但真正能够理解,并且灵活运用的人并不多)到底该如何学习javascript中的面向对象呢?在javascript这么语言正如日中天,相信不少人正在为

前端开发:面向对象与javascript中的面向对象实现(一)

前端开发:面向对象与javascript中的面向对象实现(一) 前言: 人生在世,这找不到对象是万万不行的.咱们生活中,找不到对象要挨骂,代码里也一样.朋友问我说:“嘿,在干嘛呢......”,我:“找不到对象!”,他:“就你那样也能找得到对象?”.我一脸黑线...... 废话不多说,今天博主要跟大家聊的是<面向对象与javascript中的面向对象实现>”. 面向对象理解: 面向对象是一种对现实世界理解和抽象的方法,是一种先进的程序设计理念,是一种比较抽象的,多形态的设计模式.我们可以这么理

面向对象的Javascript(4):重载

在小项目中对于JavaScript使用,只要写几个function就行了.但在大型项目中,尤其是在开发追求 良好的用户体验的网站中,如SNS,就会 用到大量的JavaScrpt,有时JavaScript的工作量胜过了C#,这时写一堆function,就会显得很乱,杂乱无章,甚至会出现命名冲突,管理和维 护起来都很麻烦.对于这种情况我们就需要使用面向对象的思想来开发JavaScript.那我们就这样作罢: 在面向对象语言里重载是很重要的一个特性,而JavaScript这个自称面向对象的语言竟然没有

一个简单的、面向对象的javascript基础框架

如果以后公司再能让我独立做一套新的完整系统,那么我肯定会为这个系统再写一个前端框架,那么我到底该如何写这个框架呢? 在我以前的博客里我给大家展示了一个我自己写的框架,由于当时时间很紧张,做之前几乎没有完整的思考过我到底该如何去写这个框架,所以事后对于这个框架我有很多遗憾之处,当我重构过一次代码后我就没再做过任何重构操作的工作,因为我根本不想再去给它修修补补了,之所以有这个想法,就是我对我写的那个框架的基础架构不满意. 为什么不满意这个基础架构了?我们先来看看我当时封装框架的方式: (functi

javascript中的面向对象(object-oriented)编程

本文原发于我的个人博客,经多次修改放到csdn上,主要是做备份用,为了更好的阅读体验,请到我的个人博客上阅读. 最近工作一直在用nodejs做开发,有了nodejs,前端.后端.脚本全都可以用javascript搞定,很是方便.但是javascript的很多语法,比如对象,就和我们常用的面向对象的编程语言不同:看某个javascript开源项目,也经常会看到使用this关键字,而这个this关键字在javascript中因上下文不同而意义不同:还有让人奇怪的原型链.这些零零碎碎的东西加起来就很容