1、语言类型:
OC:和其他强类型语言一样,会在执行前对所有代码进行编译。(compileTime + runTime)
JS 是脚本语言。浏览器会在读取代码时,逐行地执行脚本代码。(runTime)
2、数据类型:
OC:基本数据类型声明方式更细(stack)+引用数据类型(heap)
JS:基本数据类型(stack):Undefined、Null、Boolean、Number 和 String。
引用数据类型(heap)
注意点:

和OC类语言不同的是,string在ES中实现成了原始类型(primitive type)-typeof null会返回 “Object”。这是 JavaScript最初实现中的一个错误,然后被 ECMAScript沿用了,解读成对象占位符。number类型(存储的时候总是64位的float)既可以表示 32 位的整数,还可以表示 64 位的浮点数。对于浮点字面量的有趣之处在于,用它进行计算前,真正存储的是字符串。String 类型的独特之处在于,它是唯一没有固定大小的原始类型。同时,每个基本数据类型都对应一个引用类型,实际上在声明的时候是调用了对应的构造函数。例如:1.toFixed(2)是会报错的。而new Number(1).toFixed(2)是完全正确的
3、数据类型声明方式:
OC:按照类型声明,并分配存储空间;
JS:var声明所有类型(同一个 var 语句定义的变量不必具有相同的类型)
还有个有趣的点,就是JS中的变量声明不是必须的。解释程序会查找变量是否声明,如果没有声明,就在全局作用域下声明变量。这个仅仅可以发生在预执行的阶段,在runtime如果这么做,会抛出异常的。
4、关键字:
OC会涉及到内存管理和多线程的一些关键字
JS中的关键词列举如下:(保留字就不列出了)
break case catch continue default delete do else finally for function if
in instanceof new return switch this throw try typeof var void while with。

前端工程师嘛,还是不能只关注HTML,CSS和JS。由于公司现在把web前端组要和native合并,同时市面上确实native这块也比较火热。在这个契机下,准备开个学习目录,记录下自己的学习心得。

cocoa框架NS*之类的语法特征:

  1. 前缀NS一方面避免和C语言变量申明冲突,同时也扩展了COCOA框架的很多函数。
  2. OC的代码编译器兼容C,OC。在特定的情况下还可以兼容C++代码。
  3. OC语言设计的初衷有几点

    1. 代码精简,函数调用用[]来显示
    2. 变量类型突出,函数调用时候都会标示变量的类型。
    3. OOP面向对象,interface接口和implement都会放在不同的文件里面
    4. 语法兼具前端画界面和后端的数据逻辑内存管理。(这个方面比JS要考虑的东西更多一点)

上一篇我们大概分析了react的虚拟dom和render及createElement该做的事情。现在把格局放大一点,考虑到之后数据模型修改,页面必须能够动态渲染,我们建立路标系统data-reactid与Dom进行mapping, 同时我们对react每个元素的props.children增加自定义key的权限。

上述做法的好处有以下几点:

  1. 更新DOM节点: 在选择父元素等的时候直接拿data-reactid进行标示查找
  2. 更新Dom的children元素:利用key可以保存相关dom节点的信息,避免在更新操作时,丢失原有数据。
    React的view层面大概讲解到这边,具体的实现细节在上一篇文章中:虚拟DOM>真实DOM信息这一点已经体现出来了。React真正的难点是它的DOM diff算法,之后我会针对dom diff进行更新

因为在项目中用React用的比较多,准备开个专栏来研究react的设计结构及源码。

我们从下面这个简单的例子入手来看虚拟DOM和react的构造机制。

React.render(React.createElement('div', {name: "John"}), document.getElementById("container"));
由此我们可以开始定义及猜测React的基本结构
React{
   render:function(todoElement,targetNode){},
   createElement:function(type,config,children){}
};
  • render方法是将第一个参数todoElement改造成html,放入第二个对应的容器中。
  • createElement将参数改造成虚拟dom,供render函数调用。为保证信息的完整性,可以推知虚拟Dom的创建必须满足如下要求:

    虚拟dom包含信息>=真实DOM包含信息

    初步定义虚拟dom结构:
    {
    type:type,//可以是html标签如’div’或者是’function’构造函数形式
    props:props,//包含html的所有attribute和子元素children
    key:key//html的映射键值
    };

    这时候,在render函数体内,接收到的参数就是虚拟dom和目标容器。

