baobaobao


  • 首页

  • 关于他

  • 博客分类

  • 博客归档

第八章笔记

发表于 2018-06-17 | 分类于 JavaScript高级程序设计读书笔记 |

(1) window对象以及窗口框架

由于 window 对象同时扮演着 ECMAScript 中 Global 对象的角色,因此所有在全局作用域中声明
的变量、函数都会变成 window 对象的属性和方法。

(2) 窗口位置相对于top的位置

var leftPos=(typeof window.screenLeft=='number')?
     window.screenLeft:window.screenX;
     alert(leftPos);

(3)检查弹出窗口是否被屏蔽了

如果浏览器扩展或者其他程序阻止弹出窗口的话。我们用try catch来判断

var blocked = false;
try {
    var wrpxWin = window.open("http://www.wrox.com", "_blank"); if (wrpxWin == null) {
        blocked = true;//窗口被屏蔽了
    }
} catch (ex) {
    blocked = true;
}

if (blocked) {
    alert("the popupp was bolcked!");
}

(4) 对话框

  • alert
  • confirm
  • prompt

重点是第三种,让你输入一个对话框,并要求你输入数据。

 var result = prompt("what is you name?", "");
 if (result != null) {
    alert("Welcome," + result);
}

(5) location对象

location 是最有用的 BOM 对象之一,它提供了与当前窗口中加载的文档有关的信息,还提供了一
些导航功能。事实上,location 对象是很特别的一个对象,因为它既是 window 对象的属性,也是
document 对象的属性;换句话说,window.location 和 document.location 引用的是同一个对象。
location 对象的用处不只表现在它保存着当前文档的信息,还表现在它将 URL 解析为独立的片段,让
开发人员可以通过不同的属性访问这些片段。

(6) navigator对象 检测插件

function hasPlugin(name) {
    name = name.toLowerCase();
    for (var i = 0; i < navigator.plugins.length; i++) {
        if (navigator.plugins[i].name.toLowerCase().indexOf(name) > -1) {
            return true;
        }
        return false;
    }
}
alert(hasPlugin("Flash"));//检查是否有Flash插件

(6) history对象

浏览器内置对象,可以用它模仿前一个界面,后一个界面操作。

(7) 小结

   浏览器对象模型(BOM)以 window 对象为依托,表示浏览器窗口以及页面可见区域。同时,window
对象还是 ECMAScript 中的 Global 对象,因而所有全局变量和函数都是它的属性,且所有原生的构造
函数及其他函数也都存在于它的命名空间下。本章讨论了下列 BOM 的组成部分。
1 在使用框架时,每个框架都有自己的 window 对象以及所有原生构造函数及其他函数的副本。
每个框架都保存在 frames 集合中,可以通过位置或通过名称来访问。
2 有一些窗口指针,可以用来引用其他框架,包括父框架。
3 top 对象始终指向最外围的框架,也就是整个浏览器窗口。
4 parent 对象表示包含当前框架的框架,而 self 对象则回指 window。
5 使用 location 对象可以通过编程方式来访问浏览器的导航系统。设置相应的属性,可以逐段
或整体性地修改浏览器的 URL。
6 调用 replace()方法可以导航到一个新 URL,同时该 URL 会替换浏览器历史记录中当前显示
的页面。
7 *navigator 对象提供了与浏览器有关的信息。到底提供哪些信息,很大程度上取决于用户的浏
览器;不过,也有一些公共的属性(如 userAgent)存在于所有浏览器中。
BOM 中还有两个对象:screen 和 history,但它们的功能有限。screen 对象中保存着与客户端
显示器有关的信息,这些信息一般只用于站点分析。history 对象为访问浏览器的历史记录开了一个
小缝隙,开发人员可以据此判断历史记录的数量,也可以在历史记录中向后或向前导航到任意页面。*

第七章笔记

发表于 2018-06-17 | 分类于 JavaScript高级程序设计读书笔记 |

(1) 访问器属性

    var book={};
Object.defineProperties(book,{
   _year:{
       writable:true,
       value:2014
   }
})

/*以上的Object.defineProperties可以给book对象的加属性以及以及对属性的操作等*/
//当然,也可以读取属性的特性。
var descriptor=Object.getOwnPropertyDescriptor(book,"_year");
alert(descriptor.value);  //2014
alert(descriptor.configurable);  //false

(2) 在对象和原型中查找属性或者方法的顺序。

如果按照字面意思来理解,那
么 prototype 就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象的好处是可以
让所有对象实例共享它所包含的属性和方法。

.hasOwnProperty方法可以用来检查某个属性在实例中还是原型中。

同时使用 hasOwnProperty()方法和 in 操作符,就可以确定该属性到底是存在于对象中,还是存在于
原型中,如下所示。

 //这个函数实现认识某个属性在不在原型中,在的话,返回ture,否则返回false;
function hasPrototypeProperty(object, name) {
    return !object.hasOwnProperty(name) && (name in object);
}
function Person() {
}
Person.prototype.name = "nihao";
var person = new Person();
alert(hasPrototypeProperty(person, "name"));  //ture,表明name在原型中。
person.name = "goobye";
alert(hasPrototypeProperty(person, "name"));  //false,不在原型中

(3)组合使用构造函数和原型模式

创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实
例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,
但同时又共享着对方法的引用,最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参
数;可谓是集两种模式之长。下面的代码重写了前面的例子。

/*构造函数用于实例化属性*/
    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.friends = ['nihao', "goobye"];
    }


    /*原型模式用于定义方法和共享的属性*/
    Person.prototype = {
        constructor: Person,
        sayName: function () {

            alert(this.name);
        }
    }

    var person1 = new Person("nihao", 29, "software Engineer")

    alert(person1.name);//nihao

(4) 原型链

  • 子类型有时候需要重写超类型中的某个方法,或者需要添加超类型中不存在的某个方法。但不管怎
    样,给原型添加方法的代码一定要放在替换原型的语句之后。
function SuperType() {

      this.property = true;
  }
  SuperType.prototype.getSuperValue = function () {
      return this.property;
  }

  function SubType() {

      this.subproperty = false;
  }


  //继承实现
  SubType.prototype = new SuperType();
  //添加新方法
  SubType.prototype.getSubValue = function () {
      return his.subproperty;
  }
  //重写超类型方法
  SubType.prototype.getSuperValue = function () {

      return false;
  }
  var instanc = new SubType();
  alert(instanc.getSuperValue());  //false

