JavaScript初探系列——ES6

一、前言

ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。这句话基本涵盖了为什么会产生ES6这次更新的原因——编写复杂的大型应用程序。回顾近两年的前端开发,复杂度确实在快速增加,近期不论从系统复杂度还是到前端开发人员数量应该达到了一个饱和值,换个方式说,没有ES6我们的前端代码依旧可以写很多复杂的应用,而ES6的提出更好的帮我们解决了很多历史遗留问题,另一个角度ES6让JS更适合开发大型应用,而不用引用太多的库了。本文,简单介绍几个ES6核心概念,个人感觉只要掌握以下新特性便能愉快的开始使用ES6做代码了!这里的文章,请配合着阮老师这里的教程,一些细节阮老师那边讲的好得多:http://es6.ruanyifeng.com/#docs/class-extends

除了阮老师的文章还参考:http://www.infoq.com/cn/articles/es6-in-depth-arrow-functions

二、模块Module的引入

都说了复杂的大型应用了,所以我们第一个要讨论的重要特性就是模块概念,我们做一个复杂的项目必定需要两步走:

① 分得开,并且需要分开

② 合得起来

我们普遍认为没有复杂的应用,只有分不开的应用,再复杂的应用,一旦可以使用组件化、模块化的方式分成不同的小单元,那么其难度便会大大降低,模块化是大型、复杂项目的主要拦路虎。为了解决这个问题,社区制定了一些模块加载方案,对于浏览器开发来说,我们用的最多的是AMD规范,也就是大家熟知的requireJS,而ES6中在语音标准层面实现了模块功能,用以取代服务端通信的CommonJS和AMD规范,成为了通用的规范,多说无益,我们这里上一段代码说明:

 1 /*
 2 validate.js 多用于表单验证
 3 */
 4 export function isEmail (text) {
 5     var reg = /^(([^<>()[\]\\.,;:\[email protected]\"]+(\.[^<>()[\]\\.,;:\[email protected]\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
 6     return reg.test(text);
 7 }
 8
 9 export function  isPassword (text) {
10     var reg = /^[a-zA-Z0-9]{6,20}$/;
11     return reg.test(text);
12 }

那么我们现在想在页面里面使用这个工具类该怎么做呢:

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <!-- 请注意这里type=module才能运行 -->
 9 <script type="module">
10     import {isEmail} from ‘./validate.js‘;
11     var e1 = ‘dddd‘;
12     var e2 = ‘[email protected]‘
13     console.log(isEmail(e1))
14     console.log(isEmail(e2))
15 </script>
16 </body>
17 </html>

ES6中的Module提出,在我这里看来是想在官方完成之前requireJS干的工作,这里也有一些本质上的不一样:

① requireJS是使用加载script标签的方式载入js,没有什么限制

② import命令会被js引擎静态分析,先于模块其他语句执行

以上特性会直接给我们带来一些困扰,比如原来我们项目控制器会有这么一段代码:

1 var viewId = ‘‘; //由浏览器获取试图id,url可能为?viewId=booking|list|...
2 //如果不存在则需要构建,记住构建时需要使用viewdata继承源view
3 requirejs(viewId, function(View) {
4     //执行根据url参数动态加载view逻辑
5 })

前面说过了,import命令会被js引擎静态分析,先于模块其他语句执行,所以我们在根本不能将import执行滞后,或者动态化,做不到的,这种写法也是报错的:

if (viewId) {
  import view from ‘./‘ + viewId;
}

这种设计会有利于提高编译器效率,但是之前的动态业务逻辑就不知道如何继续了?而ES6如果提供import的方法,我们变可以执行逻辑:

1 import(viewId, function() {
2     //渲染页面
3 })

事实上他也提供了:

现在看起来,JS中的模块便十分完美了,至于其中一些细节,便可以用到的时候再说了

三、ES6中的类Class

我们对我们的定位一直是非常清晰的,我们就是要干大项目的,我们是要干复杂的项目,除了模块概念,类的概念也非常重要,我们之前用的这种方式实现一个类,我们来温故而知新。

当一个函数被创建时,Function构造函数产生的函数会隐式的被赋予一个prototype属性,prototype包含一个constructor对象

而constructor便是该新函数对象(constructor意义不大,但是可以帮我们找到继承关系)

每个函数都会有一个prototype属性,该属性指向另一对象,这个对象包含可以由特定类型的所有实例共享的属性和方法

每次实例化后,实例内部都会包含一个[[prototype]](__proto__)的内部属性,这个属性指向prototype

① 我们通过isPrototypeOf来确定某个对象是不是我的原型

② hasOwnPrototype 可以检测一个属性是存在实例中还是原型中,该属性不是原型属性才返回true

var Person = function (name, age) {
    this.name = name;
    this.age = age;
};
Person.prototype.getName = function () {
    return this.name;
};
var y = new Person(‘叶小钗‘, 30);

为了方便,使用,我们做了更为复杂的封装这里写一个demo:

var arr = [];
var slice = arr.slice;

function create() {
  if (arguments.length == 0 || arguments.length > 2) throw ‘参数错误‘;

  var parent = null;
  //将参数转换为数组
  var properties = slice.call(arguments);

  //如果第一个参数为类(function),那么就将之取出
  if (typeof properties[0] === ‘function‘)
    parent = properties.shift();
  properties = properties[0];

  function klass() {
    this.initialize.apply(this, arguments);
  }

  klass.superclass = parent;
  klass.subclasses = [];

  if (parent) {
    var subclass = function () { };
    subclass.prototype = parent.prototype;
    klass.prototype = new subclass;
    parent.subclasses.push(klass);
  }

  var ancestor = klass.superclass && klass.superclass.prototype;
  for (var k in properties) {
    var value = properties[k];

    //满足条件就重写
    if (ancestor && typeof value == ‘function‘) {
      var argslist = /^\s*function\s*\(([^\(\)]*?)\)\s*?\{/i.exec(value.toString())[1].replace(/\s/i, ‘‘).split(‘,‘);
      //只有在第一个参数为$super情况下才需要处理(是否具有重复方法需要用户自己决定)
      if (argslist[0] === ‘$super‘ && ancestor[k]) {
        value = (function (methodName, fn) {
          return function () {
            var scope = this;
            var args = [function () {
              return ancestor[methodName].apply(scope, arguments);
            } ];
            return fn.apply(this, args.concat(slice.call(arguments)));
          };
        })(k, value);
      }
    }

    klass.prototype[k] = value;
  }

  if (!klass.prototype.initialize)
    klass.prototype.initialize = function () { };

  klass.prototype.constructor = klass;

  return klass;
}
var AbstractView = create({
  initialize: function (opts) {
    opts = opts || {};
    this.wrapper = opts.wrapper || $(‘body‘);

    //事件集合
    this.events = {};

    this.isCreate = false;

  },
  on: function (type, fn) {
    if (!this.events[type]) this.events[type] = [];
    this.events[type].push(fn);
  },
  trigger: function (type) {
    if (!this.events[type]) return;
    for (var i = 0, len = this.events[type].length; i < len; i++) {
      this.events[type][i].call(this)
    }
  },
  createHtml: function () {
    throw ‘必须重写‘;
  },
  create: function () {
    this.root = $(this.createHtml());
    this.wrapper.append(this.root);
    this.trigger(‘onCreate‘);
    this.isCreate = true;
  },
  show: function () {
    if (!this.isCreate) this.create();
    this.root.show();
    this.trigger(‘onShow‘);
  },
  hide: function () {
    this.root.hide();
  }
});

var Alert = create(AbstractView, {

  createHtml: function () {
    return ‘<div class="alert">这里是alert框</div>‘;
  }
});

var AlertTitle = create(Alert, {
  initialize: function ($super) {
    this.title = ‘‘;
    $super();

  },
  createHtml: function () {
    return ‘<div class="alert"><h2>‘ + this.title + ‘</h2>这里是带标题alert框</div>‘;
  },

  setTitle: function (title) {
    this.title = title;
    this.root.find(‘h2‘).html(title)
  }

});

var AlertTitleButton = create(AlertTitle, {
  initialize: function ($super) {
    this.title = ‘‘;
    $super();

    this.on(‘onShow‘, function () {
      var bt = $(‘<input type="button" value="点击我" />‘);
      bt.click($.proxy(function () {
        alert(this.title);
      }, this));
      this.root.append(bt)
    });
  }
});

var v1 = new Alert();
v1.show();

var v2 = new AlertTitle();
v2.show();
v2.setTitle(‘我是标题‘);

var v3 = new AlertTitleButton();
v3.show();
v3.setTitle(‘我是标题和按钮的alert‘);

ES6中直接从标准层面解决了我们的问题,他提出了Class关键词让我们可以更好的定义类,我们这里用我们ES6的模块语法重新实现一次:

 1 export class AbstractView {
 2     constructor(opts) {
 3         opts = opts || {};
 4         this.wrapper = opts.wrapper || $(‘body‘);
 5         //事件集合
 6         this.events = {};
 7         this.isCreate = false;
 8     }
 9     on(type, fn) {
10         if (!this.events[type]) this.events[type] = [];
11         this.events[type].push(fn);
12     }
13     trigger(type) {
14         if (!this.events[type]) return;
15         for (var i = 0, len = this.events[type].length; i < len; i++) {
16             this.events[type][i].call(this)
17         }
18     }
19     createHtml() {
20         throw ‘必须重写‘;
21     }
22     create() {
23         this.root = $(this.createHtml());
24         this.wrapper.append(this.root);
25         this.trigger(‘onCreate‘);
26         this.isCreate = true;
27     }
28     show() {
29         if (!this.isCreate) this.create();
30         this.root.show();
31         this.trigger(‘onShow‘);
32     }
33     hide() {
34         this.root.hide();
35     }
36 }
37 export class Alert extends AbstractView {
38     createHtml() {
39         return ‘<div class="alert">这里是alert框</div>‘;
40     }
41 }
42 export class AlertTitle extends Alert {
43     constructor(opts) {
44         super(opts);
45         this.title = ‘‘;
46     }
47     createHtml() {
48         return ‘<div class="alert"><h2>‘ + this.title + ‘</h2>这里是带标题alert框</div>‘;
49     }
50     setTitle(title) {
51         this.title = title;
52         this.root.find(‘h2‘).html(title)
53     }
54 }
55 export class  AlertTitleButton extends AlertTitle {
56     constructor(opts) {
57         super(opts);
58         this.on(‘onShow‘, function () {
59             var bt = $(‘<input type="button" value="点击我" />‘);
60             bt.click($.proxy(function () {
61                 alert(this.title);
62             }, this));
63             this.root.append(bt)
64         });
65     }
66 }

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8 <script type="text/javascript" src="zepto.js"></script>
 9
10 <!-- 请注意这里type=module才能运行 -->
11 <script type="module">
12 import {Alert, AlertTitle, AlertTitleButton} from ‘./es6class.js‘;
13 var v1 = new Alert();
14 v1.show();
15 var v2 = new AlertTitle();
16 v2.show();
17 v2.setTitle(‘我是标题‘);
18 var v3 = new AlertTitleButton();
19 v3.show();
20 v3.setTitle(‘我是标题和按钮的alert‘);
21 </script>
22 </body>
23 </html>

这里的代码完成了与上面一样的功能,而代码更加的清爽了。

四、ES6中的函数

我们这里学习ES6,由大到小,首先讨论模块,其次讨论类,这个时候理所当然到了我们的函数了,ES6中函数也多了很多新特性或者说语法糖吧,首先我们来说一下这里的箭头函数

(一)、箭头函数

//ES5
$(‘#bt‘).click(function (e) {
    //doing something
})
//ES6
$(‘#bt‘).click(e => {
    //doing something
})

有点语法糖的感觉,有一个很大不同的是,箭头函数不具有this属性,箭头函数直接使用的是外部的this的作用域,这个想不想用看个人习惯吧。

(二)、参数新特性

ES6可以为参数提供默认属性

1 function log(x, y = ‘World‘) {
2   console.log(x, y);
3 }
4
5 log(‘Hello‘) // Hello World
6 log(‘Hello‘, ‘China‘) // Hello China
7 log(‘Hello‘, ‘‘) // Hello

至于不定参数撒的,我这里没有多过多的使用,等项目遇到再说吧,如果研究的太细碎,反而不适合我们开展工作。

五、let、const和var

之前的js世界里,我们定义变量都是使用的var,别说还真挺好用的,虽有会有一些问题,但是对于熟悉js特性的小伙伴都能很好的解决,一般记住:变量提升会解决绝大多数问题。

就能解决很多问题,而且真实项目中,我们会会避免出现变量出现重名的情况所以有时候大家面试题中看到的场景在实际工作中很少发生,只要不刻意臆想、制造一些难以判断的场景,其实并不会出现多少BUG,不能因为想考察人家对语言特性的了解,就做一些容易容易忘掉的陷阱题。

无论如何,var 声明的变量受到了一定诟病,事实上在强类型语言看来也确实是设计BUG,但是完全废弃var的使用显然不是js该做的事情,这种情况下出现了let关键词。

let与var一致用以声明变量,并且一切用var的地方都可以使用let替换,新的标准也建议大家不要再使用var了,let具有更好的作用域规则,也许这个规则是边界更加清晰了:

{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

这里是一个经典的闭包问题:

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

因为i在全局范围有效,共享同一个作用域,所以i就只有10了,为了解决这个问题,我们之前会引入闭包,产生新的作用域空间(好像学名是变量对象,我给忘了),但是那里的i跟这里的i已经不是一个东西了,但如果将var改成let,上面的答案是符合预期的。可以简单理解为每一次“{}”,let定义的变量都会产生新的作用域空间,这里产生了循环,所以每一次都不一样,这里与闭包有点类似是开辟了不同的空间。

for (let i = 0; i < 3; i++) {
  let i = ‘abc‘;
  console.log(i);
}
// abc
// abc
// abc

这里因为内部重新声明了i,事实上产生了3个作用域,这里一共有4个作用域指向,let最大的作用就是js中块级作用域的存在,并且内部的变量不会被外部所访问,所以之前为了防止变量侮辱的立即执行函数,似乎变得不是那么必要了。

之前我们定义一个常量会采用全部大写的方式:

var NUM = 10;

为了解决这个问题,ES6引入了const命令,让我们定义只读常量,这里不对细节做过多研究,直接后续项目实践吧,项目出真知。

六、生成器Generators

ES6中提出了生成器Generators的概念,这是一种异步编程的解决方案,可以将其理解为一种状态机,封装了多个内部状态,这里来个demo:

function* helloWorldGenerator() {
  yield ‘hello‘;
  yield ‘world‘;
  return ‘ending‘;
}
var hw = helloWorldGenerator();
hw.next()
// { value: ‘hello‘, done: false }
hw.next()
// { value: ‘world‘, done: false }
hw.next()
// { value: ‘ending‘, done: true }
hw.next()
// { value: undefined, done: true }

这个yield(产出)类似于之前的return,直观的理解就是一个函数可以返回多次了,或者说函数具有“顺序状态”,yield提供了暂停功能。这里我想写个代码来验证下期中的作用域状态:

function* test(){
    let i = 0;
    setTimeout(function() {
        i++;
    }, 1000);
    yield i;
    yield i++;
    return i
}

let t = test();
console.log(t.next());

setTimeout(function() {
    console.log(t.next());
}, 2000);
console.log(t.next());

//{value: 0, done: false}
//{value: 0, done: false}
//{value: 2, done: true}

之前我们写一个城市级联的代码,可能会有些令人蛋疼:

 1 $.get(‘getCity‘, {id: 0}, function(province) {
 2     let pid = province[0];
 3     //根据省id获取城市数据
 4     $.get(‘getCity‘, {id: pid}, function(city) {
 5         let cityId = city[0];
 6         //根据市级id获取县
 7         $.get(‘getCity‘, {id: cityId}, function(city) {
 8             //do smt.
 9         });
10     });
11 });

这个代码大家应当比较熟悉了,用promise能从语法层面解决一些问题,这里简单介绍下promise。

(一)、Promise

Promise是一种异步解决方案,有些同事认为其出现就是为了我们代码变得更好看,解决回调地狱的语法糖,ES6将其写入了语音标准,提供了原生Promise对象。Promise为一容器,里面保存异步事件的结果,他是一个对象具有三个状态:pending(进行中)、fulfilled(已成功)、rejected(已失败),这里还是来个简单代码说明:

1 function timeout(ms) {
2   return new Promise((resolve, reject) => {
3     setTimeout(resolve, ms, ‘done‘);
4   });
5 }
6
7 timeout(100).then((value) => {
8   console.log(value);
9 });

实例化Promise时,第一个回调必须提供,是进行转为成功时候会执行,第二个也是一个函数失败时候调用,非必须,这里来个demo:

 1 let  timeout = function (ms) {
 2     return new Promise(function (resolve) {
 3         setTimeout(resolve, ms);
 4     });
 5 };
 6
 7 timeout(1000).then(function () {
 8     return timeout(1000).then(function () {
 9         let s = ‘大家‘;
10         console.log(s)
11         return s;
12     })
13
14 }).then(function (data) {
15     return timeout(1000).then(function () {
16         let s = data + ‘好,‘;
17         console.log(s)
18         return s;
19     })
20 }).then(function(data) {
21     return timeout(1000).then(function () {
22         let s = data + ‘我是叶小钗‘;
23         console.log(s)
24         return s;
25     });
26 }).then(function(data) {
27     console.log(data)
28 });

如果我们请求有依赖的话,第一个请求依赖于第二个请求,代码就可以这样写:

 1 let getData = function(url, param) {
 2     return new Promise(function (resolve) {
 3         $.get(url, param, resolve );
 4     });
 5 }
 6 getData(‘http://api.kuai.baidu.com/city/getstartcitys?callback=?‘).then(function (data) {
 7     console.log(‘我获取了省数据,我们马上根据省数据申请市数据‘, data);
 8     return getData(‘http://api.kuai.baidu.com/city/getstartcitys?callback=?‘).then(function (data1) {
 9         console.log(data1);
10         return ‘我是市数据‘;
11     })
12
13 }).then(function(data) {
14     //前面的参数传过来了
15     console.log(data);
16     console.log(‘我获取了市数据,我们马上根据市数据申请县数据‘);
17     getData(‘http://api.kuai.baidu.com/city/getstartcitys?callback=?‘).then(function (data1) {
18         console.log(data1);
19     });
20 })

