天天看點

ES6--對象、函數的擴充

版權聲明:本文為部落客原創文章,遵循 CC 4.0 by-sa 版權協定,轉載請附上原文出處連結和本聲明。

本文連結:https://ligang.blog.csdn.net/article/details/70197432

七、對象的擴充

ES6中為對象屬性和方法提供了簡潔的方式,表達式作為屬性名變成可能,并提供了name屬性傳回函數名。

屬性的簡潔表示法

const name = 'ligang';
const person = {
    name,
    sayName() {
        console.log(this.name);
    }
};           

複制

屬性名表達式

const propKey = 'name';
const person = {
  [propKey]: "ligang",
  ['a' + 'ge']: 27
}           

複制

方法的name屬性

var doSomething = function() {}
doSomething.name; // "doSomething"
(new Function()).name;  // "anonymous"           

複制

取值函數

存值函數在方法名的前面加上set;取值函數在方法名的前面加上get。

var person = {
    set name(n) {
        this.n = n;
    },
    get name() {
        return this.n;
    }
};
console.log(person.name); // undefined
person.name = 'ligang';
console.log(person.name); // "ligang"           

複制

Object.is()

用來比較兩個值是否嚴格相等。它與嚴格比較運算符(===)的行為基本一緻,不同之處隻有兩個:一是+0不等于-0,二是NaN等于自身。

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

複制

Object.assign()

用來将源對象(source)的所有可枚舉屬性,複制到目标對象(target)。

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

複制

注意: Object.assign方法實行的是淺拷貝,而不是深拷貝。也就是說,如果源對象某個屬性的值是對象,那麼目标對象拷貝得到的是這個對象的引用。

用途(1):為對象添加屬性

class Point {
  constructor(x, y) {
    Object.assign(this, {x, y});
  }
}           

複制

用途(2):為對象添加方法

Object.assign(SomeClass.prototype, {
  someMethod(arg1, arg2) {},
  anotherMethod() {}
});           

複制

用途(3):克隆對象

function clone(origin) {
  return Object.assign({}, origin);
}           

複制

用途(4):合并多個對象

const merge = (target, ...sources) => Object.assign(target, ...sources);           

複制

用途(5):為屬性指定預設值

const DEFAULTS = {
  logLevel: 0,
  outputFormat: 'html'
};
function processContent(options) {
  options = Object.assign({}, DEFAULTS, options);
}           

複制

__proto__屬性

該屬性被大部分浏覽器實作,但其并沒有被ES6正式收錄。是以不建議直接使用該屬性,而是使用

Object.setPrototypeOf()

(寫操作)、

Object.getPrototypeOf()

(讀操作)、

Object.create()

(生成操作)代替。

function A(){}
A.prototype.say = function(){console.log("A");};
function B(){}
B.prototype.say = function(){console.log("B");};

var obj = Object.create(A.prototype);
obj.say();  // "A"
Object.getPrototypeOf(obj); // Object(A)
Object.setPrototypeOf(obj, B.prototype);
obj.say();  // "B"
Object.getPrototypeOf(obj); // Object(B)           

複制

對象的擴充運算符

ES7提案将rest參數引入對象,目前Babel已經支援這項功能。

let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }           

複制

八、函數的擴充

函數參數預設值

ES6之前不能直接為函數的參數指定預設值,隻能采用變通的方法,通過“||”來規避,如下:

function log(x, y) {
  y = y || 'World';
  console.log(x, y);
}           

複制

但上述存在一個問題,當y對應的布爾值為false,則該指派不起作用。

log('Hello',0);// Hello World           

複制

面對上述問題,我們通常會:

// 寫法一
if (typeof y === 'undefined') {
    y = 'World';
}
// 寫法二
if (arguments.length === 1) {
    y = 'World';
}           

複制

在ES6中允許為函數的參數設定預設值,即直接寫在參數定義的後面。

function log(x, y = 'World') {
  console.log(x, y);
}           

複制

rest參數

ES6引入rest參數(形式為“…變量名”),用于擷取函數的多餘參數,這樣就不需要使用arguments對象了。