(5) 原型继承的问题以及解决

它的问题就是当一个子类继承父类的时候,当定义子类对象时。子类某一个对象对父类中属性或者方法的改动都会反映到子类的其他对象中,
因为父类成了子类定义对象的原型。其他对象使用后也会有相应改变。那么可以使用借用构造函数来解决。

借用构造函数

function SuperType() {
     this.colors = ["red", "blue", "green"];
 }
 function SubType() {
     //继承了Suptype
     SuperType.call(this);
 }

 var instance1 = new SubType();
 instance1.colors.push("black");//"red,blue,green,black" 
 alert(instance1.colors);
 var instance2 = new SubType();
 alert(instance2.colors);  //"red,blue,green" ,现在每个子类对象就保持了自己对父类的最初属性了。

(6) 小结

 ECMAScript 支持面向对象(OO)编程,但不使用类或者接口。对象可以在代码执行过程中创建和
 增强,因此具有动态性而非严格定义的实体。在没有类的情况下,可以采用下列模式创建对象。
 1   工厂模式,使用简单的函数创建对象,为对象添加属性和方法,然后返回对象。这个模式后来
 被构造函数模式所取代。
 2   构造函数模式,可以创建自定义引用类型,可以像创建内置对象实例一样使用 new 操作符。不
 过,构造函数模式也有缺点,即它的每个成员都无法得到复用,包括函数。由于函数可以不局
限于任何对象(即与对象具有松散耦合的特点),因此没有理由不在多个对象间共享函数。
 3   原型模式,使用构造函数的 prototype 属性来指定那些应该共享的属性和方法。组合使用构造
 函数模式和原型模式时,使用构造函数定义实例属性,而使用原型定义共享的属性和方法。
  JavaScript 主要通过原型链实现继承。原型链的构建是通过将一个类型的实例赋值给另一个构造函
 数的原型实现的。这样,子类型就能够访问超类型的所有属性和方法,这一点与基于类的继承很相似。
 原型链的问题是对象实例共享所有继承的属性和方法,因此不适宜单独使用。解决这个问题的技术是借
 用构造函数,即在子类型构造函数的内部调用超类型构造函数。这样就可以做到每个实例都具有自己的
 属性,同时还能保证只使用构造函数模式来定义类型。使用最多的继承模式是组合继承,这种模式使用
 原型链继承共享的属性和方法,而通过借用构造函数继承实例属性。
 此外,还存在下列可供选择的继承模式。
 4   原型式继承,可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅
 复制。而复制得到的副本还可以得到进一步改造。
 5 寄生式继承,与原型式继承非常相似,也是基于某个对象或某些信息创建一个对象,然后增强
 对象,最后返回对象。为了解决组合继承模式由于多次调用超类型构造函数而导致的低效率问
 题,可以将这个模式与组合继承一起使用。
 6  寄生组合式继承,集寄生式继承和组合继承的优点与一身,是实现基于类型继承的最有效方式。

第六章笔记

发表于 2018-06-17 | 分类于 JavaScript高级程序设计读书笔记 |

(1) 访问器属性

    var book={};
Object.defineProperties(book,{
   _year:{
       writable:true,
       value:2014
   }
})

/*以上的Object.defineProperties可以给book对象的加属性以及以及对属性的操作等*/
//当然,也可以读取属性的特性。
var descriptor=Object.getOwnPropertyDescriptor(book,"_year");
alert(descriptor.value);  //2014
alert(descriptor.configurable);  //false

(2) 在对象和原型中查找属性或者方法的顺序。

如果按照字面意思来理解,那
么 prototype 就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象的好处是可以
让所有对象实例共享它所包含的属性和方法。

.hasOwnProperty方法可以用来检查某个属性在实例中还是原型中。

同时使用 hasOwnProperty()方法和 in 操作符,就可以确定该属性到底是存在于对象中,还是存在于
原型中,如下所示。

 //这个函数实现认识某个属性在不在原型中,在的话,返回ture,否则返回false;
function hasPrototypeProperty(object, name) {
    return !object.hasOwnProperty(name) && (name in object);
}
function Person() {
}
Person.prototype.name = "nihao";
var person = new Person();
alert(hasPrototypeProperty(person, "name"));  //ture,表明name在原型中。
person.name = "goobye";
alert(hasPrototypeProperty(person, "name"));  //false,不在原型中

(3)组合使用构造函数和原型模式

创建自定义类型的最常见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实
例属性,而原型模式用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,
但同时又共享着对方法的引用,最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参
数;可谓是集两种模式之长。下面的代码重写了前面的例子。

/*构造函数用于实例化属性*/
    function Person(name, age, job) {
        this.name = name;
        this.age = age;
        this.job = job;
        this.friends = ['nihao', "goobye"];
    }


    /*原型模式用于定义方法和共享的属性*/
    Person.prototype = {
        constructor: Person,
        sayName: function () {

            alert(this.name);
        }
    }

    var person1 = new Person("nihao", 29, "software Engineer")

    alert(person1.name);//nihao

(4) 原型链

  • 子类型有时候需要重写超类型中的某个方法,或者需要添加超类型中不存在的某个方法。但不管怎
    样,给原型添加方法的代码一定要放在替换原型的语句之后。
function SuperType() {

      this.property = true;
  }
  SuperType.prototype.getSuperValue = function () {
      return this.property;
  }

  function SubType() {

      this.subproperty = false;
  }


  //继承实现
  SubType.prototype = new SuperType();
  //添加新方法
  SubType.prototype.getSubValue = function () {
      return his.subproperty;
  }
  //重写超类型方法
  SubType.prototype.getSuperValue = function () {

      return false;
  }
  var instanc = new SubType();
  alert(instanc.getSuperValue());  //false

(5) 原型继承的问题以及解决

它的问题就是当一个子类继承父类的时候,当定义子类对象时。子类某一个对象对父类中属性或者方法的改动都会反映到子类的其他对象中,
因为父类成了子类定义对象的原型。其他对象使用后也会有相应改变。那么可以使用借用构造函数来解决。

借用构造函数