离春节的日子越来越近,还有10天就可以回家了。今天没有做什么业务上的事情,自己温习了下JavaScript的一些高级教程。

  1. 内存管理

    1. 堆: 存储对象,更确切的说是数据大小可变的数据类型,它们的值存储的是指向内存中对象地址。属于二级缓存区域(由垃圾回收算法回收内存)
    2. 栈: 动态内存区域,存储基本数据类型。JS不像C类语言,它对字符串做了处理,并将其归入基本数据类型。它们的值直接存储在变量的访问位置。属于一级缓存区域
    3. 消息队列:负责JS主线程与其他进程(主要是各种I/O操作)的通信的线程是消息线程,这意味着在I/O操作中,谁先有结果返回,可以在JS函数调用栈为空时,优先得到JS调用栈的处理。队列这种结构就是先进先出的典型。当栈再次为空的时候,就意味着消息队列的结束。
    4. 添加消息: 常用的setTimeout(fn,0)在消息队列的尾部添加事件回调函数
  2. 看了下reactJS虚拟Dom的部分源码。

    1. 不得不说自己真还没有这个水平完全写一个类似React的MVVM框架出来,还有很长的路要走哩。主要的技术难点分析下来,在于这几点

      1.  Model + view:建立合适的数据模型描述Dom结构。这一点reactJS的主要做法就是添加路标系统---data-reactid,通过使用reactid标示每一个dom节点,可以让View和Model建立很好地映射关系。
      
      1. VM + 处理事件:在前端的世界里,几乎天天离不开处理各种事件。在view层产生各种事件,如click等的时候,我们如何检测事件发生的dom节点。比较常规的做法是,将所有的事件都挂载在document上,通过冒泡的形式,获取e.target.getAttribute(‘data-reactid’)来遍历Model寻找需要更改的数据范围。这种常规的思想缺点在于,遍历是个比较费性能的事,而且处理回调函数需要考虑到各种情况,对Model设计是个大考验。而React的思路比较好,它把所有的data-reactid和Model综合起来,构建了和DOM 完全映射的VM (virtual dom),在处理事情的时候也采用事件代理+hash表的形式。这个我只是大概有个思路,具体实现,还不是特别清楚,需要继续研习。
      2. DOM diff算法:这个是个大头,也是React的核心所在,这个算法需要考虑的几个大头问题是:

        1.  映射关系以data-reactid为准的情况下,以什么样的尺度比较两次Model的不同,是浅对比还是深对比。
        
        1. 选定比对尺度后,对页面的真实DOM是reorder,reorganize 还是destroy,create等等
        2. 对于用户没有通过react进行的操作,如何在Model更新的时候依旧保留
          夜深了,发现写个日记确实能够帮助巩固很多知识呢! anyway,night

 

前端工程师在写页面JS的时候很少会关注到编译的情况,更多的是看执行的结果,然后根据相应的报错信息修正代码。在javascript的世界里,scope的作用域概念存在于函数中,当函数运行到某行代码需要查找某个变量时,编译器会在当前函数作用域下查找该变量,如果没有找到则继续往上一层函数作用域查找,这个过程会一直持续到全局作用域,如果没有找到相应变量,则抛出报错信息。

在JS中存在这样的代码,

console.log(e());//打印e
function e(){
console.log(‘e’)
}

这个是很令人费解的,在执行第一行代码的时候,编译解析器并没有执行到funtion哪一行,为何还是能打印出字符呢? 这个问题的答案在于,JS执行每个函数作用域时,会把所有的变量按照local,global,closure分类声明,同时将以var声明的变量赋值undefined,将所有以funtion func(){}形式定义的函数放在FUNCTIONS里面,function在JS中是一级对象,它们可以拥有属性和方法,无论何时都会返回值,当用new形式加载function时,返回this值,除了显式定义return,其它的情况都是返回undefined。

回到正题,当JS在碰到每个函数作用域时,会先声明完函数作用域的本地变量同时对所有在函数体内引用到的外界变量创建closure。在closure里面存储的变量有个神奇的地方,它会对它以内所有代码检查一遍是否存在引用上下文变量的情况,如果存在则将变量添加进clousure,由此也可以窥见为何递归在JS中容易出现栈溢出的情况。具体的测试,见下方代码

var ddd=’ddd’;// t的上下文变量
function e(){//t的上下文变量
console.log(‘e’)
}
var t= (function foo() {
debugger//查看执行时候,变量存储形式
var x = 1;
var test=’test’;
return function () {
return function(){
console.log(e)
console.log(ddd)}
};
}());

在debugger区域你可以看到,debugger区域里面的closure已经存储了e和ddd变量(图片支持的不是很好,不贴了,直接把数据结构给出)。

  • local:this
  • closure:ddd=’ddd’
    Functions:e(){}
  • global
    好了,做到这一步,基本可以看清楚javascript函数作用域的一些scope变量存储及作用域提升的细节:闭包就是一个函数创建时候的上下文(context)绑定,而变量提升则是JS在执行前做的一些分类变量类型(global,closure,local,Functions)的声明工作,其实也是比较能够理解和简单的。

在我看来,对于前端工程师来说,充分利用JS函数作用域的特性,采用闭包缓存全局变量加快代码执行速度,利用JS语法的灵活性来更好的规划代码,这是比较好的。

用webpack打包react,涉及到原型链的时候,需要注意的几个问题。webpack执行顺序是先声明每个原型挂载在prototype上的方法。

var Test2 = (function (_Test1) { _inherits(Test2, _Test1);//匿名函数立即执行,挂载所有的prototype方法 function Test2(props, context) {//构造函数方法,在实例化的时候执行 _classCallCheck(this, _Test2); **__Test1.call(this, props, context);_**//不断挂载在this对象上,继承 this.renderDisplay = this.renderDisplay.bind(this); this.state = { thumbNailIndex: 0 };} var _Test2 = Test2; Test2 = _utilsClassNameMixin2['default'](Test2) || Test2; return Test2;})(_test1Js2['default']); }
针对_classCallCheck进行说明,这是ES6语法的检测,保证super函数调用在this之前,不对原型做任何操作! "function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }"
下面引一段react关于生成实例的源码 备注:这里只是引部分代码,inst为经历了各种继承关系(call)最后生成的this值. // These should be set up in the constructor, but as a convenience for // simpler class abstractions, we set them up after the fact. inst.props = publicProps; inst.context = publicContext; inst.refs = emptyObject; inst.updater = ReactUpdateQueue; 可以看到react在最后处理阶段,无论你在继承关系中做了什么,还是会把props,refs,context修正回来。至于其他的例如state等属性,则没有做最后修改,所以在extends的关系中,可以做的事情是state而不是props

  • 重要的原型!!
  • 在实例化构造函数的时候,所有的继承关系是通过apply,call的形式传递this值的,而不是通过new function的形式。
  • 整个过程分为3步骤:

    • 生成所有的prototype构造函数
    • 生成所有的实例(this)继承关系
    • 由react接手最后的this,修改props,updater等保护属性,返回页面应用实例