如此便可以避免多层嵌套了,关于Promise的知识点还很多,我们遇到复杂的工作场景再拿出来说吧,我对他的定位就是一个语法糖,将异步的方式变成同步的写法,骨子里还是异步,上面我们用Promise解决回调地狱问题,但是回调地狱问题遇到的不多,却发现Promise一堆then看见就有点烦,我们的Generator函数似乎可以让这个情况得到缓解。

但是暂时在实际工作中我没有找到更好的使用场景,这里暂时到这里,后面工作遇到再详述,对这块不是很熟悉也不妨碍我们使用ES6写代码。

七、代理

代理,其实就是你要做什么我帮你做了就行了,一般代理的原因都是,我需要做点手脚,或者多点操作,或者做点“赋能”,如我们常常包装setTimeout一般:

1 let timeout = function (ms, callback) {
2     setTimeout(callback, ms);
3 }

我们包装setTimeout往往是为了clearTimeout的时候能全部清理掉,其实就是拦截下,ES6提供了Proxy关键词用于设置代理器:

 1 var obj = new Proxy({}, {
 2   get: function (target, key, receiver) {
 3     console.log(`getting ${key}!`);
 4     return Reflect.get(target, key, receiver);
 5   },
 6   set: function (target, key, value, receiver) {
 7     console.log(`setting ${key}!`);
 8     return Reflect.set(target, key, value, receiver);
 9   }
10 });
11 obj.count = 1
12 //  setting count!
13 ++obj.count
14 //  getting count!
15 //  setting count!
16 //  2