function SuperType() {
     this.colors = ["red", "blue", "green"];
 }
 function SubType() {
     //继承了Suptype
     SuperType.call(this);
 }

 var instance1 = new SubType();
 instance1.colors.push("black");//"red,blue,green,black" 
 alert(instance1.colors);
 var instance2 = new SubType();
 alert(instance2.colors);  //"red,blue,green" ,现在每个子类对象就保持了自己对父类的最初属性了。

(6) 小结

 ECMAScript 支持面向对象(OO)编程,但不使用类或者接口。对象可以在代码执行过程中创建和
 增强,因此具有动态性而非严格定义的实体。在没有类的情况下,可以采用下列模式创建对象。
 1   工厂模式,使用简单的函数创建对象,为对象添加属性和方法,然后返回对象。这个模式后来
 被构造函数模式所取代。
 2   构造函数模式,可以创建自定义引用类型,可以像创建内置对象实例一样使用 new 操作符。不
 过,构造函数模式也有缺点,即它的每个成员都无法得到复用,包括函数。由于函数可以不局
限于任何对象(即与对象具有松散耦合的特点),因此没有理由不在多个对象间共享函数。
 3   原型模式,使用构造函数的 prototype 属性来指定那些应该共享的属性和方法。组合使用构造
 函数模式和原型模式时,使用构造函数定义实例属性,而使用原型定义共享的属性和方法。
  JavaScript 主要通过原型链实现继承。原型链的构建是通过将一个类型的实例赋值给另一个构造函
 数的原型实现的。这样,子类型就能够访问超类型的所有属性和方法,这一点与基于类的继承很相似。
 原型链的问题是对象实例共享所有继承的属性和方法,因此不适宜单独使用。解决这个问题的技术是借
 用构造函数,即在子类型构造函数的内部调用超类型构造函数。这样就可以做到每个实例都具有自己的
 属性,同时还能保证只使用构造函数模式来定义类型。使用最多的继承模式是组合继承,这种模式使用
 原型链继承共享的属性和方法,而通过借用构造函数继承实例属性。
 此外,还存在下列可供选择的继承模式。
 4   原型式继承,可以在不必预先定义构造函数的情况下实现继承,其本质是执行对给定对象的浅
 复制。而复制得到的副本还可以得到进一步改造。
 5 寄生式继承,与原型式继承非常相似,也是基于某个对象或某些信息创建一个对象,然后增强
 对象,最后返回对象。为了解决组合继承模式由于多次调用超类型构造函数而导致的低效率问
 题,可以将这个模式与组合继承一起使用。
 6  寄生组合式继承,集寄生式继承和组合继承的优点与一身,是实现基于类型继承的最有效方式。

第五章笔记

发表于 2018-06-16 | 分类于 JavaScript高级程序设计读书笔记 |

(1) 引用类型

在 ECMAScript 中,引用类型是一种数据结构。
用于将数据和功能组织在一起。它也常被称为类,但这种称呼并不妥当。尽管 ECMAScript
从技术上讲是一门面向对象的语言,但它不具备传统的面向对象语言所支持的类和接口等基
本结构。引用类型有时候也被称为对象定义,因为它们描述的是一类对象所具有的属性和方法。

(2) object定义

推荐定义object用字面量定义

var person = {    
 name : "Nicholas",  
 age : 29  
};   
var person = {}; //与 new Object()相同  
person.name = "Nicholas";  
person.age = 29;   

(3)array定义推荐

var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组  
var names = []; // 创建一个空数组 ,用它即可。 
var values = [1,2,]; // 不要这样!这样会创建一个包含 2 或 3 项的数组  
var options = [,,,,,]; // 不要这样!这样会创建一个包含 5 或 6 项的数组 

一些知识点

/*1 动态给数组加数据,类似于线性表了。*/
var colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组  
colors[colors.length] = "black"; //(在位置 3)添加一种颜色  
colors[colors.length] = "brown"; //(在位置 4)再添加一种颜色
/*2 数组的toLocaleString()方法,其实是调用每一项的toString方法,输出。*/    
/*数组的栈以及队列方法  
push,pop,shift    
其中push和shift结合可以实现队列方法。*/ 
 var colors=new Array();    
     var count=colors.push("red","green");  //这个函数调用会返回2,有意思  
       alert(count);  
       count=colors.push("black");  
       alert(count);  
       var item=colors.shift();  //取得第一项,厉害了  
       alert(item);

(4) 数组的迭代方法

  • every():对数组中的每一项运行给定函数,如果该函数对每一项都返回 true,则返回 true。
  • filter():对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组。
  • forEach():对数组中的每一项运行给定函数。这个方法没有返回值。
  • map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
  • some():对数组中的每一项运行给定函数,如果该函数对任一项返回 true,则返回 true。
    以上方法都不会修改数组中的包含的值。
    在这些方法中,最相似的是 every()和 some(),它们都用于查询数组中的项是否满足某个条件。
    对 every()来说,传入的函数必须对每一项都返回 true,这个方法才返回 true;否则,它就返回
    false。而 some()方法则是只要传入的函数对数组中的某一项返回 true,就会返回 true。请看以下
    例子。
var numbers = [1, 2, 4, 343, 43, 423, 4];    
       var everyResult = numbers.every(function (item, index, array) {  
        return (item>2)
       })
   alert(everyResult);  //false,他要求所有item都>2才可以。
   var evetyResultq=numbers.some(function(item,index,array){  
   return  (item>2)
   })
   alert(everyResult);//ture,他只要求其中有一个到几个>2即可。
var filteResult=numbers.filter(function(item,index,array){
       return (item>2);
   })
   alert(filteResult)  //返回这个数组所有大于2的数,并组成一个数组,这个牛逼了

(5) 作为值的函数

/*因为 ECMAScript 中的函数名本身就是变量,所以函数也可以作为值来使用。也就是说,不仅可以  
像传递参数一样把一个函数传递给另一个函数,而且可以将一个函数作为另一个函数的结果返回。来看  
一看下面的函数。*/
  function callSomeFunction(someFunction, someArgument) {  
        return someFunction(someArgument);  //函数返回一个值,这个值就是一个函数
    }
    function add10num(num) {
        return num + 10;
    }
    var result = callSomeFunction(add10num, 10);
    alert(result);//20

(6) 作为值的函数以及call

  function callSomeFunction(someFunction, someArgument) {
      return someFunction(someArgument);  //函数返回一个值,这个值就是一个函数
  }
  function add10num(num) {
      return num + 10;
  }
  var result = callSomeFunction(add10num, 10);
  alert(result);//20
