JavaScript语言学习以及部分ThreeJs分析



JavaScript语言特性

 

语法很多地方类似于C语言if,else,for,while等和c语言一致不涉及面向对象的部分还是和C语言有不少共同点的

 

 

优势:HTML标准的官方语言做前端开发的唯一选择后端开发的选择之一最基本的面向对象也是最彻底的面向对象。下面从几个小的方面展示一些javascript的特性。

 

特性1:所有事物都是对象字符串数值数组函数

 

让我们以一份简单json数据为例。

var person=

{

            firstname: "Bill",

            lastname: "Gates",

            id: 5566,

… //其他属性

            createPat: function () {

                this.pat = { name:"mimi", type: "cat", id: 1111 };

            }

…//其他方法

        };

//json数据格式

 

从不同的角度看待:

 

数据:这个person从数据的角度,可以认为是一份数据。保存了一个人的个人信息。可以用person["id"]访问数据的相关value。在调用person.createPat之前,person数据中并不保存pat即宠物的数据。调用person.createPat之后,可以用person["pat"]访问person的宠物数据(宠物数据也嵌套包含名字id等等)。从这个角度可以看出来json数据定义很灵活,支持的类型也非常多。

 

对象:person也就是一个人,它具有三个属性,firstnamelastnameid。可以用person.id访问对象属性。使用person.createPat以后,还可以给person增加一个pat的新属性。这是完全面向对象的。从这里可以看出,这一段数据可以被作为普通数据使用。也可以作为一个对象来管理。这就是比较灵活的地方。

 

基类对象以及基类方法:通过这个简单的person对象,可以继续构造它的子对象。如:

var a =Object.create(person);

a.area ="Asia";

var b =Object.create(person);

b.area ="Africa";

构建了一个a对象,地区在亚洲,和一个b对象地区在非洲。他们都继承了person的其余属性。只在地区这个属性上有所区别。可以被认为是两个不同子对象。

子对象a调用createPat,可以给子对象a添加pat属性。所以createPat可以看做不同子对象都可以调用的基类公共方法。

 

内部类:另外一种用法如下:

var cat1 = new person.createCat(); 这样的话,createPat不但能看做一个方法,还能看成一个内部类型。通过new关键字可以生成不同的createCat实例。而person就成了多个内部类的聚合,类似于一个命名空间。需要注意的是,这里的cat1person是一样的,都可以在键值对基础上不断扩展。Cat1也可以成为类似于person这样的内部类聚合体。这样可以不断嵌套,从而构建更加复杂的类型。

 

总结:上面的例子充分说明了为什么是简单彻底的面向对象。也说明了使用js语言的灵活性。使用js创建类,以及实现继承除了上面提到的,还有多种办法。就不列举了。

 

下面简单列举Three.js的面向对象方式:

varTHREE = { REVISION: '66' }; //类似于整个THREE的命名空间。 是多个内部类的聚合。

某一个功能模块类的实现:

THREE.CanvasRenderer= function ( parameters ) {  //相当于类定义

this.autoClear= true;          //类成员变量

this.setSize= function ( width, height, updateStyle ) {。。。}//类方法

 

}

 

//通过prototye Object.create来实现继承。

THREE.Geometry2.prototype= Object.create( THREE.BufferGeometry.prototype );

 

 

 

特性2:闭包

function closure(){                                //一个方法

var str = "I'm a part variable."; //方法里的局部变量。在方面外面无法访问

return function(){        //方法中的嵌套方法,根据局部变量作用域,这里可以访问str

alert(str);        //输出str的值

}

}

 

var fObj = closure();  //返回一个function

fObj();                                 //调用function可以获取str的值

 

来自 <http://baike.baidu.com/view/1518602.htm?fr=aladdin>

 

上面代码演示了闭包特性。

闭包有两个特性:

1  通过闭包能获取某个方法局部变量的值。如上面执行fObj可以输出closure局部变量str的值。

2 局部变量在闭包调用中不会被释放。而是继续保存。如str变量是局部变量,一般局部变量在方法执行完以后就可以释放了。但这里str因为在内部方法使用,而内部方法被fObj引用。所以fObj导致str不会在closure执行完以后就释放。

 

 

闭包用途:

 

1 方法局部变量只能通过闭包方法这一种途径访问,如closure方法中的局部变量str,只能通过closure返回的fObj来访问。利用这一点保护数据安全性。类似于私有变量。全局变量的缺点在于任何地方都能访问修改不安全,同时起名字容易和别人冲突。利用闭包构建的局部变量是没有这些问题的。

 

2 局部变量不会被释放。利用这个特点,把方法中的某个局部变量用来保存一些执行过程中的值。如某个局部变量count,利用闭包特性使其自加,由于count不会释放,每次count都加1,可以用来计数等等。而count是局部变量,不是全局变量,全局变量可能会在某个地方被人修改,闭包使用的局部变量根据闭包用途1,只存在一个调用路径,可以方便跟踪数据。

 

function closure(){

var count= 0;

return function(){

count++;

return count;

}

}

 

3 使用闭包特性构建面向对象框架。通过下面例子可以看出来。name是一个局部变量,但是由于被getName setName所引用,所以值可以保存。并且可以通过setget方法来改变。这样使用方式基本就和一个类一样。而且并没有使用new关键字。本质上是利用闭包 的特性把name保存到内存里。

 

function Person() {

            var name = "default";

 

            return {

                getName: function () {

                    return name;

                },

                setName: function (newName) {

                    name = newName;

                }

            }

        };

 var john = new Person();