//target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为
var proxy = new Proxy(target, handler);

我们这里继续写一个简单的demo:

 1 let person = {
 2     constructor: function(name, age = 20) {
 3         this.name = name;
 4         this.age = age
 5     },
 6     addAge: function() {
 7         this.age++;
 8     },
 9     getAge: function() {
10         return this.age;
11     }
12 }
13
14 var proxy = new Proxy(person, {
15     get: function(target, property) {
16         console.log(arguments);
17         return target[property];
18     },
19     set: function(target, property) {
20         console.log(arguments);
21     }
22 });
23
24 person.constructor(‘叶小钗‘, 30);
25 console.log(person.age)
26 console.log(proxy.age)

但是暂时我没有发现比较好的业务场景,比如说,我现在重写了一个实例的get方法,便能在一个全局容器中记录这个被执行了多少次,这里一个业务场景是:我一次个页面连续发出了很多次请求,但是我单页应用做页面跳转时候,我需要将所有的请求句柄移除,这个似乎也不是代理完成的工作,于是要使用ES6写代码,似乎可以暂时忽略代理。

参考资料:https://www.cnblogs.com/yexiaochai/p/9359943.html

原文地址:https://www.cnblogs.com/wyh19941210/p/11565139.html

时间: 2024-10-07 11:26:17