window.color = "red";
  var o = { color: "blue" };
  function sayColor() {
      alert(this.color);
  }
  sayColor();
  sayColor.call(this);//red,这是全局变量使用
  sayColor.call(o);//blue,call可以帮我们指定this对象所指向的位置。完美

(7)基本包装类型的生存期以及后台解析成对象

var s1="some text";
var s2=s1.substring(2);
/*后台其实是执行了这样的一个过程

(1) 创建 String 类型的一个实例;
(2) 在实例上调用指定的方法;
(3) 销毁这个实例。
可以将以上三个步骤想象成是执行了下列 ECMAScript 代码。
var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;
经过此番处理,基本的字符串值就变得跟对象一样了。而且,上面这三个步骤也分别适用于 Boolean
和 Number 类型对应的布尔值和数字值。
引用类型与基本包装类型的主要区别就是对象的生存期。使用 new 操作符创建的引用类型的实例,
在执行流离开当前作用域之前都一直保存在内存中。而自动创建的基本包装类型的对象,则只存在于一
行代码的执行瞬间,然后立即被销毁。这意味着我们不能在运行时为基本类型值添加属性和方法。如下代码所示
 */

var s1 = "some text";
s1.color = "red";
alert(s1.color); //undefined

(8)单体内置对象Global对象

不属于任何其他对象的属性和方法,最终都是Global对象中的属性和方法。
winow对象,

ECMAScript 虽然没有指出如何直接访问 Global 对象,但 Web 浏览器都是将这个全局对象作为
window 对象的一部分加以实现的。因此,在全局作用域中声明的所有变量和函数,就都成为了 window
对象的属性。来看下面的例子。

var color = "red";
function sayColor(){
 alert(window.color);
}
window.sayColor(); //"red" 

(9)小结

对象在 JavaScript 中被称为引用类型的值,而且有一些内置的引用类型可以用来创建特定的对象,
现简要总结如下:
1 引用类型与传统面向对象程序设计中的类相似,但实现不同;
2 Object 是一个基础类型,其他所有类型都从 Object 继承了基本的行为;
3 Array 类型是一组值的有序列表,同时还提供了操作和转换这些值的功能;
4  Date 类型提供了有关日期和时间的信息,包括当前日期和时间以及相关的计算功能;
5 RegExp 类型是 ECMAScript 支持正则表达式的一个接口,提供了最基本的和一些高级的正则表
达式功能。
函数实际上是 Function 类型的实例,因此函数也是对象;而这一点正是 JavaScript 最有特色的地
方。由于函数是对象,所以函数也拥有方法,可以用来增强其行为。
因为有了基本包装类型,所以 JavaScript 中的基本类型值可以被当作对象来访问。三种基本包装类
型分别是:Boolean、Number 和 String。以下是它们共同的特征:
6 每个包装类型都映射到同名的基本类型;
7 在读取模式下访问基本类型值时,就会创建对应的基本包装类型的一个对象,从而方便了数据
操作;
8 操作基本类型值的语句一经执行完毕,就会立即销毁新创建的包装对象。
在所有代码执行之前,作用域中就已经存在两个内置对象:Global 和 Math。在大多数 ECMAScript
实现中都不能直接访问 Global 对象;不过,Web 浏览器实现了承担该角色的 window 对象。全局变
量和函数都是 Global 对象的属性。Math 对象提供了很多属性和方法,用于辅助完成复杂的数学计算
任务。

第四章笔记

发表于 2018-06-16 | 分类于 JavaScript高级程序设计读书笔记 |

(1) 访问变量有基本类型与引用类型

你不能给基本类型加属性和方法,但是引用类型可以。如果你给一个引用类型
加了属性和方法,另一个也会有,其实他们之间都是地址传递。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
在JavaScript中,参数都是按值传递的。但是,向函数传递基本类型的值时  
它会复制并传递。而传引用类型的参数,直接都是传送地址,会同时反映到该引用上。
/*基本类型传递*/
function addTe(num){
num+=10;
return num;
}
var numbe=10;
alert(addTe(numbe));//30
alert(numbe); //还是10

/*引用类型传递*/
function setName(boj){
obj.name="nihao";
}

var person=new Object();
setName(person);
alert(person.name); //“nihao”

(2) 检测类型