function add(...values) {
  let sum = 0;
  for(let val of values) {
    sum += val;
  }
  return sum;
}           

複制

注意:

  • rest參數之後不能再有其他參數(即隻能是最後一個參數),否則會報錯;
  • 函數的length屬性,不包括rest參數。

擴充運算符

擴充運算符(spread)是三個點(…)好比rest參數的逆運算,将一個數組轉為用逗号分隔的參數序列。

// 等價于Math.max(14, 3, 77)
Math.max(...[14, 3, 77]); 

// 與解構指派結合起來,用于生成數組
const [first, ...rest] = [1, 2, 3, 4, 5];             

複制

箭頭函數

(1)使用文法

方式一:單一參數的單行箭頭函數

文法:

arg => statement

示例:

const fn = x => x + 1;
fn(1); // 2           

複制

方式二:多參數的單行箭頭函數

文法:

(arg1, arg2) => statement

示例:

const fn = (x, y) => x + y;
fn(1, 1); // 2           

複制

方式三:多行箭頭函數

文法:

arg => {}
(arg1, arg2) => {}           

複制

示例:

const fn = (x, y) => {
  return x + y;
}
fn(1, 1); // 2           

複制

方式四:無參數箭頭函數

文法:

() => statemnt

示例:

const fn = () => console.log("hello");
fn(); // "hello"           

複制

(2)this穿透

箭頭函數會将函數内部的this延伸至上一層作用域中,即上一層的上下文會穿透到内層的箭頭函數中。

// ES5
var name = "window";
var obj = {
  name: "obj",
  sayName: function(){
    return function(){
      console.log(this.name);
    }
  }
};
var sayname = obj.sayName();
sayname();  // "window"
sayName.call(obj); // "obj"

// ES6
var name = "window";
var obj = {
  name: "obj",
  sayName: function(){
    return () => console.log(this.name);
  }
};

var sayname = obj.sayName();
sayname();  // "obj"
sayname.call(obj);  // "obj"           

複制

(3)注意事項

  • 箭頭函數對上下文的綁定是強制的,無法通過apply或call方法改變。見上述示例
  • 因為箭頭函數綁定上下文的特性,故不能随意在頂層作用域使用箭頭函數
var name = "window";
var obj = {
  name: "obj",
  sayName: () => console.log(this.name)
}
obj.sayName();  // "window"

// ES5等價方式
var name = "window";
var that = this;
var obj = {
  name: "obj",
  sayName: function(){
    console.log(that.name);
  }
}
obj.sayName();  // "window"           

複制

  • 箭頭函數中沒有arguments、callee、caller等對象
var fn = () => {
  console.log(arguments);
}
fn(1, 2);  // Uncaught ReferenceError: arguments is not defined           

複制

可以通過參數清單代替實作

var fn = (...args) => {
  console.log(args);
}
fn(1, 2);  // [1, 2]           

複制

注意: arguments在箭頭函數中,會跟随上下文綁定到上層,是以在不确定上下文綁定結果的情況下,盡可能不要在箭頭函數中使用arguments,而要使用…args。

多傳回值

方式一:使用對象作為傳回載體

Syntax: {arg1, arg2} = {arg1: value1, arg2: value2}

function test() {
    return {
        name: 'ligang',
        age: 27
    };
}
const {name, age} = test();
// const {age, name} = test();
console.log(name, age); // ligang 27           

複制

方式二:使用數組作為傳回載體

數組作為傳回載體與使用對象作為傳回載體差別是:數組需要讓被賦予的變量(或常量)名按照數組的順序擷取。

Syntax: [arg1, arg2] = [value1, value2]

function test() {
    return ["liang", 27];
}
const [name, age] = test();
console.log(name, age); // ligang 27           

複制

Syntax: [arg1, ,arg2] = [value1, value2, value3]

function test() {
    return ["liang", "male", 27];
}
const [name, ,age] = test();
console.log(name, age); // ligang 27           

複制

Syntax: [arg1, ...resetArgs] = [value1, value2, value3]

function test() {
    return ["liang", "male", 27];
}
const [name, ...others] = test();
console.log(name, others); // liang ["male", 27]           

複制