本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出 原文连接,博客地址为 http://www.cnblogs.com/jasonnode/ 。该系列课程是汇智网 整理编写的,课程地址为 http://www.dwz.cn/3e6Yml

对象

属性的简洁表示法


ES6允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。

function f( x, y ) {
return { x, y };
}
// 等同于
function f( x, y ) {
return { x: x, y: y };
}

示例:

var Person = {
name: '张三',
birth:'1990-01-01',
// 等同于hello: function ()...
hello() { document.write('我的名字是', this.name); }
};
Person.hello();

这种写法用于函数的返回值,将会非常方便。

function getPoint() {
  var x = 1;
  var y = 10;
  return {x, y};
}
getPoint() // {x:1, y:10}

属性名表达式


JavaScript语言定义对象的属性,有两种方法。

let obj = {};
// 方法一
obj.foo = true;
// 方法二
obj['a'+'bc'] = 123;
document.write(obj);

上面代码的方法一是直接用标识符作为属性名,方法二是用表达式作为属性名,这时要将表达式放在方括号之内。

如果使用字面量方式定义对象(使用大括号),在ES5中只能使用方法一(标识符)定义属性。

var obj = {
  foo: true,
  abc: 123
};

ES6允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。

let propKey = 'foo';

let obj = {
[propKey]: true,
['a'+'bc']: 123
};

表达式还可以用于定义方法名。

let obj = {
  ['h'+'ello']() {
    return 'hi';
  }
}; document.write(obj.hello()); // hi

比较两个值是否严格相等


Object.is()用来比较两个值是否严格相等。它与严格比较运算符(===)的行为基本一致,不同之处只有两个:一是+0不等于-0,二是NaN等于自身。

+0 === -0 //true
NaN === NaN // false Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

源对象的所有可枚举属性,复制到目标对象


Object.assign方法用来将源对象(source)的所有可枚举属性,复制到目标对象(target)。它至少需要两个对象作为参数,第一个参数是目标对象,后面的参数都是源对象。只要有一个参数不是对象,就会抛出TypeError错误。

var target = { a: 1 };

var source1 = { b: 2 };
var source2 = { c: 3 }; Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

var target = { a: 1, b: 1 };

var source1 = { b: 2, c: 2 };
var source2 = { c: 3 }; Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

proto属性


proto属性,用来读取或设置当前对象的prototype对象。该属性一度被正式写入ES6草案,但后来又被移除。目前,所有浏览器(包括IE11)都部署了这个属性。

// es6的写法

var obj = {
__proto__: someOtherObj,
method: function() { ... }
} // es5的写法 var obj = Object.create(someOtherObj);
obj.method = function() { ... }

Symbol类型


ES6引入了一种新的原始数据类型Symbol,表示独一无二的ID。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

let s = Symbol();

typeof s
// "symbol"

typeof运算符的结果,表明变量s是Symbol数据类型,而不是字符串之类的其他类型。

注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象。

Symbol类型的值不能与其他类型的值进行运算,会报错。

var sym = Symbol('My symbol');

"your symbol is " + sym
// TypeError: can't convert symbol to string
`your symbol is ${sym}`
// TypeError: can't convert symbol to string

但是,Symbol类型的值可以转为字符串。

var sym = Symbol('My symbol');

String(sym) // 'Symbol(My symbol)'
sym.toString() // 'Symbol(My symbol)'

内置代理


Proxy 内置的一个代理工具,使用他可以在对象处理上加一层屏障:

S6原生提供Proxy构造函数,用来生成Proxy实例。

var proxy = new Proxy(target, handler)
new Proxy()表示生成一个Proxy实例,它的target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。 var plain = {
name : "hubwiz"
};
var proxy = new Proxy(plain, {
get: function(target, property) {
return property in target ? target[property] : "汇智网";
}
}); proxy.name // "hubwiz"
proxy.title // "汇智网"

Proxy(target, handler), 这里的 handler有如下的方法:

  • get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy['foo'],返回类型不限。最后一个参数receiver可选,当target对象设置了propKey属性的get函数时,receiver对象会绑定get函数的this对象。
  • set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy['foo'] = v,返回一个布尔值。
  • has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
  • deleteProperty(target, propKey) :拦截delete proxy[propKey]的操作,返回一个布尔值。
  • enumerate(target):拦截for (var x in proxy),返回一个遍历器。
  • hasOwn(target, propKey):拦截proxy.hasOwnProperty('foo'),返回一个布尔值。
  • ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy),返回一个数组。该方法返回对象所有自身的属性,而Object.keys()仅返回对象可遍历的属性。
  • getOwnPropertyDescriptor(target, propKey) :拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
  • defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
  • preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
  • getPrototypeOf(target) :拦截Object.getPrototypeOf(proxy),返回一个对象。
  • isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
  • setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。