多用instanceof,但是他不能检测object
如果变量是给定引用类型(根据它的原型链来识别;第 6 章将介绍原型链的实例那么
instanceof 操作符就会返回 true。
请看下面的例子:
alert(person instanceof Object); // 变量 person 是 Object 吗?
alert(colors instanceof Array); // 变量 colors 是 Array 吗?
alert(pattern instanceof RegExp); // 变量 pattern 是 RegExp 吗?
根据规定,所有引用类型的值都是 Object 的实例。因此,在检测一个引用类型值和 Object 构造
函数时,instanceof 操作符始终会返回 true。当然如果使用 instanceof 操作符检测基本类型的
值,则该操作符始终会返回 false,因为基本类型不是对象。

(3) 垃圾收集机制

1 标记清楚收集方式,用一个标志位来标记变量何时“进环境”,何时“出环境”
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方
式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记
的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器
完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。
2 引用计数方式
3 管理内存,当不再使用一个变量时,请手动设置其为null

(4) 小结

JavaScript 变量可以用来保存两种类型的值:基本类型值和引用类型值。基本类型的值源自以下 5
种基本数据类型:Undefined、Null、Boolean、Number 和 String。基本类型值和引用类型值具
有以下特点:

  • 基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中;
  • 从一个变量向另一个变量复制基本类型的值,会创建这个值的一个副本;
  • 引用类型的值是对象,保存在堆内存中;
  • 包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针;
  • 从一个变量向另一个变量复制引用类型的值,复制的其实是指针,因此两个变量最终都指向同
    一个对象;
  • 确定一个值是哪种基本类型可以使用 typeof 操作符,而确定一个值是哪种引用类型可以使用
    instanceof 操作符。
    所有变量(包括基本类型和引用类型)都存在于一个执行环境(也称为作用域)当中,这个执
    行环境决定了变量的生命周期,以及哪一部分代码可以访问其中的变量。以下是关于执行环境的几
    点总结:
  • 执行环境有全局执行环境(也称为全局环境)和函数执行环境之分;
  • 每次进入一个新执行环境,都会创建一个用于搜索变量和函数的作用域链;
  • 函数的局部环境不仅有权访问函数作用域中的变量,而且有权访问其包含(父)环境,乃至全
    局环境;
  • 全局环境只能访问在全局环境中定义的变量和函数,而不能直接访问局部环境中的任何数据;
  • 变量的执行环境有助于确定应该何时释放内存。
    JavaScript 是一门具有自动垃圾收集机制的编程语言,开发人员不必关心内存分配和回收问题。可
    以对 JavaScript 的垃圾收集例程作如下总结。
  • 离开作用域的值将被自动标记为可以回收,因此将在垃圾收集期间被删除。
  • “标记清除”是目前主流的垃圾收集算法,这种算法的思想是给当前不使用的值加上标记,然
    后再回收其内存。
  • 另一种垃圾收集算法是“引用计数”,这种算法的思想是跟踪记录所有值被引用的次数。JavaScript
    引擎目前都不再使用这种算法;但在 IE 中访问非原生 JavaScript 对象(如 DOM 元素)时,这种
    算法仍然可能会导致问题。
  • 当代码中存在循环引用现象时,“引用计数”算法就会导致问题。
  • 解除变量的引用不仅有助于消除循环引用现象,而且对垃圾收集也有好处。为了确保有效地回
    收内存,应该及时解除不再使用的全局对象、全局对象属性以及循环引用变量的引用。

第三章笔记

发表于 2018-06-16 | 分类于 JavaScript高级程序设计读书笔记 |

(1) 未初始化值会被赋予“undefined”这个值。

即便未初始化的变量会自动被赋予 undefined 值,但显式地初始化
变量依然是明智的选择。如果能够做到这一点,那么当 typeof 操作符
返回”undefined”值时,我们就知道被检测的变量还没有被声明,而不是
尚未初始化。

(2) null和object是一样的,用typeof是辨认不出的。

(3) object类似于java中的终极对象object,

JavaScript中所有对象都是在object复制而来。而终极对象object拥有很多性质。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
仅仅创建 Object 的实例并没有什么用处,但关键是要理解一个重要的思想:即在  
ECMAScript 中,(就像 Java 中的 java.lang.Object 对象一样)Object
类型是所有它的实例的基础。换句话说,Object 类型所具有的任何属性和方法也
同样存在于更具体的对象中。Object 的每个实例都具有下列属性和方法。
1 constructor:保存着用于创建当前对象的函数。对于前面的例子而言,构造函数
(constructor)就是 Object()。
2 hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而
不是在实例
的原型中)是否存在。其中,作为参数的属性名(propertyName)必须以字符串形式指定(例
如:o.hasOwnProperty("name"))。
3 isPrototypeOf(object):用于检查传入的对象是否是传入对象的原型(第 5 章将讨论原
型)。
4 propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用 for-in 语句
(本章后面将会讨论)来枚举。与 hasOwnProperty()方法一样,作为参数的属性名必须以字符
串形式指定。
5 toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
6 toString():返回对象的字符串表示。
7 valueOf():返回对象的字符串、数值或布尔值表示。通常与 toString()方法的返回值
相同。

(4) 小结

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
也已经着手开始实现第 5 版了。以下简要总结了 ECMAScript 中基本的要素。  
1 ECMAScript 中的基本数据类型包括 Undefined、Null、Boolean、Number 和 String。
2 与其他语言不同,ECMScript 没有为整数和浮点数值分别定义不同的数据类型,Number 类型可
用于表示所有数值。
3 ECMAScript 中也有一种复杂的数据类型,即 Object 类型,该类型是这门语言中所有对象的基
础类型。
4 严格模式为这门语言中容易出错的地方施加了限制。
5 ECMAScript 提供了很多与 C 及其他类 C 语言中相同的基本操作符,包括算术操作符、布尔操作
符、关系操作符、相等操作符及赋值操作符等。
6 ECMAScript 从其他语言中借鉴了很多流控制语句,例如 if 语句、for 语句和 switch 语句等。
ECMAScript 中的函数与其他语言中的函数有诸多不同之处。
7 无须指定函数的返回值,因为任何 ECMAScript 函数都可以在任何时候返回任何值。
8 实际上,未指定返回值的函数返回的是一个特殊的 undefined 值。
9 ECMAScript 中也没有函数签名的概念,因为其函数参数是以一个包含零或多个值的数组的形式
传递的。
10 可以向 ECMAScript 函数传递任意数量的参数,并且可以通过 arguments 对象来访问这些参数。
11 由于不存在函数签名的特性,ECMAScript 函数不能重载

第二章笔记

发表于 2018-06-16 | 分类于 JavaScript高级程序设计读书笔记 |

1 重点介绍了script作为脚步的一些属性以及相关

(1) javascript居然是JavaScript语言和DOM以及BOM的结合体。

(2) 判断浏览器是否能够使用JavaScript语言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<html>

<body>




<noscript>
<p>本页面需要浏览器支持JavaScript</p>
</noscript>
<script type="text/javascript" defer="defer">
</script>


</body>

</html>

(3) 小结

JavaScript 插入到 HTML 页面中要使用

原生JavaScript实现订阅/发布模式

发表于 2018-06-03 |

###1 订阅/发布模式说明
什么是订阅/发布模式呢?
举个简单的例子。我们在开发网站常常有这样的一种情况。就是用户登录过的主界面和没登录过
的主界面显示是不一样的,而没有使用订阅/发布模式的话。我们很可能会写出下面的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//登录成功情况下
login.succ(function( data ){
header.setAvatar( data.avatar);
nav.setAvatar( data.avatar );
message.refresh();
cart.refresh();
address.refresh();
});

//登录失败情况下
login.fail(function( data ){
header.setAvatar( data.avatar);
nav.setAvatar( data.avatar );
message.refresh();
cart.refresh();
address.refresh();
});

/*这两种情况都有相应的处理逻辑,假如现在又出现了新的模块的话。我们又要在上述的两种情况下
加入逻辑代码,十分不利于维护。*/