john.setName("john");

 

var jack = Person();

jack.setName("jack");

 

4 其他使用方法还非常多。上面列举的常用的。

 

 

特点3:单线程架构,异步编程:setTimeout

javascript语言的执行环境是单线程。所以所有javascript语句都不能创建新线程。所有的代码都必须在一个线程里执行。所以对于耗时长的操作必须采用异步方案。

 

采用异步的几种方案:

1setTimeout

 

//此操作耗时 开机就执行会阻塞UI显示

functionabc()

{

   var a = 1;

};

 

//这个方法使用setTimeout来延时执行一个操作       

functiondelay(func) {

 

  setTimeout(function () {

 

      func();

 

    }, 1000);

 

  };

 

//abc执行延时操作

delay(abc);


 

特点:

1 同一时间内只有一段javascript代码被执行。其他代码会被加入到消息队列。

当前执行的代码如果耗时,就一定会阻塞其他代码执行。因为单线程没法被抢占。

 

2  setTimeout相当于在x秒钟以后把回调代码加入消息队列。abc这个方法仍然耗时,但是会在前面代码执行完毕以后,即x秒钟以后才会执行。把耗时的时间延后了,可以把时间先分给UI显示等重要操作。

 

3 由于不会抢占。所以setTimeout定时器到了的时候,如果有其他代码(鼠标键盘事件处理?画面刷新处理?动画处理?其它定时器回调?等等)还在执行,那么定时器绑定的回调函数就被加入队列中等待。也就是不管定时几秒,都没办法保证恰好在定时到达的时间执行。

 

3 setTimeout外还有一个类似函数setIntervel。机制是一样的。不过这个函数是每隔多少时间就执行一次。如果执行某次发现上次还没有执行就丢弃。当然,比如间隔一秒,也是无法精确保证的。比如第一次执行时候恰好有其他代码(如鼠标事件处理)拖延了半秒,就会导致半秒延迟执行。下一次触发的时候线程空闲,没有延迟。这样这两次操作间隔了半秒。而不是设定值1秒。

 

4 setTimeout的回调操作如果操作时间太长也会影响体验(单线程导致回调执行时,画控制UIjavascript无法执行)。如回调1秒钟才能执行完毕,那么这一秒钟之内点鼠标,操作键盘等需要UI刷新的javascript也没法执行。所以最好把setTimeout的回调分为多个耗时少的操作。

 

特点4:真正意义上的工作线程的实现。

 

1 GoogleGears:谷歌提供的一个浏览器插件工具。可以支持多线程。需要浏览器安装插件。所以不多介绍。

2 WebWorkerHTML5提供的javascript多线程解决方案。

可以使用worker类创建一个新的工作线程。

 

//worker.js

onmessage =function (evt){

var d = evt.data;//通过evt.data获得发送来的数据

postMessage( d );//将获取到的数据发送会主线程

}

 

//------------------------------------------------------------------------

 

var worker =new Worker("worker.js"); //创建一个Worker对象并向它传递将在新线程中执行的脚本的URL

worker.postMessage("helloworld");     //向worker发送数据

worker.onmessage =function(evt){     //接收worker传过来的数据函数

console.log(evt.data);              //输出worker发送来的数据

}

来自 <http://www.cnblogs.com/feng_013/archive/2011/09/20/2175007.html>

 

用途:通过创建工作线程。可以把一些耗时的操作放到线程中执行。

执行完毕后,可以通过postMessage把结果传递过来。主线程的onmessage方法里可以接收结果并处理。

 

共享工作线程:可以让多个页面共享的处理。不使用onmessage。使用onconnect来定义接收时的处理。

 

总结

webworker看起来很美好,但处处是魔鬼。

我们可以做什么:

1.可以加载一个JS进行大量的复杂计算而不挂起主进程,并通过postMessage,onmessage进行通信

2.可以在worker中通过importScripts(url)加载另外的脚本文件

3.可以使用 setTimeout(),clearTimeout(), setInterval(), and clearInterval()

4.可以使用XMLHttpRequest来发送请求

5.可以访问navigator的部分属性

有那些局限性:

1.不能跨域加载JS

2.worker内代码不能访问DOM

3.各个浏览器对Worker的实现不大一致,例如FF里允许worker中创建新的worker,而Chrome中就不行

4.不是每个浏览器都支持这个新特性

来自 <http://www.cnblogs.com/feng_013/archive/2011/09/20/2175007.html>

 

特点5:资源加载。

 

1.threejs中使用了XMLHttpRequest进行json资源加载。(数据、模型等都可以用json表示)例如加载js模型文件。

 

varloader = new THREE.JSONLoader();

            var callbackMale = function(geometry, materials) {

                。。。

            };

           loader.load("models/xxx.js",callbackMale);

 

 

可以看到,loader调用加载后传入一个回调函数。该回调函数会在加载完毕以后被回调。load方法内部是采用XMLHttpRequest实现加载的。所以是真正的多线程加载。加载完毕后会把结果放到单线程消息队列。常用的模型如objply等都是用这种办法。

 

2 纹理异步加载

 loader.load('textures/xxx.jpg', function (texture) {

 

                uniformsTerrain.tDiffuse.value= texture;

            });

 

 

纹理图片的加载也是类似的。如上面接口当加载完毕后会调用回调函数。纹理的onload实现是靠img标签来实现的。不知道是否是多线程加载。应该也是。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值