富有表现力的Javascript

参考书籍: 一本老书(相当老,十年前的书) 《Pro JavaScript Design Patterns》第一章 Expressive JavaScript
参考网站: 阮一峰老师的开源书籍《ECMAScript 6 入门》网站 函数的扩展Class 的基本语法
参考连接:ES5, ES6, ES2016, ES.Next: JavaScript 的版本是怎么回事?「译」

这本老书第一章节主要讲解Javascript的灵活性

1.1实现一个控制动画开始与结束的功能

/* 简单地声明两个函数*/
function startAnimation(){
    //...
};
function stopAnimation(){
   // ...
};

优点:创建起来简单
缺点:不可以用来创建动画对象

1.2创建类

1.2.1旧语法版本


// Anim class
//旧语法当中并没有相关类的声明  
//通过构造函数来模拟类,约定函数名首字母大写以和普通函数进行区分
//方式一 函数声明
function Anim(){
    //...
}

//方式二 函数表达式
var Anim = function(){
    // ...
};

1.2.2 es6语法版本

//方式一 类声明
class Anim{
    constructor{
    //...
    }
}

//方法二 class表达式  Me 不是真正类名,Me只在类内部使用
const Anim = class Me{
  constructor{
    //...
    }
}

1.3向类中添加原型方法

方法:对象中的属性的引用指向一个函数function,则这个函数称作这个对象的方法method

1.3.1 旧语法版本

//first  way 分开声明原型方法  追加原型方法的时候也可以使用这种形式
Anim.prototype.start = function (){
    // ...
};
Anim.prototype.stop = function(){
    // ...
};

//second way 集中声明原型方法
Anim.prototype = {
    start : function(){
        // ...
    },
    stop : function(){
        // ...
    }
};

//third way 给函数对象添加一个method方法,用来给类声明方法 
//追加原型方法的时候也可以使用这种形式
Function.prototype.method = function(name ,fn){
    this.prototype[name]=fn;
};

Anim.method("start",function(){
    // ...
});
Anim.method('stop',function(){
    // ...
});

//fourth way 第三种方式的升级版,允许方法链式调用 ,
//仅仅是简单地在创建方法之后返回this
Function.prototype.method = function(name ,fn){
    this.prototype[name] = fn;
    return this;
}

1.3.2 es6语法版本

用于检测的几个api:

  • Object.keys(Anim.prototype) 返回Anim类原型上自身可枚举属性名的数组
  • Object.getOwnPropertyNames(Anim.prototype) 返回Anim类原型上自身所有属性名的数组(可枚举,不可枚举的统统列出来)
  • 某某对象.hasOwnProperty(“属性名”) 检测某对象自身是否有某属性,返回true或false
  • for…in 列出所有可枚举的属性,包括原型链上的属性
//fist way 直接在声明类的时候,在其内部定义方法
//定义“类”的方法的时候,前面不需要加上function这个关键字
const Anim = class {
    constructor() {
        // ...
    }
    //注意:类内部定义的方法  是不可枚举的
    start() {

    }
    stop() {

    }
    //类内部定义方法的属性名可以使用表达式
    ["te" + "st"]() {

    }
}

// second way 直接在 class 的prototype 属性对象上定义原型方法
//同样不用写function关键字 

//备注:这种形式是从阮一峰老师的开源书籍 [Class 的基本语法]一章中看到的
//为了理解便拿来做实验用,对其不太了解,所以在实际开发的时候暂时不用这种方式

//当时我电脑上装的node 版本为8.9.3  ,使用sublime 的nodejs插件 ctrl+b 
//直接运行这段代码的时候, 无法识别这种形式定义的原型方法
//疑问:为啥不能识别?
//要使用babel编译之后才能识别定义的原型方法

// 注意:对Anim的prototype属性对象直接赋值
// 经过 babel 编译器编译后, 会直接覆盖掉Anim内部定义的原型方法
// 所以喽,要写上constructor(){} 构造函数呦,要有这个函数呦.
// 经过这种方法声明的原型方法是可以被枚举的

class Anim {};

Anim .prototype = {
    constructor() {},
    start(){},
    stop(){}
}

//third way 旧语法版本里的那几种方法都可以用 ,因为 typeof Anim 的结果为function
// javascript 中的 class本质还是函数,实例对象指向的原型是同一个原型
//...

//追加原型方法  说明:Object.assign 是es5中的Api
Object.assign(Anim.prototype, {
    method1() {
       //...
    },
    method2(){
      //...
    }
});


//额外的内容 立即执行类

//立即执行的Class

let person = new class {
    constructor(name) {
        this.name = name;
    }

    sayName() {
        console.log(this.name);
    }
}('张三');

//test
person.sayName(); //张三

1.4 立即执行函数

1.4.1旧语法版本

//立即执行函数最常用的功能是隔离作用域 外部无法访问到 foo变量
(function(){
    var foo=10;
    var bar=2;
    console.log(foo*bar);
})();

//匿名函数带参数+立即执行 
(function(foo,bar){
    console.log(foo*bar);
})(10,2);

//匿名函数立即执行并返回一个值
var baz = (function(foo,bar){
    return foo*bar ;
})(10,2);

//闭包是一个被保护的变量空间,通过嵌套函数来创建
//函数运行在被定义时的作用域中,可以访问被定义时作用域中的变量.

//匿名函数更有趣的一种使用方式是用来创建一个闭包
//通过使用匿名函数包裹函数,来达到保护变量的目的
var baz;
(function(){
  var foo=10;
  var bar =2;
  baz = function(){
     return foo*bar;
  }
})();

//或者长这样
var baz = (function(){
  var foo=10;
  var bar =2;
  return function(){
     return foo*bar;
  }
})();

baz(); //baz可以访问 foo和bar 尽管它是在 匿名函数外执行的

1.4.1es6语法版本

//箭头函数使得函数表达式更加简洁
//箭头函数的一个用处就是简化回调函数,this指向固定化,也很适合用用于回调函数
//箭头函数的this指向函数定义生效时所在的对象,因此可以用在定时器中
//单个参数可以不使用括号,没有参数或多个参数用括号
//箭头函数单条语句可以不使用花括号,多条语句要使用花括号并返回值
//什么都不返回则 写void doseNotReturn(); 
//单独返回对象则用括号把对象括起来

//花括号,块级作用,隔离作用域 外部无法访问到 foo变量
{
    let foo=10;
    let bar = 2;
    console.log(foo*bar);
}

//匿名函数带参数+立即执行 
{
    ((foo,bar)=>console.log(foo*bar))(10,2);
}

//匿名函数立即执行并返回一个值
{
    let baz=((foo,bar)=>foo*bar)(10,2);
    console.log(baz);
}

//闭包是一个被保护的变量空间,通过嵌套函数来创建
//函数运行在被定义时的作用域中,可以访问被定义时作用域中的变量.

let baz;
(() => {
    let foo = 10;
    let bar = 2;
    baz = () => foo * bar;
})()

baz(); //baz可以访问 foobar 尽管它是在 匿名函数外执行的

es6语法版javascript设计模式练习计划查看初始内容


Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