###2 订阅/发布模式的实践
如果我们利用订阅/发布模式的话,整个流程就十分清晰了。
模式解释:发布—订阅模式又叫观察者模式,它定义对象间的一种一对多的依赖关系,当一个对象
的状态发生改变时,所有依赖于它的对象都将得到通知。在 JavaScript 开发中,我们一般用事件模
型来替代传统的发布—订阅模式。
流程如下:

  • 创建发布者对象,它具有订阅者的对象数组(我们网页中的各个模块)。以及相应的发布通知这些对象执行相应方法。
  • 创建订阅者。它具有接收到发布信息的执行方法(模块初始化方法)。
  • 发布者接收到通知(登录成功)。
  • 对所有订阅者对象数组进行通知。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//实践代码

//创建发布者对象,它具有订阅者的对象数组
//(我们网页中的各个模块)。以及相应的发布通知这些对象执行相应方法。
var login = {}; // 定义发布者。
login.modules = []; // 缓存列表,存放模块订阅者的回调函数
login.listen = function( fn ){ // 增加订阅者
this.clientList.push( fn ); // 订阅的消息添加进缓存列表
};
login.trigger = function(){ // 发布消息
for( var i = 0, fn; fn = this.modules[ i++ ]; ){
fn.apply( this, arguments ); // (2) // arguments 是发布消息时带上的参数
}
};



$.ajax( 'http:// xxx.com?login', function(data){ // 登录成功
login.trigger( 'loginSucc', data); // 发布登录成功的消息
});


各模块监听登录成功的消息:
var header = (function(){ // header 模块
login.listen( 'loginSucc', function( data){
header.setAvatar( data.avatar );
});
return {
setAvatar: function( data ){
console.log( '设置 header 模块的头像' );
}
}
})();
var nav = (function(){ // nav 模块
login.listen( 'loginSucc', function( data ){
nav.setAvatar( data.avatar );
});
return {
setAvatar: function( avatar ){
console.log( '设置 nav 模块的头像' );
}
}
})();

###2.1改进
以上就是一个简单的订阅/发布的实现。但上述代码还有问题,比如我们给每一个发布者都赋予了订阅者的参数列表是一种
资源浪费。我们的订阅者至少需要知道发布者的名字才能接受到信息。硬编码十分明显。接下来。我们可以使用一个全局的订阅、
发布对象,抽象出一个“中介者”的对象。他负责把订阅者以及发布者隔离开。
以一个售楼处以及客户的关系作为例子。同样在程序中,发布—订阅模式可以用一个全局的 Event 对象来实现,订阅者不需要
了解消息来自哪个发布者,发布者也不知道消息会推送给哪些订阅者,Event 作为一个类似“中介者”的角色,把订阅者和发布
者联系起来。
示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
var Event = (function () {
//创建订阅者对象数组
var clientList = {},
listen,
trigger,
remove;
//订阅者订阅实现
listen = function (key, fn) {
if (!clientList[key]) {
clientList[key] = [];
}
clientList[key].push(fn);
};
//发布者发布消息实现
trigger = function () {
var key = Array.prototype.shift.call(arguments),
fns = clientList[key];
if (!fns || fns.length === 0) {
return false;
}
for (var i = 0, fn; fn = fns[i++];) {
fn.apply(this, arguments);
}
};
//订阅者取消订阅
remove = function (key, fn) {
var fns = clientList[key];
if (!fns) {
return false;
}

if (!fn) {
fns && (fns.length = 0);
} else {
for (var l = fns.length - 1; l >= 0; l--) {
var _fn = fns[l];
if (_fn === fn) {
fns.splice(l, 1);
}
}
}
};
//暴露的公共接口
return {
listen: listen,
trigger: trigger,
remove: remove
}
})();
//小红订阅消息
Event.listen('squareMeter88', function (price) {
// 小红订阅消息,小红想要订阅88平方米的楼房价格。
//我们发现并不需要小红这个对象传入,只需要传入要监听的对象,以及回调函数即可
console.log('价格= ' + price); // 这里为小红接收到信息所做出的业务操作。输出:'价格=2000000'
});
//发布者发布消息
Event.trigger('squareMeter88', 2000000); // 售楼处发布88平方米的楼房价格消息。

到这里为止。一个比较完善的模式流程就差不多搞定了。

###2.2 界面实践
接下来我们用一个关于界面的示例来形象说明如何使用它。
需求:比如现在有两个模块,a 模块里面有一个按钮,每次点击按钮之后,b 模块里的 div 中会显示
按钮的总点击次数,我们用全局发布—订阅模式完成下面的代码,使得 a 模块和 b 模块可以在保
持封装性的前提下进行通信。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<html>

<body>
<!--a模块触发点击点击事件-->
<button id="count">点我</button>
<!--b模块,订阅点击事情,并作出反应-->
<div id="show"></div>
</body>
<script>

var Event = (function () {
//创建订阅者对象数组
var clientList = {},
listen,
trigger,
remove;
//订阅者订阅实现
listen = function (key, fn) {
if (!clientList[key]) {
clientList[key] = [];
}
clientList[key].push(fn);
};
//发布者发布消息实现
trigger = function () {
var key = Array.prototype.shift.call(arguments),
fns = clientList[key];
if (!fns || fns.length === 0) {
return false;
}
for (var i = 0, fn; fn = fns[i++];) {
fn.apply(this, arguments);
}
};
//订阅者取消订阅
remove = function (key, fn) {
var fns = clientList[key];
if (!fns) {
return false;
}

if (!fn) {
fns && (fns.length = 0);
} else {
for (var l = fns.length - 1; l >= 0; l--) {
var _fn = fns[l];
if (_fn === fn) {
fns.splice(l, 1);
}
}
}
};
//暴露的公共接口
return {
listen: listen,
trigger: trigger,
remove: remove
}
})();

var a = (function () {
var count = 0;
var button = document.getElementById("count");
button.onclick = function () {
console.log("发布点击add消息,并随需要传入参数");
Event.trigger("add", count++)
}
})();
var b = (function () {
var div = document.getElementById("show");
console.log("订阅点击add消息,并获得a模块的参数");
Event.listen("add", function (count) {
div.innerHTML = count;

})
})();


</script>

</html>