JavaScript初探系列——ES6的相关文章

JavaScript初探系列之String的基本操作

1.字符串转换 字符串转换是最基础的要求和工作,你可以将任何类型的数据都转换为字符串,你可以用下面三种方法的任何一种: var num= 19; // 19 var myStr = num.toString(); // "19" 你同样可以这么做: var num= 19; // 19 var myStr = String(num); // "19" 或者,再简单点儿: var num= 19; // 19 var myStr = "" +num

JavaScript初探系列之面向对象

面向对象的语言有一个标志,即拥有类的概念,抽象实例对象的公共属性与方法,基于类可以创建任意多个实例对象,一般具有封装.继承.多态的特性!但JS中对象与纯面向对象语言中的对象是不同的,ECMA标准定义JS中对象:无序属性的集合,其属性可以包含基本值.对象或者函数.可以简单理解为JS的对象是一组无序的值,其中的属性或方法都有一个名字,根据这个名字可以访问相映射的. 一   重新认识面向对象 为了说明 JavaScript 是一门彻底的面向对象的语言,首先有必要从面向对象的概念着手 , 探讨一下面向对

JavaScript初探系列之日期对象

时间对象是一个我们经常要用到的对象,无论是做时间输出.时间判断等操作时都与这个对象离不开.它是一个内置对象--而不是其它对象的属性,允许用户执行各种使用日期和时间的过程. 一   Date 日期对象 日期对象可以储存任意一个日期,并且可以精确到毫秒数(1/1000 秒). 定义一个时间对象 : var Udate=new Date(); 注意:使用关键字new,Date()的首字母必须大写. 使 Udate 成为日期对象,并且已有初始值:当前时间(当前电脑系统时间). 如果要自定义初始值,可以用