如果目标对象是函数,那么还有两种额外操作可以拦截。

  • apply(target, object, args):拦截Proxy实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。
  • construct(target, args, proxy):拦截Proxy实例作为构造函数调用的操作,比如new proxy(...args)。

函数

默认参数


现在可以在定义函数的时候指定参数的默认值了,而不用像以前那样通过逻辑或操作符来达到目的了。

function sayHello(name){
//传统的指定默认参数的方式
var name = name||'hubwiz';
document.write('Hello '+name);
} //运用ES6的默认参数
function sayHello2(name='hubwiz'){
document.write(`Hello ${name}`);
}
sayHello(); //输出:Hello hubwiz
sayHello('汇智网'); //输出:Hello 汇智网
sayHello2(); //输出:Hello hubwiz
sayHello2('汇智网'); //输出:Hello 汇智网

rest参数


rest参数(形式为“...变量名”)可以称为不定参数,用于获取函数的多余参数,这样就不需要使用arguments对象了。

rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

function add(...values) {
  let sum = 0;   for (var val of values) {
    sum += val;
  }
  return sum;
} add(1, 2, 3) //

不定参数的格式是三个句点后跟代表所有不定参数的变量名。比如以上示例中,...values 代表了所有传入add函数的参数。

扩展运算符


扩展运算符(spread)是三个点(...)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。该运算符主要用于函数调用。

它允许传递数组或者类数组直接做为函数的参数而不用通过apply。

var people=['张三','李四','王五'];

//sayHello函数本来接收三个单独的参数people1,people2和people3
function sayHello(people1,people2,people3){
document.write(`Hello ${people1},${people2},${people3}`);
} //但是我们将一个数组以拓展参数的形式传递,它能很好地映射到每个单独的参数
sayHello(...people); //输出:Hello 张三,李四,王五 //而在以前,如果需要传递数组当参数,我们需要使用函数的apply方法
sayHello.apply(null,people); //输出:Hello 张三,李四,王五

箭头函数


箭头函数是使用=>语法的函数简写形式。这在语法上与 C#、Java 8 和 CoffeeScript 的相关特性非常相似。

var array = [1, 2, 3];
//传统写法
array.forEach(function(v, i, a) {
  document.write(v);
});
//ES6
array.forEach(v => document.write(v));

它们同时支持表达式体和语句体。与(普通的)函数所不同的是,箭头函数和其上下文中的代码共享同一个具有词法作用域的this。

var evens = [1,2,3,4,5];
var fives = [];
// 表达式体
var odds = evens.map(v => v + 1);
var nums = evens.map((v, i) => v + i);
var pairs = evens.map(v => ({even: v, odd: v + 1})); // 语句体
nums.forEach(v => {
  if (v % 5 === 0)
    fives.push(v);
}); document.write(fives); // 具有词法作用域的 this
var bob = {
  _name: "Bob",
  _friends: ["Amy", "Bob", "Cinne", "Dylan", "Ellen"],
  printFriends() {
    this._friends.forEach(f =>
    document.write(this._name + " knows " + f));
  }
} bob.printFriends();

箭头函数有几个使用注意点。

  • 函数体内的this对象,绑定定义时所在的对象,而不是使用时所在的对象。
  • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
  • 不可以使用arguments对象,该对象在函数体内不存在。

上面三点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的。

函数绑定


函数绑定运算符是并排的两个双引号(::),双引号左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。

let log = ::console.log;
// 等同于
var log = console.log.bind(console); foo::bar;
// 等同于
bar.call(foo); foo::bar(...arguments);
i// 等同于
bar.apply(foo, arguments);

尾调用优化


什么是尾调用?

尾调用的概念非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。

function f(x){
return g(x);
}

上面代码中,函数f的最后一步是调用函数g,这就叫尾调用。

以下三种情况,都不属于尾调用。

// 情况一
function f(x){
let y = g(x);
return y;
} // 情况二
function f(x){
return g(x) + 1;
} // 情况三
function f(x){
g(x);
}

以上的示例中,情况一、二是调用函数g之后,有其他操作。情况三等同于下面的代码。

function f(x){
g(x);
return undefined;
}

  尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用记录,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用记录,取代外层函数的调用记录就可以了。

function f() {
  let m = 1;
  let n = 2;
  return g(m + n);
}
f(); // 等同于
function f() {
  return g(3);
}
f(); // 等同于
g(3);

上面代码中,如果函数g不是尾调用,函数f就需要保存内部变量m和n的值、g的调用位置等信息。但由于调用g之后,函数f就结束了,所以执行到最后一步,完全可以删除 f(x) 的调用帧,只保留g(3) 的调用帧。