本文小结:
本章我们学习了发布—订阅模式,也就是常说的观察者模式。发布—订阅模式在实际开发中非
常有用。

  • 它的优点:一为时间上的解耦,二为对象之间的解耦。它的应用非常广泛,既可以用在异步编程
    中,也可以帮助我们完成更松耦合的代码编写。发布—订阅模式还可以用来帮助实现一些别的设计
    模式,比如中介者模式。从架构上来看,无论是 MVC 还是 MVVM,都少不了发布—订阅模式的参与
    ,而且 JavaScript 本身也是一门基于事件驱动的语言。
  • 它的缺点:创建订阅者本身要消耗一定的时间和内存,而且当你订阅一个消息后,也许此消息
    最后都未发生,但这个订阅者会始终存在于内存中。另外,发布—订阅模式虽然可以弱化对象之间的
    联系,但如果过度使用的话,对象和对象之间的必要联系也将被深埋在背后,会导致程序难以跟踪
    维护和理解。特别是有多个发布者和订阅者嵌套到一起的时候,要跟踪一个 bug 不是件轻松的事情。

#3 小发现
在编码的时候发现了原生JavaScript的onclick和click的区别,现在放入这里供大家参考
区别:

  • 原生javascript的click在w3c里边的阐述是DOM button对象,也是html DOM click() 方法,
    可模拟在按钮上的一次鼠标单击。button 对象代表 HTML 文档中的一个按钮。button元素没有默
    认的行为,但是必须有一个 onclick 事件句柄以便使用。
  • onclick是一个事件,Event对象 。支持该事件的 JavaScript 对象:button, document,
    checkbox, link, radio, reset, submitHTML DOM Event 对象,代表事件的状态,比如事
    件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。事件通常与函数结合使用,函数
    不会在事件发生前被执行!
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <html>
    <head>
    <script type="text/javascript">
    function clickButton()
    {
    document.getElementById('button1').click()
    }
    function alertMsg()
    {
    alert("Button 1 was clicked!")
    }
    </script>
    </head>
    <body onload="clickButton()">

    <form>
    <input type="button" id="button1" onclick="alertMsg()" value="Button 1" />
    </form>

    </body>
    </html>

原生JavaScript实现模板引擎

发表于 2018-06-03 |

本文实现来自《深入浅出node.js》第8章的模板小结
本文主要阐述如何利用模板引擎来实现对模板的解析。很多时候
我们常常能在jsp中看到这样的语法结构。

1
2
3
4
5
6
7
8
9
10
11
12
  'Hello <%=username%>.';
```
有经验的同学会想到一个问题。编译器是如何识别以及将username替换成我们
真实数据的?
下面将用JavaScript实现对它的解析。
###1 准备工作
实现原理:
> * 语法分解
> * 处理表达式(上述的<%=username%>)
> * 生成可执行的语句
> * 和真实数据一起执行。生成最终字符串(类似于Hello Jackson Tian. )
###2 代码实践

//模板语法代码。
//引擎拼接字符串的原理还是通过正则表达式进行匹配替换。以此我们可以想到
//几乎所有的模板都可以用这种方法编译使用。vue中的模板也是。
var render = function (str, data) {
//先把我们的定义标签<%=username%>换成obj.name来解析

    var tpl = str.replace(/<%=([ % \s\S]+?)%>/g, function (match, code) {
        return "' + obj." + code + "+ '";
    });
    console.log(tpl);  //hello ' + obj.username+ '.
    tpl = "var tpl = '" + tpl + "'\nreturn tpl;";  
    console.log(tpl); //var tpl='Hello ' + obj.username+ '.'     return tpl;
      //下面构造一个新的函数来实现解析obj中username 
    var complied = new Function('obj', tpl);
    return complied(data);
};
var tpl = 'Hello <%=username%>.';
//调用模板函数,这里的参数为模板对象,以及模板中对应的字符串解析策略。
//类似于策略模式中,给dom控件赋予相应的校验策略。
console.log(render(tpl, { username: 'Jackson Tian' }));

// => Hello Jackson Tian.

1
2
3
###3注意点  

这里的new Function()代表

/ newFunction 解析
1 var message = new Function(‘msg’,’alert(msg)’);
2 // 等价于:
3 function message(msg) {
4 alert(msg);
5 }
/
`

原生JavaScript实现模板引擎

发表于 2018-06-03 |

欢迎使用 Cmd Markdown 编辑阅读器


·
我们理解您需要更便捷更高效的工具记录思想,整理笔记、知识,并将其中承载的价值传播给他人,Cmd Markdown 是我们给出的答案 —— 我们为记录思想和分享知识提供更专业的工具。 您可以使用 Cmd Markdown:

  • 整理知识,学习笔记
  • 发布日记,杂文,所见所想
  • 撰写发布技术文稿(代码支持)
  • 撰写发布学术论文(LaTeX 公式支持)

cmd-markdown-logo

除了您现在看到的这个 Cmd Markdown 在线版本,您还可以前往以下网址下载:

Windows/Mac/Linux 全平台客户端

请保留此份 Cmd Markdown 的欢迎稿兼使用说明,如需撰写新稿件,点击顶部工具栏右侧的 新文稿 或者使用快捷键 Ctrl+Alt+N。


什么是 Markdown

Markdown 是一种方便记忆、书写的纯文本标记语言,用户可以使用这些标记符号以最小的输入代价生成极富表现力的文档:譬如您正在阅读的这份文档。它使用简单的符号标记不同的标题,分割不同的段落,粗体 或者 斜体 某些文字,更棒的是,它还可以

1. 制作一份待办事宜 Todo 列表

  • 支持以 PDF 格式导出文稿
  • 改进 Cmd 渲染算法,使用局部渲染技术提高渲染效率
  • 新增 Todo 列表功能
  • 修复 LaTex 公式渲染问题
  • 新增 LaTex 公式编号功能

2. 书写一个质能守恒公式[^LaTeX]

$$E=mc^2$$

3. 高亮一段代码[^code]

1
2
3
4
5
6
7
@requires_authorization
class SomeClass:
pass

if __name__ == '__main__':
# A comment
print 'hello world'

4. 高效绘制 流程图

1
2
3
4
5
6
7
8
st=>start: Start
op=>operation: Your Operation
cond=>condition: Yes or No?
e=>end

st->op->cond
cond(yes)->e
cond(no)->op

5. 高效绘制 序列图

1
2
3
Alice->Bob: Hello Bob, how are you?
Note right of Bob: Bob thinks
Bob-->Alice: I am good thanks!

6. 高效绘制 甘特图