JavaScript初探系列之数组的基本操作

在程序语言中数组的重要性不言而喻,JavaScript中数组也是最常使用的对象之一,数组是值的有序集合,由于弱类型的原因,JavaScript中数组十分灵活.强大,不像是Java等强类型高级语言数组只能存放同一类型或其子类型元素,JavaScript在同一个数组中可以存放多种类型的元素,而且是长度也是可以动态调整的,可以随着数据增加或减少自动对数组长度做更改. 一.创建数组 在JavaScript多种方式创建数组 (一)构造函数 1.无参构造函数,创建一空数组 var a1=new Array(

JavaScript初探系列之Ajax应用

一 什么是Ajax Ajax是(Asynchronous JavaScript And XML)是异步的JavaScript和xml.也就是异步请求更新技术.Ajax是一种对现有技术的一种新的应用,不是一门新语言.它是用JavaScript编写.与xml的关系就是可以读取和返回xml文件. Ajax在2005年提出的,在2006,2007年迅速的发展,目前很多网站都使用了ajax技术,在招聘软件工程师时,ajax技术是必须要求掌握的. AJAX即"Asynchronous JavaScript

JavaScript初探系列——DOM

DOM(文档对象模型)是针对HTML和XML文档的一个API,描绘了一个层次化的节点树,允许开发人员添加.删除和修改页面的某一部分. HTML DOM 树形结构如下: 一.Node方面 (一).节点类型 节点类型(nodeName) 数值常量(nodeValue) 元素节点 1 属性节点 2 文本节点 3 注释节点 8 文档节点 9 文档碎片节点 11 确定节点类型,兼容的方法是将nodeType属性与数字值进行比较,如下所示: if(someNode.nodeType==1){ alert("

深入理解javascript作用域系列第四篇——块作用域

× 目录 [1]let [2]const [3]try 前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀.简洁的代码,比如块作用域.随着ES6的推广,块作用域也将用得越来越广泛.本文是深入理解javascript作用域系列第四篇——块作用域 let for (var i= 0; i<10; i++) { console.log(i); } 上面这段是很熟

深入理解javascript函数系列第三篇

前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数系列第三篇--属性和方法 属性 [length属性] 函数系列第二篇中介绍过,arguments对象的length属性表示实参个数,而函数的length属性则表示形参个数 function add(x,y){ console.log(arguments.length)//3 console.log(

javascript面向对象系列第三篇——实现继承的3种形式

前面的话 学习如何创建对象是理解面向对象编程的第一步,第二步是理解继承.开宗明义,继承是指在原有对象的基础上,略作修改,得到一个新的对象.javascript主要包括类式继承.原型继承和拷贝继承这三种继承方式.本文是javascript面向对象系列第三篇——实现继承的3种形式 类式继承 大多数面向对象的编程语言都支持类和类继承的特性,而JS却不支持这些特性,只能通过其他方法定义并关联多个相似的对象,如new和instanceof.不过在后来的ES6中新增了一些元素,比如class关键字,但这并不