“尾调用优化”(Tail call optimization),即只保留内层函数的调用帧,这样可以节省内存。

ECMAScript 6教程 (二) 对象和函数的更多相关文章

  1. 简明python教程二-----对象

    物理行:是你在编写程序时所看见的. 逻辑行:是Python看见的单个语句. 默认的,python希望每行都只使用一个语句,这样使得代码更加易读. 如果你想要在一个物理行中使用多于一个逻辑行,用分号“: ...

  2. 《zw版·Halcon-delphi系列原创教程》 Halcon分类函数010,obj,对象管理

    <zw版·Halcon-delphi系列原创教程> Halcon分类函数010,obj,对象管理 为方便阅读,在不影响说明的前提下,笔者对函数进行了简化: :: 用符号“**”,替换:“p ...

  3. Fastify 系列教程二 (中间件、钩子函数和装饰器)

    Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) 中间件 Fastify 提供了与 Express 和 Restify ...

  4. Fastify 系列教程二 (中间件、钩子函数和装饰器)

    Fastify 系列教程: Fastify 系列教程一 (路由和日志) Fastify 系列教程二 (中间件.钩子函数和装饰器) Fastify 系列教程三 (验证.序列化和生命周期) Fastify ...

  5. XAML实例教程系列 - 对象和属性(二)

    XAML实例教程系列 - 对象和属性 2012-05-22 14:18 by jv9, 1778 阅读, 6 评论, 收藏, 编辑 在前一篇已经介绍XAML概念:“XAML语言是Extensible ...

  6. ECMAScript 6 学习(二)async函数

     1.什么是async函数 2.用法 2.1基本用法 3.语法 3.1返回promise对象 3.2promise状态的变化 3.3await命令 1.什么是async函数 async函数也是异步编程 ...

  7. CRL快速开发框架系列教程二(基于Lambda表达式查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  8. 《zw版·Halcon-delphi系列原创教程》 Halcon分类函数017·point点函数

    <zw版·Halcon-delphi系列原创教程> Halcon分类函数017·point点函数 为方便阅读,在不影响说明的前提下,笔者对函数进行了简化: :: 用符号“**”,替换:“p ...

  9. 《zw版·Halcon-delphi系列原创教程》 Halcon分类函数016,xld,xld轮廓

    <zw版·Halcon-delphi系列原创教程> Halcon分类函数016,xld,xld轮廓 为方便阅读,在不影响说明的前提下,笔者对函数进行了简化: :: 用符号“**”,替换:“ ...

随机推荐

  1. Func<T>与Action<T>委托泛型介绍:转

    .Net 3.5之后,微软推出了Func<T>与Action<T>泛型委托.进一步简化了委托的定义. Action<T>委托主要的表现形式如下: public de ...

  2. 关于iOS多线程的总结

    关于iOS多线程的总结   在这篇文章中,我将为你整理一下 iOS 开发中几种多线程方案,以及其使用方法和注意事项.当然也会给出几种多线程的案例,在实际使用中感受它们的区别.还有一点需要说明的是,这篇 ...

  3. open Session In View和过滤器配置

    Open Session In View模式的主要思想是:当Web Request(浏览器请求)开始时,自动打开Session,当Web Request结束时,自动关闭Session.也就是说,Ses ...

  4. [LintCode] Longest Consecutive Sequence 求最长连续序列

    Given an unsorted array of integers, find the length of the longest consecutive elements sequence. H ...

  5. 类:String,Math,DateTime,Random随机数,异常保护

    String类: 练习: Math类: Random随机数: DateTime类: 异常保护: 练习: 1. 2. 3.方法一: 方法二: 4.人机大战石头剪刀布 5. //请输入你想输入的数字 // ...

  6. android-GridView控件的使用

    GridView 按行列方式显示多个组件(二维布局界面) 数据源(集合)-适配器(SimpleAdapter)-视图界面(GridView),加载适配器-配置监听器(OnItemClickListen ...

  7. java客户端调用c#的webservice服务

    此处使用到了CXF框架,可以使用以下坐标从maven仓库中获取相关jar包: <dependency> <groupId>org.apache.cxf</groupId& ...

  8. 继续畅通工程-Floyd

    畅通工程续 Time Limit : 3000/1000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Total Submiss ...

  9. SQL Server如何添加登录名

    1.电脑上如果安装有SQL Server,我们在开始里面打开SQL Server Management Studio,或者以桌面的快捷方式等打开SQL Server. 2.首先以Windows身份验证 ...

  10. 3D Touch

    一.认识3D Touch   1.硬件和操作系统要求      iPhone 6s或者iPhone 6s Plus      操作系统要求 ios9+ 2.3D Touch的交互效果 QuickAct ...