1
2
3
4
5
6
7
8
9
10
11
12
13
title 项目开发流程
section 项目确定
需求分析 :a1, 2016-06-22, 3d
可行性报告 :after a1, 5d
概念验证 : 5d
section 项目实施
概要设计 :2016-07-05 , 5d
详细设计 :2016-07-08, 10d
编码 :2016-07-15, 10d
测试 :2016-07-22, 5d
section 发布验收
发布: 2d
验收: 3d

7. 绘制表格

项目 价格 数量
计算机 \$1600 5
手机 \$12 12
管线 \$1 234

8. 更详细语法说明

想要查看更详细的语法说明,可以参考我们准备的 Cmd Markdown 简明语法手册,进阶用户可以参考 Cmd Markdown 高阶语法手册 了解更多高级功能。

总而言之,不同于其它 所见即所得 的编辑器:你只需使用键盘专注于书写文本内容,就可以生成印刷级的排版格式,省却在键盘和工具栏之间来回切换,调整内容和格式的麻烦。Markdown 在流畅的书写和印刷级的阅读体验之间找到了平衡。 目前它已经成为世界上最大的技术分享网站 GitHub 和 技术问答网站 StackOverFlow 的御用书写格式。


什么是 Cmd Markdown

您可以使用很多工具书写 Markdown,但是 Cmd Markdown 是这个星球上我们已知的、最好的 Markdown 工具——没有之一 :)因为深信文字的力量,所以我们和你一样,对流畅书写,分享思想和知识,以及阅读体验有极致的追求,我们把对于这些诉求的回应整合在 Cmd Markdown,并且一次,两次,三次,乃至无数次地提升这个工具的体验,最终将它演化成一个 编辑/发布/阅读 Markdown 的在线平台——您可以在任何地方,任何系统/设备上管理这里的文字。

1. 实时同步预览

我们将 Cmd Markdown 的主界面一分为二,左边为编辑区,右边为预览区,在编辑区的操作会实时地渲染到预览区方便查看最终的版面效果,并且如果你在其中一个区拖动滚动条,我们有一个巧妙的算法把另一个区的滚动条同步到等价的位置,超酷!

2. 编辑工具栏

也许您还是一个 Markdown 语法的新手,在您完全熟悉它之前,我们在 编辑区 的顶部放置了一个如下图所示的工具栏,您可以使用鼠标在工具栏上调整格式,不过我们仍旧鼓励你使用键盘标记格式,提高书写的流畅度。

tool-editor

3. 编辑模式

完全心无旁骛的方式编辑文字:点击 编辑工具栏 最右侧的拉伸按钮或者按下 Ctrl + M,将 Cmd Markdown 切换到独立的编辑模式,这是一个极度简洁的写作环境,所有可能会引起分心的元素都已经被挪除,超清爽!

4. 实时的云端文稿

为了保障数据安全,Cmd Markdown 会将您每一次击键的内容保存至云端,同时在 编辑工具栏 的最右侧提示 已保存 的字样。无需担心浏览器崩溃,机器掉电或者地震,海啸——在编辑的过程中随时关闭浏览器或者机器,下一次回到 Cmd Markdown 的时候继续写作。

5. 离线模式

在网络环境不稳定的情况下记录文字一样很安全!在您写作的时候,如果电脑突然失去网络连接,Cmd Markdown 会智能切换至离线模式,将您后续键入的文字保存在本地,直到网络恢复再将他们传送至云端,即使在网络恢复前关闭浏览器或者电脑,一样没有问题,等到下次开启 Cmd Markdown 的时候,她会提醒您将离线保存的文字传送至云端。简而言之,我们尽最大的努力保障您文字的安全。

6. 管理工具栏

为了便于管理您的文稿,在 预览区 的顶部放置了如下所示的 管理工具栏:

tool-manager

通过管理工具栏可以:

发布:将当前的文稿生成固定链接,在网络上发布,分享
新建:开始撰写一篇新的文稿
删除:删除当前的文稿
导出:将当前的文稿转化为 Markdown 文本或者 Html 格式,并导出到本地
列表:所有新增和过往的文稿都可以在这里查看、操作
模式:切换 普通/Vim/Emacs 编辑模式

7. 阅读工具栏

tool-manager

通过 预览区 右上角的 阅读工具栏,可以查看当前文稿的目录并增强阅读体验。

工具栏上的五个图标依次为:

目录:快速导航当前文稿的目录结构以跳转到感兴趣的段落
视图:互换左边编辑区和右边预览区的位置
主题:内置了黑白两种模式的主题,试试 黑色主题,超炫!
阅读:心无旁骛的阅读模式提供超一流的阅读体验
全屏:简洁,简洁,再简洁,一个完全沉浸式的写作和阅读环境

8. 阅读模式

在 阅读工具栏 点击 或者按下 Ctrl+Alt+M 随即进入独立的阅读模式界面,我们在版面渲染上的每一个细节:字体,字号,行间距,前背景色都倾注了大量的时间,努力提升阅读的体验和品质。

9. 标签、分类和搜索

在编辑区任意行首位置输入以下格式的文字可以标签当前文档:

标签: 未分类

标签以后的文稿在【文件列表】(Ctrl+Alt+F)里会按照标签分类,用户可以同时使用键盘或者鼠标浏览查看,或者在【文件列表】的搜索文本框内搜索标题关键字过滤文稿,如下图所示:

file-list

10. 文稿发布和分享

在您使用 Cmd Markdown 记录,创作,整理,阅读文稿的同时,我们不仅希望它是一个有力的工具,更希望您的思想和知识通过这个平台,连同优质的阅读体验,将他们分享给有相同志趣的人,进而鼓励更多的人来到这里记录分享他们的思想和知识,尝试点击 (Ctrl+Alt+P) 发布这份文档给好友吧!


再一次感谢您花费时间阅读这份欢迎稿,点击 (Ctrl+Alt+N) 开始撰写新的文稿吧!祝您在这里记录、阅读、分享愉快!

作者 @ghosert
2016 年 07月 07日

[^LaTeX]: 支持 LaTeX 编辑显示支持,例如:$\sum_{i=1}^n a_i=0$, 访问 MathJax 参考更多使用方法。

[^code]: 代码高亮功能支持包括 Java, Python, JavaScript 在内的,四十一种主流编程语言。

1…91011
鲍志强

鲍志强

求道者

104 日志
19 分类
15 标签
GitHub E-Mail 知乎
© 2016 — 2019 baobaobao
主题 — NexT.Pisces v5.1.4