ES6 Object.assign
1、基本用法
Object.assign
方法用來將源對象(source
)的全部可枚舉屬性,複製到目標對象(target
)。它至少須要兩個對象做爲參數,第一個參數是目標對象,後面的參數都是源對象。只要有一個參數不是對象,就會拋出TypeError錯誤。css
var target = { a: 1 }; var source1 = { b: 2 }; var source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
注:若是目標對象與源對象有同名屬性,或多個源對象有同名屬性,則後面的屬性會覆蓋前面的屬性。html
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}
若是隻有一個參數,Object.assign會直接返回該參數。html5
var obj = {a: 1}; Object.assign(obj) === obj // true
若是該參數不是對象,則會先轉成對象,而後返回。java
typeof Object.assign(2) // "object"
因爲undefined和null沒法轉成對象,因此若是它們做爲參數,就會報錯。node
Object.assign(undefined) // 報錯 Object.assign(null) // 報錯
若是非對象參數出如今源對象的位置(即非首參數),那麼處理規則有所不一樣。首先,這些參數都會轉成對象,若是沒法轉成對象,就會跳過。這意味着,若是undefined和null不在首參數,就不會報錯。其餘類型的值(即數值、字符串和布爾值)不在首參數,也不會報錯。可是,除了字符串會以數組形式,拷貝入目標對象,其餘值都不會產生效果。react
Object.assign
只拷貝自身屬性,不可枚舉的屬性(enumerable
爲false
)和繼承的屬性不會被拷貝。jquery
Object.assign({b: 'c'}, Object.defineProperty({}, 'invisible', { enumerable: false, value: 'hello' }) ) // { b: 'c' } Object.assign({b: 'c'}, Object.defineProperty({}, 'invisible', { enumerable: true, value: 'hello' }) ) // {b: "c", invisible: "hello"}
對於嵌套的對象,Object.assign
的處理方法是替換,而不是添加。git
var target = { a: { b: 'c', d: 'e' } } var source = { a: { b: 'hello' } } Object.assign(target, source) // { a: { b: 'hello' } }
上面代碼中,target對象的a屬性被source對象的a屬性整個替換掉了,而不會獲得{ a: { b: 'hello', d: 'e' } }的結果。這一般不是開發者想要的,須要特別當心。有一些函數庫提供Object.assign的定製版本(好比Lodash
的_.defaultsDeep
方法),能夠解決深拷貝的問題。程序員
注意,Object.assign
能夠用來處理數組,可是會把數組視爲對象。
Object.assign([1, 2, 3], [4, 5]) // [4, 5, 3]
其中,4覆蓋1,5覆蓋2,由於它們在數組的同一位置,因此就對應位置覆蓋了。
Object.assign方法實行的是淺拷貝,而不是深拷貝。也就是說,若是源對象某個屬性的值是對象,那麼目標對象拷貝獲得的是這個對象的引用。
var obj1 = {a: {b: 1}}; var obj2 = Object.assign({}, obj1); obj1.a.b = 2; obj2.a.b // 2
上面代碼中,源對象obj1的a屬性的值是一個對象,Object.assign拷貝獲得的是這個對象的引用。這個對象的任何變化,都會反映到目標對象上面。
2、用途
1. 爲對象添加屬性
class Point { constructor(x, y) { Object.assign(this, {x, y}); } }
這樣就給Point
類的對象實例添加了x、y屬性。
2. 爲對象添加方法
Object.assign(SomeClass.prototype, { someMethod(arg1, arg2) { ··· }, anotherMethod() { ··· } }); // 等同於下面的寫法 SomeClass.prototype.someMethod = function (arg1, arg2) { ··· }; SomeClass.prototype.anotherMethod = function () { ··· };
上面代碼使用了對象屬性的簡潔表示法,直接將兩個函數放在大括號中,再使用assign
方法添加到SomeClass.prototype
之中。
3. 克隆對象
function clone(origin) { return Object.assign({}, origin); }
上面代碼將原始對象拷貝到一個空對象,就獲得了原始對象的克隆。
不過,採用這種方法克隆,只能克隆原始對象自身的值,不能克隆它繼承的值。若是想要保持繼承鏈,能夠採用下面的代碼。
function clone(origin) { let originProto = Object.getPrototypeOf(origin); return Object.assign(Object.create(originProto), origin); }
在JS裏子類利用Object.getPrototypeOf
去調用父類方法,用來獲取對象的原型。用它能夠模仿Java
的super。
4. 合併多個對象
//多個對象合併到某個對象 const merge =(target, ...sources) => Object.assign(target, ...sources); //多個對象合併到新對象 const merge = (...sources) => Object.assign({}, ...sources);
5. 爲屬性指定默認值
const DEFAULTS = { logLevel: 0, outputFormat: 'html' }; function processContent(options) { let options = Object.assign({}, DEFAULTS, options); }
上面代碼中,DEFAULTS
對象是默認值,options
對象是用戶提供的參數。Object.assign
方法將DEFAULTS
和options
合併成一個新對象,若是二者有同名屬性,則option
的屬性值會覆蓋DEFAULTS
的屬性值。
注: 因爲存在深拷貝的問題,DEFAULTS
對象和options
對象的全部屬性的值,都只能是簡單類型,而不能指向另外一個對象。不然,將致使DEFAULTS
對象的該屬性不起做用。
3、瀏覽器支持
參考:
es6 javascript對象方法Object.assign()
ECMAScript 6 筆記(六)
編程風格
1. 塊級做用域
(1)let 取代 var
(2)全局常量和線程安全
在let
和const
之間,建議優先使用const
,尤爲是在全局環境,不該該設置變量,只應設置常量。
const
優於let
有幾個緣由。
一個是const
能夠提醒閱讀程序的人,這個變量不該該改變;
另外一個是const
比較符合函數式編程思想,運算不改變值,只是新建值,並且這樣也有利於未來的分佈式運算;
最後一個緣由是 JavaScript 編譯器會對const
進行優化,因此多使用const
,有利於提供程序的運行效率,也就是說let
和const
的本質區別,實際上是編譯器內部的處理不一樣。
// bad var a = 1, b = 2, c = 3; // good const a = 1; const b = 2; const c = 3; // best const [a, b, c] = [1, 2, 3];
2. 字符串
靜態字符串一概使用單引號或反引號,不使用雙引號。動態字符串使用反引號。
// bad const a = "foobar"; const b = 'foo' + a + 'bar'; // acceptable const c = `foobar`; // good const a = 'foobar'; const b = `foo${a}bar`; const c = 'foobar';
3. 解構賦值
使用數組成員對變量賦值時,優先使用解構賦值。
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
函數的參數若是是對象的成員,優先使用解構賦值。
// bad function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; } // good function getFullName(obj) { const { firstName, lastName } = obj; } // best function getFullName({ firstName, lastName }) { }
若是函數返回多個值,優先使用對象的解構賦值,而不是數組的解構賦值。這樣便於之後添加返回值,以及更改返回值的順序。
// bad function processInput(input) { return [left, right, top, bottom]; } // good function processInput(input) { return { left, right, top, bottom }; } const { left, right } = processInput(input);
4. 對象
單行定義的對象,最後一個成員不以逗號結尾。多行定義的對象,最後一個成員以逗號結尾。
// bad const a = { k1: v1, k2: v2, }; const b = { k1: v1, k2: v2 }; // good const a = { k1: v1, k2: v2 }; const b = { k1: v1, k2: v2, };
對象儘可能靜態化,一旦定義,就不得隨意添加新的屬性。若是添加屬性不可避免,要使用Object.assign
方法。
// bad const a = {}; a.x = 3; // if reshape unavoidable const a = {}; Object.assign(a, { x: 3 }); // good const a = { x: null }; a.x = 3;
對象的屬性和方法,儘可能採用簡潔表達法,這樣易於描述和書寫。
var ref = 'some value'; // bad const atom = { ref: ref, value: 1, addValue: function (value) { return atom.value + value; }, }; // good const atom = { ref, value: 1, addValue(value) { return atom.value + value; }, };
5. 數組
使用擴展運算符(...)拷貝數組。
// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
使用Array.from方法,將相似數組的對象轉爲數組。
const foo = document.querySelectorAll('.foo'); const nodes = Array.from(foo);
6. 函數
當即執行函數能夠寫成箭頭函數的形式。
(() => { console.log('Welcome to the Internet.'); })();
那些須要使用函數表達式的場合,儘可能用箭頭函數代替。由於這樣更簡潔,並且綁定了this。
// bad [1, 2, 3].map(function (x) { return x * x; }); // good [1, 2, 3].map((x) => { return x * x; }); // best [1, 2, 3].map(x => x * x);
簡單的、單行的、不會複用的函數,建議採用箭頭函數。若是函數體較爲複雜,行數較多,仍是應該採用傳統的函數寫法。
不要在函數體內使用arguments變量,使用rest運算符(...)代替。由於rest運算符顯式代表你想要獲取參數,並且arguments是一個相似數組的對象,而rest運算符能夠提供一個真正的數組。
// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
使用默認值語法設置函數參數的默認值。
// bad function handleThings(opts) { opts = opts || {}; } // good function handleThings(opts = {}) { // ... }
7. Map結構
只有模擬現實世界的實體對象時,才使用Object。若是隻是須要key: value
的數據結構,使用Map結構。由於Map有內建的遍歷機制。
let map = new Map(arr); for (let key of map.keys()) { console.log(key); } for (let value of map.values()) { console.log(value); } for (let item of map.entries()) { console.log(item[0], item[1]); }
8. Class
老是用Class,取代須要prototype的操做。由於Class的寫法更簡潔,更易於理解。
// bad function Queue(contents = []) { this._queue = [...contents]; } Queue.prototype.pop = function() { const value = this._queue[0]; this._queue.splice(0, 1); return value; } // good class Queue { constructor(contents = []) { this._queue = [...contents]; } pop() { const value = this._queue[0]; this._queue.splice(0, 1); return value; } }
使用extends
實現繼承,由於這樣更簡單,不會有破壞instanceof
運算的危險。
9. 模塊
使用import
取代require
。
// bad const moduleA = require('moduleA'); const func1 = moduleA.func1; const func2 = moduleA.func2; // good import { func1, func2 } from 'moduleA';
使用export
取代module.exports
。
// commonJS的寫法 var React = require('react'); var Breadcrumbs = React.createClass({ render() { return <nav />; } }); module.exports = Breadcrumbs; // ES6的寫法 import React from 'react'; const Breadcrumbs = React.createClass({ render() { return <nav />; } }); export default Breadcrumbs
若是模塊只有一個輸出值,就使用export default
,若是模塊有多個輸出值,就不使用export default
,不要export default
與普通的export
同時使用。
不要在模塊輸入中使用通配符。由於這樣能夠確保你的模塊之中,有一個默認輸出(export default)。
若是模塊默認輸出一個函數,函數名的首字母應該小寫。
若是模塊默認輸出一個對象,對象名的首字母應該大寫。
const StyleGuide = { es6: { } }; export default StyleGuide;
10. ESLint的使用
ESLint是一個語法規則和代碼風格的檢查工具,能夠用來保證寫出語法正確、風格統一的代碼。
首先,安裝ESLint。
$ npm i -g eslint
而後,安裝Airbnb語法規則。
$ npm i -g eslint-config-airbnb
最後,在項目的根目錄下新建一個.eslintrc
文件,配置ESLint。
{ "extends": "eslint-config-airbnb" }
如今就能夠檢查,當前項目的代碼是否符合預設的規則。
index.js
文件的代碼以下。
var unusued = 'I have no purpose!'; function greet() { var message = 'Hello, World!'; alert(message); } greet();
使用ESLint檢查這個文件。
$ eslint index.js index.js 1:5 error unusued is defined but never used no-unused-vars 4:5 error Expected indentation of 2 characters but found 4 indent 5:5 error Expected indentation of 2 characters but found 4 indent ✖ 3 problems (3 errors, 0 warnings)
上面代碼說明,原文件有三個錯誤,一個是定義了變量,卻沒有使用,另外兩個是行首縮進爲4個空格,而不是規定的2個空格。
ECMAScript 6 筆記(一)
1、ECMAScript 6簡介
1996年11月,JavaScript的創造者Netscape公司,決定將JavaScript提交給國際標準化組織ECMA,但願這種語言可以成爲國際標準。次年,ECMA發佈262號標準文件(ECMA-262)的初版,規定了瀏覽器腳本語言的標準,並將這種語言稱爲ECMAScript,這個版本就是1.0版。
該標準從一開始就是針對JavaScript語言制定的,可是之因此不叫JavaScript,有兩個緣由。一是商標,Java是Sun公司的商標,根據受權協議,只有Netscape公司能夠合法地使用JavaScript這個名字,且JavaScript自己也已經被Netscape公司註冊爲商標。二是想體現這門語言的制定者是ECMA,不是Netscape,這樣有利於保證這門語言的開放性和中立性。
ECMAScript和JavaScript的關係是,前者是後者的規格,後者是前者的一種實現(另外的ECMAScript方言還有Jscript和ActionScript)。平常場合,這兩個詞是能夠互換的。
2、let與做用域
1. let
ES6新增了let
命令,用來聲明變量。它的用法相似於var
,可是所聲明的變量,只在let
命令所在的代碼塊內有效。
{ let a = 10; var b = 1; } a // ReferenceError: a is not defined. b // 1
適用場景:for循環
不存在變量提高
let
不像var
那樣會發生「變量提高」現象。因此,變量必定要在聲明後使用,不然報錯。
// var 的狀況 console.log(foo); // 輸出undefined var foo = 2; // let 的狀況 console.log(bar); // 報錯ReferenceError let bar = 2;
變量foo
用var
命令聲明,會發生變量提高,即腳本開始運行時,變量foo
已經存在了,可是沒有值,因此會輸出undefined
。
變量bar
用let
命令聲明,不會發生變量提高。這表示在聲明它以前,變量bar
是不存在的,這時若是用到它,就會拋出一個錯誤。
暫時性死區
只要塊級做用域內存在let
命令,它所聲明的變量就「綁定」(binding)這個區域,再也不受外部的影響。
var tmp = 123; if (true) { tmp = 'abc'; // ReferenceError let tmp; }
存在全局變量tmp
,可是塊級做用域內let
又聲明瞭一個局部變量tmp
,致使後者綁定這個塊級做用域,因此在let
聲明變量前,對tmp
賦值會報錯。
若是區塊中存在let
和const
命令,這個區塊對這些命令聲明的變量,從一開始就造成了封閉做用域。凡是在聲明以前就使用這些變量,就會報錯。
若是一個變量聲明前使用會報錯
typeof x; // ReferenceError let x;
若是根本沒被聲明,爲undefined,反而不會報錯
typeof undeclared_variable // "undefined"
這樣的設計是爲了讓你們養成良好的編程習慣,變量必定要在聲明以後使用,不然就報錯。
暫時性死區的本質就是,只要一進入當前做用域,所要使用的變量就已經存在了,可是不可獲取,只有等到聲明變量的那一行代碼出現,才能夠獲取和使用該變量。
不容許重複聲明
let不容許在相同做用域內,重複聲明同一個變量。
2. 塊級做用域
function f1() { let n = 5; if (true) { let n = 10; } console.log(n); // 5 }
ES6容許塊級做用域的任意嵌套,內層做用域能夠定義外層做用域的同名變量。
塊級做用域的出現,實際上使得得到普遍應用的當即執行函數表達式(IIFE)再也不必要了。
// IIFE 寫法 (function () { var tmp = ...; ... }()); // 塊級做用域寫法 { let tmp = ...; ... }
塊級做用域與函數聲明
ES5規定,函數只能在頂層做用域和函數做用域之中聲明,不能在塊級做用域聲明。
// ES5嚴格模式 'use strict'; if (true) { function f() {} } // 報錯
ES6 引入了塊級做用域,明確容許在塊級做用域之中聲明函數。塊級做用域之中,函數聲明語句的行爲相似於let
,在塊級做用域以外不可引用。
function f() { console.log('I am outside!'); } (function () { function f() { console.log('I am inside!'); } if (false) { } f(); }());
上述代碼結果:
ES5:I am outside!
ES6: I am inside!
- 容許在塊級做用域內聲明函數。
- 函數聲明相似於
var
,即會提高到全局做用域或函數做用域的頭部。 - 同時,函數聲明還會提高到所在的塊級做用域的頭部。
注意,上面三條規則只對ES6的瀏覽器實現有效,其餘環境的實現不用遵照,仍是將塊級做用域的函數聲明看成let
處理。
考慮到環境致使的行爲差別太大,應該避免在塊級做用域內聲明函數。若是確實須要,也應該寫成函數表達式,而不是函數聲明語句。
// 函數聲明語句 { let a = 'secret'; function f() { return a; } } // 函數表達式 { let a = 'secret'; let f = function () { return a; }; }
ES6的塊級做用域容許聲明函數的規則,只在使用大括號的狀況下成立,若是沒有使用大括號,就會報錯。
do表達式
{ let t = f(); t = t * t + 1; }
上面代碼中,塊級做用域將兩個語句封裝在一塊兒。可是,在塊級做用域之外,沒有辦法獲得t
的值,由於塊級做用域不返回值,除非t
是全局變量。
在塊級做用域以前加上do
,使它變爲do
表達式。
let x = do { let t = f(); t * t + 1; };
上面代碼中,變量x
會獲得整個塊級做用域的返回值。
3. const命令
const
聲明一個只讀的常量。一旦聲明,常量的值就不能改變。
對於const
來講,只聲明不賦值,就會報錯。
const
的做用域與let
命令相同:只在聲明所在的塊級做用域內有效。
if (true) { const MAX = 5; } MAX // Uncaught ReferenceError: MAX is not defined
var message = "Hello!"; let age = 25; // 如下兩行都會報錯 const message = "Goodbye!"; const age = 30;
對於複合類型的變量,變量名不指向數據,而是指向數據所在的地址。const
命令只是保證變量名指向的地址不變
4. 頂層對象的屬性
頂層對象,在瀏覽器環境指的是window
對象,在Node指的是global
對象。
ES5之中,頂層對象的屬性與全局變量是等價的。
window.a = 1; a // 1 a = 2; window.a // 2
上面代碼中,頂層對象的屬性賦值與全局變量的賦值,是同一件事。
ES6:
一方面規定,爲了保持兼容性,var
命令和function
命令聲明的全局變量,依舊是頂層對象的屬性;
另外一方面規定,let
命令、const
命令、class
命令聲明的全局變量,不屬於頂層對象的屬性。
5. global對象
2、 變量的解構賦值
ES6容許按照必定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構(Destructuring)。
1. 數組的解構賦值
var a = 1; var b = 2; var c = 3; //ES6容許寫成下面這樣。 var [a, b, c] = [1, 2, 3];
若是解構不成功,變量的值就等於undefined
。
var [foo] = []; var [bar, foo] = [1];
以上兩種狀況都屬於解構不成功,foo
的值都會等於undefined
。
另外一種狀況是不徹底解構,即等號左邊的模式,只匹配一部分的等號右邊的數組。這種狀況下,解構依然能夠成功。
let [x, y] = [1, 2, 3]; x // 1 y // 2 let [a, [b], d] = [1, [2, 3], 4]; a // 1 b // 2 d // 4
若是等號的右邊不是數組(或者嚴格地說,不是可遍歷的結構,參見《Iterator》一章),那麼將會報錯。
默認值
解構賦值容許指定默認值
var [foo = true] = []; foo // true [x, y = 'b'] = ['a']; // x='a', y='b' [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
注意,ES6內部使用嚴格相等運算符(===
),判斷一個位置是否有值。因此,若是一個數組成員不嚴格等於undefined
,默認值是不會生效的。
var [x = 1] = [undefined]; x // 1 var [x = 1] = [null]; x // null
上面代碼中,若是一個數組成員是null
,默認值就不會生效,由於null
不嚴格等於undefined
。
若是默認值是一個表達式,那麼這個表達式是惰性求值的,即只有在用到的時候,纔會求值。
function f() { console.log('aaa'); } let [x = f()] = [1];
上面代碼中,由於x
能取到值,因此函數f
根本不會執行。上面的代碼其實等價於下面的代碼。
let x; if ([1][0] === undefined) { x = f(); } else { x = [1][0]; }
2. 對象的解構賦值
var { foo, bar } = { foo: "aaa", bar: "bbb" }; foo // "aaa" bar // "bbb"
var { baz } = { foo: "aaa", bar: "bbb" }; baz // undefined
對象的解構與數組有一個重要的不一樣。數組的元素是按次序排列的,變量的取值由它的位置決定;
而對象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。
對象的解構賦值的內部機制,是先找到同名屬性,而後再賦給對應的變量。真正被賦值的是後者,而不是前者。
對於let
和const
來講,變量不能從新聲明,因此一旦賦值的變量之前聲明過,就會報錯。
let foo; ({foo} = {foo: 1}); // 成功 let baz; ({bar: baz} = {bar: 1}); // 成功
上面代碼中,let
命令下面一行的圓括號是必須的,不然會報錯。由於解析器會將起首的大括號,理解成一個代碼塊,而不是賦值語句。
var node = { loc: { start: { line: 1, column: 5 } } }; var { loc: { start: { line }} } = node; line // 1 loc // error: loc is undefined start // error: start is undefined
上面代碼中,只有line
是變量,loc
和start
都是模式,不會被賦值。
對象的解構也能夠指定默認值。若是解構失敗,變量的值等於undefined
。若是解構模式是嵌套的對象,並且子對象所在的父屬性不存在,那麼將會報錯。
因爲數組本質是特殊的對象,所以能夠對數組進行對象屬性的解構。
var arr = [1, 2, 3]; var {0 : first, [arr.length - 1] : last} = arr; first // 1 last // 3
3. 字符串的解構賦
字符串被轉換成了一個相似數組的對象。
const [a, b, c, d, e] = 'hello'; a // "h" b // "e" c // "l" d // "l" e // "o"
相似數組的對象都有一個length
屬性,所以還能夠對這個屬性解構賦值。
let {length : len} = 'hello'; len // 5
4. 數值和布爾值的解構賦值
解構賦值時,若是等號右邊是數值和布爾值,則會先轉爲對象。
let {toString: s} = 123; s === Number.prototype.toString // true let {toString: s} = true; s === Boolean.prototype.toString // true
上面代碼中,數值和布爾值的包裝對象都有toString
屬性,所以變量s
都能取到值。
解構賦值的規則是,只要等號右邊的值不是對象,就先將其轉爲對象。因爲undefined
和null
沒法轉爲對象,因此對它們進行解構賦值,都會報錯。
5. 函數參數的解構賦值
function add([x, y]){ return x + y; } add([1, 2]); // 3
函數add
的參數表面上是一個數組,但在傳入參數的那一刻,數組參數就被解構成變量x
和y
。對於函數內部的代碼來講,它們能感覺到的參數就是x
和y
。
[[1, 2], [3, 4]].map(([a, b]) => a + b); // [ 3, 7 ]
function move({x = 0, y = 0} = {}) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, 0] move({}); // [0, 0] move(); // [0, 0]
function move({x, y} = { x: 0, y: 0 }) { return [x, y]; } move({x: 3, y: 8}); // [3, 8] move({x: 3}); // [3, undefined] move({}); // [undefined, undefined] move(); // [0, 0]
上面代碼是爲函數move
的參數指定默認值,而不是爲變量x
和y
指定默認值,因此會獲得與前一種寫法不一樣的結果。
undefined
就會觸發函數參數的默認值。
[1, undefined, 3].map((x = 'yes') => x); // [ 1, 'yes', 3 ]
只要有可能,就不要在模式中放置圓括號。
不能使用圓括號的狀況
(1)變量聲明語句中,不能帶有圓括號
(2)函數參數中,模式不能帶有圓括號。
(3)賦值語句中,不能將整個模式,或嵌套模式中的一層,放在圓括號之中。
// 所有報錯 var [(a)] = [1]; function f([(z)]) { return z; } ({ p: a }) = { p: 42 }; ([a]) = [5];
可使用圓括號的狀況只有一種:賦值語句的非模式部分,可使用圓括號。
[(b)] = [3]; // 正確 ({ p: (d) } = {}); // 正確 [(parseInt.prop)] = [3]; // 正確
面三行語句均可以正確執行,由於首先它們都是賦值語句,而不是聲明語句;其次它們的圓括號都不屬於模式的一部分。第一行語句中,模式是取數組的第一個成員,跟圓括號無關;第二行語句中,模式是p,而不是d;第三行語句與第一行語句的性質一致。
6. 用途
(1)交換變量的值
[x, y] = [y, x];
(2)從函數返回多個值
函數只能返回一個值,若是要返回多個值,只能將它們放在數組或對象裏返回。有了解構賦值,取出這些值就很是方便。
// 返回一個數組 function example() { return [1, 2, 3]; } var [a, b, c] = example(); // 返回一個對象 function example() { return { foo: 1, bar: 2 }; } var { foo, bar } = example();
(3)函數參數的定義
解構賦值能夠方便地將一組參數與變量名對應起來。
// 參數是一組有次序的值 function f([x, y, z]) { ... } f([1, 2, 3]); // 參數是一組無次序的值 function f({x, y, z}) { ... } f({z: 3, y: 2, x: 1});
(4)提取JSON數據
解構賦值對提取JSON對象中的數據,尤爲有用。
var jsonData = { id: 42, status: "OK", data: [867, 5309] }; let { id, status, data: number } = jsonData; console.log(id, status, number); // 42, "OK", [867, 5309]
(5)函數參數的默認值
jQuery.ajax = function (url, { async = true, beforeSend = function () {}, cache = true, complete = function () {}, crossDomain = false, global = true, // ... more config }) { // ... do stuff };
(6)遍歷Map結構
任何部署了Iterator接口的對象,均可以用for...of
循環遍歷。
在ES6中,有三類數據結構原生具有Iterator接口: 數組、某些相似數組的對象、Set和Map結構
,對象(Object)之因此沒有默認部署Iterator接口,是由於對象的哪一個屬性先遍歷,哪一個屬性後遍歷是不肯定的,須要開發者手動指定。
Iterator接口部署在對象的 Symbol.Iterator
屬性上, 能夠調用這個屬性,就獲得遍歷器對象。
var arr = ['a', 'b', 'c']; var iterator = arr[Symbol.iterator](); var a = iterator.next(); console.log(a) //{value: 'a', done: false}
for–of與for–in
for...in 遍歷每個屬性名稱,而 for...of遍歷每個屬性值。
在對象沒有部署Iterator接口的狀況下調用for…of會報錯。當一個部署了Iterator接口的對象調用for…of時,實現的步驟是這樣的:
-
調用對象的Symbol.Iterator的屬性得到遍歷器生成函數;
-
調用遍歷器生成函數返回遍歷器對象其實for…of就至關於一直調用遍歷器對象的next方法,直到返回done爲true;
Map結構原生支持Iterator接口,配合變量的解構賦值,獲取鍵名和鍵值就很是方便。
var map = new Map(); map.set('first', 'hello'); map.set('second', 'world'); for (let [key, value] of map) { console.log(key + " is " + value); } // first is hello // second is world
若是隻想獲取鍵名,或者只想獲取鍵值,能夠寫成下面這樣。
// 獲取鍵名 for (let [key] of map) { // ... } // 獲取鍵值 for (let [,value] of map) { // ... }
(7)輸入模塊的指定方法
加載模塊時,每每須要指定輸入那些方法。解構賦值使得輸入語句很是清晰。
const { SourceMapConsumer, SourceNode } = require("source-map");
電子書來源:阮一峯
react入門——慕課網筆記
1、 jsx
1. 被稱爲語法糖:糖衣語法,計算機語言中添加的某種語法,對語言的功能沒有影響,更方便程序員使用,增長程序的可讀性,下降出錯的可能性
相似的還有(coffeescript,typescript),最終都被解析爲js
2. 解析jsx的是jsxtransformer.js 指定jsx語法用<text/jsx>
3. 經過如下代碼渲染dom
1 React.render(<hello name=」world」/>, 2 Document.getElementbyId(「container」));
var hello = React.createClass({ render: function(){ return <div>hello {this.props.name}</div>; } }); React.render(<hello name="world"/>, document.getElementById("container'));
props是指屬性組,this是實例
2、 css
1. class
不能在標籤上直接寫class,須要改成className (因爲此處非真正的dom,class是關鍵字,不能解析)
var Hello = React.createClass({ render: function(){ return <div className="redfont">hello {this.props.name}</div>; } });
2. 內聯式
不能字符串來表示,須要用樣式對象來表示,樣式對象是以駝峯標示寫法,值爲樣式值
var Introduce = React.createClass({ render: function(){ return <div style={{fontSize:'44px'}}>{this.props.info}</div>; } });
{}中是執行表達式
{{}}內聯樣式寫法
駝峯表達式:
render: function(){ //定義樣式內容,樣式obj var styleObj = { color: 'red', fontSize:'32px' }; //className代替class return <div className="redfont" style={styleObj}>hello {this.props.name}</div>; }
3、React components生命週期
1. Mounted是:React Components被render解析生成對應的DOM節點並被插入瀏覽器的DOM結構的一個過程。
2. Update是:一個mounted的React Components被從新render的過程。
對比當前state變化
State
每個狀態react都封裝了對應的hook函數~鉤子
這種函數是Windows消息處理機制的一部分,經過設置「鉤子」,應用程序能夠在系統級對全部消息、事件進行過濾,訪問在正常狀況下沒法訪問的消息。
對事件進行hook後系統會受到相應通知
3.Unmounted是:一個mounted的React Components對應的DOM節點被從DOM結構中移除的這樣一個過程。
GetInitialstate
最終返回一個object其中包含其state
getInitialState:function(){ alert('init'); return { opacity:1.0 }; }
This
是伴隨函數生成時的函數內部實例對象
隨着函數運行在不一樣的環境發生變化
始終指的是調用函數的那個對象
-
- 當其出如今settimeout函數參數中時,因爲函數參數就是一個純粹的函數調用,不隸屬於其餘對象,隸屬於全局對象,屬於global
- 當其出如今setinistialstate這樣的函數體內,是做爲其所屬實例對象的方法來調用,此時this指component實例對象
- This出如今構造函數:
function test(){ this.x = 1; } var o = new test();
this 指新生成的對象
4. This出如今apply call bind等方法
做用函數的調用對象,指第一個參數
4、 React-component-listener
- Dom更新
傳統:直接修改dom的innerhtml或classname
事件綁定:Eventlistener
React:
給組件添加事件綁定(on駝峯式命名方式)
render: function (){
return(
<div>
<button onClick={this.handleClick}>顯示|隱藏</button>
<span ref="tip"> 點擊測試</span>
</div>
);
}
添加點擊事件:onClick={this.xxxxx}
與dom綁定不同,這裏不是真實的dom節點,大小寫敏感,經過對象屬性定義在對象實例上
var Btnclick = React.createClass({ handleClick: function(event){ },
Event對象是在js原生基礎上封裝的,所以同時具備原生event方法
2. 獲取組件
1)使用‘ref’ property標記組件
用ref屬性給子組件添加名字,經過this.refs能夠索引到子組件
render: function (){ return( <div> <button onClick={this.handleClick}>顯示|隱藏</button> <span ref="tip"> 點擊測試</span> </div> ); }
this.refs.tip
索引到的是react component而不是真實的dom節點
2)在dom裏得到這個節點:
使用react提供的方法:ReactDOM.findDOMNode(react component)
5、 補充
ajax
組件的數據來源,一般是經過 Ajax 請求從服務器獲取,可使用 componentDidMount
方法設置 Ajax 請求,等到請求成功,再用 this.setState
方法從新渲染 UI
1 var UserGist = React.createClass({ 2 getInitialState: function() { 3 return { 4 username: '', 5 lastGistUrl: '' 6 }; 7 }, 8 9 componentDidMount: function() { 10 $.get(this.props.source, function(result) { 11 var lastGist = result[0]; 12 if (this.isMounted()) { 13 this.setState({ 14 username: lastGist.owner.login, 15 lastGistUrl: lastGist.html_url 16 }); 17 } 18 }.bind(this)); 19 }, 20 21 render: function() { 22 return ( 23 <div> 24 {this.state.username}'s last gist is 25 <a href={this.state.lastGistUrl}>here</a>. 26 </div> 27 ); 28 } 29 }); 30 31 ReactDOM.render( 32 <UserGist source="https://api.github.com/users/octocat/gists" />, 33 document.body 34 );
上面代碼使用 jQuery 完成 Ajax 請求,這是爲了便於說明。React 自己沒有任何依賴,徹底能夠不用jQuery,而使用其餘庫。
6、 注意事項
1. 注意react更新後的變化
2. 返回虛擬dom時包裝爲一個div,保證返回一個結果
3. 組件的首字母必須大寫,否則不報錯也不顯示
4. this.refs.[refName]
屬性獲取的是真實 DOM ,因此必須等到虛擬 DOM 插入文檔之後,才能使用這個屬性,不然會報錯
5. this.props
和 this.state
都用於描述組件的特性,可能會產生混淆。一個簡單的區分方法是,this.props
表示那些一旦定義,就再也不改變的特性,而 this.state
是會隨着用戶互動而產生變化的特性。
6. 用戶在表單填入的內容,屬於用戶跟組件的互動,因此不能用 this.props
讀取,而要定義一個 onChange
事件的回調函數,經過 event.target.value
讀取用戶輸入的值。textarea
元素、select
元素、radio
元素都屬於這種狀況
7. 使用map遍歷時注意:
8. grunt build能夠用npm run list 代替
以上爲慕課網《react入門》總結,全部試驗代碼地址已上傳至git:https://github.com/chaoranwill/chaoran-home/tree/master/react/react-mytest 歡迎fork/clone
jquery中動態新增的元素節點沒法觸發事件解決辦法
好比作一個ajax讀取留言列表的時候,每條留言後面有個回覆按鈕,class爲「reply」,若是你用的是$(".reply").click(function(){ //do something... }),想必後面經過ajax加載進來的列表中的回覆按鈕,點擊事件會失效。
其實最簡單的方法就是直接在標籤中寫onclick="",可是這樣寫實際上是有點low的,最好的方式仍是經過給類名綁定一個click事件。
解決jquery中動態新增的元素節點沒法觸發事件的問題有兩種解決方法,以下:
方法一:使用live
live()函數會給被選的元素綁定上一個或者多個事件處理程序,而且規定當這些事件發生時運行的函數。經過live()函數適用於匹配選擇器的當前及將來的元素。好比,經過腳本動態建立的元素。
實現以下:
$('.liLabel').live('click', function(){ alert('OK'); });
方法二:使用on
能夠經過on方法綁定事件,能夠綁定到它的父級或者body中,實現以下:
$("#ulLabel").on('click','.liLabel',function(){ alert('OK') }); 或者: $("body").on('click','.liLabel',function(){ alert('OK') });
響應式圖像
將picture元素和srcset,sizes屬性歸入html5規範,新規範意在解決:
- 基於設備象素比(device-pixel-radio)選擇
- 基於viewport選擇
- 基於Art direction(美術設計)選擇
- 基於圖像格式選擇
1、固定寬度圖像:基於設備像素比選擇
srcset
屬性列出了瀏覽器能夠選擇加載的源圖像池,是一個由逗號分隔的列表。x
描述符表示圖像的設備像素比。瀏覽器根據運行環境,利用這些信息來選擇適當的圖像。不理解srcset
的瀏覽器會直接加載src
屬性中聲明的圖像。
<img srcset="crest-383.jpg 1.5x, crest-510.jpg 2x" src="crest-255.jpg" alt="USWNT crest" />
網站logo就是固定寬度圖像的一個例子,無論viewport的寬度如何,始終保持相同的寬度。
與內容相關的圖片,一般也須要響應式,它們的大小每每隨viewport改變。對於這類圖像,還有更好的處理方法。
2、可變寬度的圖像:基於viewport選擇
1. 對於可變寬度的圖像,咱們使用srcset
搭配w
描述符以及sizes
屬性 。w
描述符告訴瀏覽器列表中的每一個圖象的寬度。sizes
屬性是一個包含兩個值的,由逗號分隔的列表。根據最新規範,若是srcset
中任何圖像使用了w
描述符,那麼必需要設置sizes
屬性。
2. sizes
屬性有兩個值:第一個是媒體條件;第二個是源圖尺寸值,在特定媒體條件下,此值決定了圖片的寬度。須要注意是,源圖尺寸值不能使用百分比,vw
是惟一可用的CSS單位。
<img srcset="uswnt-480.jpg 480w, uswnt-640.jpg 640w, uswnt-960.jpg 960w, uswnt-1280.jpg 1280w" sizes="(max-width: 400px) 100vw, (max-width: 960px) 75vw, 640px" src="uswnt-640.jpg" alt="USWNT World Cup victory">
上例中,咱們告訴瀏覽器在viewport寬度小於400像素時,使圖像的寬度與viewport等寬。在viewport寬度小於960像素時,使圖像的寬度爲viewport寬度的75%。當viewport大於960像素時,使圖像的寬度爲640像素。
vm
當處理寬度的時候,%
單位更合適。處理高度的時候,vh
單位更好。
1. 佔滿寬度的元素: % > vw
正如我所提到的,vw
單位根據視窗的寬度決定它的大小。然而,瀏覽器是根據瀏覽器的窗口計算視窗大小的,包括了滾動條的空間。
若是頁面延伸超過視口的高度——滾動條出現——視窗的寬度將會大於html
元素的寬度。
所以,若是你將一個元素設置爲100vw
,這個元素將會延伸到html
和body
元素範圍以外。在這個例子中,我用紅色邊框包裹html
元素,而後給section
元素設置背景顏色。
由於這個細微的差異,當使一個元素橫跨整個頁面的寬度時,最好使用百分比單位而不是視口的寬度。
2. 佔滿高度的元素:vh > %
在另外一方面,當使一個元素跨越整個頁面的高度時,vh
遠比百分比單位好。
由於用百分比定義的元素的大小是由它的父元素決定的,只有父元素也填滿整個屏幕的高度時咱們才能擁有一個填滿整個屏幕的高度的元素。
然而,用vh
的話,就像下面寫的那麼簡單:
1
2
3
|
.example {
height
:
100
vh;
}
|
無論.example
元素如何嵌套,它仍是可以相對於視窗尺寸設置大小。滾動條的問題也不是一個問題,由於如今大多數頁面一般不會有水平滾動條。
vh應用
全屏背景圖片
vh
單位一個典型的用途是用來建立一個橫跨整個屏幕高度和寬度的背景圖片,無論設備的大小。這用vh
很容易實現:
.bg { position: relative; background: url('bg.jpg') center/cover; width: 100%; height: 100vh; }
佔滿全屏的內容塊像「多頁面」同樣
section { width: 100%; height: 100vh; }
咱們能夠用javascript來實現翻動頁面的錯覺。
$('nav').on('click', function() { if ( $(this).hasClass('down') ) { var movePos = $(window).scrollTop() + $(window).height(); } if ( $(this).hasClass('up') ) { var movePos = $(window).scrollTop() - $(window).height(); } $('html, body').animate({ scrollTop: movePos }, 1000); })
兼容性
若是您以爲閱讀本文對您有幫助,請點一下「推薦」按鈕,您的「推薦」將是我最大的寫做動力!歡迎各位轉載,可是未經做者本人贊成,轉載文章以後必須在文章頁面明顯位置給出做者和原文鏈接,不然保留追究法律責任的權利。
彈窗細節
1、 背景鎖定與滾動條引發的抖動問題
瀏覽網頁時常常會發現彈框出現後,滾動鼠標時,蒙版下面的頁面仍是能夠滾動的,其實這些滾動都是不必的,由於彈框的原意就是要聚焦用戶的注意力。
所以咱們要作的是 – 背景鎖定(從技術角度實際上是暫時性幹掉滾動條)。
技術原理:當Dialog彈框出現的時候,根元素overflow:hidden.
problem:此時,因爲頁面滾動條從有到無,頁面會晃動,這樣糟糕的體驗顯然是不能容忍了,因而,對<body>元素進行處理,右側增長一個滾動條寬度(假設寬度是widthScrollbar)的透明邊框。
$(document.body).css('border-right',widthScrollbar+'px solid transparent');
Dialog隱藏的時候再把滾動條放開。
2、避免彈框上再彈出彈框
要儘可能避免在彈框上再彈一層彈框,2層蒙版會讓用戶以爲負擔很重。能夠改用輕量彈框或從新把交互梳理。
微信瀏覽器——返回操做
微信的內置瀏覽器屏蔽了 相似 window.close() 這樣的操做
WeixinJSBridge.call('closeWindow')
能夠解決問題
Float 的那些事
css float
定義元素浮動到左側或者右側。其出現的本意是讓文字環繞圖片而已。
left、right、inherit(從父級元素獲取float值)、none
1、浮動的性質
1. 包裹性
display:inline-block某種意義上的做用就是包裹(wrap),而浮動也有相似的效果。舉個常見例子,或許您有實現寬度自適應按鈕的經驗,實現寬度自適應的關鍵就是要讓按鈕的大小自適應於文字的個數,這就須要按鈕要自動包裹在文字的外面。咱們用什麼方法實現呢?一就是display:inline-block;二就是float。
浮動屬性(不管是左浮動仍是右浮動)某種意義上而言與display:inline-block屬性的做用是如出一轍的
區別:浮動的方向性
display:inline-block僅僅一個水平排列方向,就是從左往右,而float能夠從右往左排列
2. 破壞性
2.1 float元素不佔據正常文檔流空間
因爲浮動塊不在文檔的普通流中,因此文檔的普通流中的塊表現得就像浮動塊不存在同樣。
3塊div均未加float
塊1享有浮動,脫離文檔流而且向右移動
塊1向左浮動。IE8和Firefox中由於它再也不處於文檔流中,因此它不佔據空間,實際上覆蓋住了塊2,使塊2從視圖中消失。而IE6和IE7中緊跟在浮動元素塊1的塊2也會跟着浮動。以下圖
2.2 浮動「塌陷」
對父元素的影響:若是父元素只包含浮動元素,且父元素未設置高度和寬度的時候。那麼它的高度就會塌縮爲零。
此類狀況出現緣由
浮動的「本職工做」:文字環繞顯示;「非本職工做」:列表佈局;證據:高度塌陷
因此浮動元素塌陷的問題根本就不是瀏覽器的bug,而是咱們沒有正確地深刻地瞭解浮動,是咱們本身使用不當,由於浮動本不該該用在這裏的。
解決方案
① 在使用float元素的父元素結束前加一個高爲0寬爲0且有clear:both樣式的div
<div> <div><span>塊1</span> float:left </div> <div><span>塊2</span> float:left</div> <div><span>塊3</span> float:left</div> <div></div> </div>
② 在使用float元素的父元素添加overflow:hidden;
③ 使用after僞對象清除浮動
3. float與JavaScript
使用JavaScript設置float不能使用 obj.style.float="left";
IE:
obj.style.styleFloat = "left";
其餘瀏覽器:
obj.style.cssFloat = "left";
Flex佈局
Flex是Flexible Box的縮寫,意爲"彈性佈局",用來爲盒狀模型提供最大的靈活性。
任何一個容器均可以指定爲Flex佈局。
.box{ display: flex; }
行內元素也可使用flex佈局
.box{ display: inline-flex; }
Webkit內核的瀏覽器,必須加上-webkit
前綴。
.box{ display: -webkit-flex; /* Safari */ display: flex; }
*注意,設爲Flex佈局之後,子元素的float
、clear
和vertical-align
屬性將失效
採用Flex佈局的元素,稱爲Flex容器(flex container),簡稱"容器"。它的全部子元素自動成爲容器成員,稱爲Flex項目(flex item),簡稱"項目"。
容器的屬性
如下6個屬性設置在容器上。
- flex-direction
- flex-wrap
- flex-flow
- justify-content
- align-items
- align-content
1 flex-direction屬性
flex-direction
屬性決定主軸的方向(即項目的排列方向)。
.box { flex-direction: row | row-reverse | column | column-reverse; }
它可能有4個值。
row
(默認值):主軸爲水平方向,起點在左端。row-reverse
:主軸爲水平方向,起點在右端。column
:主軸爲垂直方向,起點在上沿。column-reverse
:主軸爲垂直方向,起點在下沿。
2 flex-wrap屬性
默認狀況下,項目都排在一條線(又稱"軸線")上。flex-wrap
屬性定義,若是一條軸線排不下,如何換行。
.box{ flex-wrap: nowrap | wrap | wrap-reverse; }
(1)nowrap
(默認):不換行。
(2)wrap
:換行,第一行在上方。
(3)wrap-reverse
:換行,第一行在下方。
3 flex-flow
flex-flow
屬性是flex-direction
屬性和flex-wrap
屬性的簡寫形式,默認值爲row nowrap
。
.box { flex-flow: <flex-direction> || <flex-wrap>; }
4 justify-content屬性
justify-content
屬性定義了項目在主軸上的對齊方式。
.box { justify-content: flex-start | flex-end | center | space-between | space-around; }
它可能取5個值,具體對齊方式與軸的方向有關。下面假設主軸爲從左到右。
flex-start
(默認值):左對齊flex-end
:右對齊center
: 居中space-between
:兩端對齊,項目之間的間隔都相等。space-around
:每一個項目兩側的間隔相等。因此,項目之間的間隔比項目與邊框的間隔大一倍。
5 align-items屬性
align-items
屬性定義項目在交叉軸上如何對齊。
.box { align-items: flex-start | flex-end | center | baseline | stretch; }
它可能取5個值。具體的對齊方式與交叉軸的方向有關,下面假設交叉軸從上到下。
flex-start
:交叉軸的起點對齊。flex-end
:交叉軸的終點對齊。center
:交叉軸的中點對齊。baseline
: 項目的第一行文字的基線對齊。stretch
(默認值):若是項目未設置高度或設爲auto,將佔滿整個容器的高度。
6 align-content屬性
align-content
屬性定義了多根軸線的對齊方式。若是項目只有一根軸線,該屬性不起做用。
.box { align-content: flex-start | flex-end | center | space-between | space-around | stretch; }
該屬性可能取6個值。
flex-start
:與交叉軸的起點對齊。flex-end
:與交叉軸的終點對齊。center
:與交叉軸的中點對齊。space-between
:與交叉軸兩端對齊,軸線之間的間隔平均分佈。space-around
:每根軸線兩側的間隔都相等。因此,軸線之間的間隔比軸線與邊框的間隔大一倍。stretch
(默認值):軸線佔滿整個交叉軸。
項目的屬性
如下6個屬性設置在項目上。
order
flex-grow
flex-shrink
flex-basis
flex
align-self
1 order屬性
order
屬性定義項目的排列順序。數值越小,排列越靠前,默認爲0。
.item { order: <integer>; }
2 flex-grow屬性
flex-grow
屬性定義項目的放大比例,默認爲0
,即若是存在剩餘空間,也不放大。
.item { flex-grow: <number>; /* default 0 */ }
若是全部項目的flex-grow
屬性都爲1,則它們將等分剩餘空間(若是有的話)。若是一個項目的flex-grow
屬性爲2,其餘項目都爲1,則前者佔據的剩餘空間將比其餘項多一倍。
3 flex-shrink屬性
flex-shrink
屬性定義了項目的縮小比例,默認爲1,即若是空間不足,該項目將縮小。
.item { flex-shrink: <number>; /* default 1 */ }
若是全部項目的flex-shrink
屬性都爲1,當空間不足時,都將等比例縮小。若是一個項目的flex-shrink
屬性爲0,其餘項目都爲1,則空間不足時,前者不縮小。
4 flex-basis屬性
flex-basis
屬性定義了在分配多餘空間以前,項目佔據的主軸空間(main size)。瀏覽器根據這個屬性,計算主軸是否有多餘空間。它的默認值爲auto
,即項目的原本大小。
.item { flex-basis: <length> | auto; /* default auto */ }
它能夠設爲跟width
或height
屬性同樣的值(好比350px),則項目將佔據固定空間。
5 flex屬性
flex
屬性是flex-grow
, flex-shrink
和 flex-basis
的簡寫,默認值爲0 1 auto
。後兩個屬性可選。
6 align-self屬性
align-self
屬性容許單個項目有與其餘項目不同的對齊方式,可覆蓋align-items
屬性。默認值爲auto
,表示繼承父元素的align-items
屬性,若是沒有父元素,則等同於stretch
。
HTML5 data-* 自定義屬性
在HTML5中添加了data-*的方式來自定義屬性,所謂data-*實際上上就是data-前綴加上自定義的屬性名,使用這樣的結構能夠進行數據存放。使用data-*能夠解決自定義屬性混亂無管理的現狀。
1. 讀寫方式
<div id="test" data-age="24"> Click Here </div>
其中的data-age就是一種自定義屬性,固然咱們也能夠經過JavaScript來對其進行操做,HTML5中元素都會有一個dataset的屬性,這是一個DOMStringMap類型的鍵值對集合
var test = document.getElementById('test'); test.dataset.my = 'Byron';
*使用JavaScript操做dataset有兩個須要注意的地方
(1) 咱們在添加或讀取屬性的時候須要去掉前綴data-*,像上面的例子咱們沒有使用test.dataset.data-my = 'Byron';的形式。
(2) 若是屬性名稱中還包含連字符(-),須要轉成駝峯命名方式,但若是在CSS中使用選擇器,咱們須要使用連字符格式
如:
<style type="text/css"> [data-birth-date] { background-color: #0f0; width:100px; margin:20px; } </style>
test.dataset.birthDate = '19890615';
這樣咱們經過JavaScript設置了data-birth-date自定義屬性,在CSS樣式表爲div添加了一些樣式
讀取的時候也是經過dataset對象,使用」.」來獲取屬性,一樣須要去掉data-前綴,連字符須要轉化爲駝峯命名
如:
var test = document.getElementById('test'); test.dataset.my = 'Byron'; test.dataset.birthDate = '19890615'; test.onclick = function () { alert(this.dataset.my + ' ' + this.dataset.age+' '+this.dataset.birthDate); }
*getAttribute/setAttribute能夠操做全部的dataset內容,dataset內容只是attribute的一個子集,特殊就特殊在命名上了,可是dataset內只有帶有data-前綴的屬性
那麼爲何咱們還要用data-*呢,一個最大的好處是咱們能夠把全部自定義屬性在dataset對象中統一管理,遍歷啊神馬的都哦很方便,而不至於零零散散了,因此用用仍是不錯的。
2. 瀏覽器兼容性
- Internet Explorer 11+
- Chrome 8+
- Firefox 6.0+
- Opera 11.10+
- Safari 6+
轉自這裏
參數傳遞的四種形式----- URL,超連接,js,form表單
4種get傳參方式
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script type="text/javascript"> function Go() { window.location.href="localhost:21811/Handler1.ashx?id=1&name='abc'" } </script> </head> <body> <!--//參數傳遞的幾種形式--> <!--第一種:直接在URL後面加參數:--> localhost:21811/Handler1.ashx?id=1&name="abc" <!--第二種:用超連接的方法傳遞參數:當點擊超連接的時候,首先會跳轉到localhost:21811/Handler1.ashx頁面,而後還會傳遞id 和name 兩個參數過去--> <a href="localhost:21811/Handler1.ashx?id=1&name='abc'">超連接傳遞參數</a></body> <!--第三種:經過js方法傳遞:用戶點擊這個button按鈕,觸發onClick事件,執行Go()方法,跳轉到localhost:21811/Handler1.ashx頁面,同時傳遞了id,和name兩個參數過去--> <input type="button" onclick="Go()" value="經過js方法傳遞參數" /> <!--第四種:經過form表單傳遞--> <form action="Handler1.ashx" method="get"><!--注意action裏面的鏈接不能帶參數的-->> <input type="text" name="id" value="3" /> <input type="text" name="name" value="abc" /> <input type="submit" value="經過傳遞參數" /> </form> </body> </html>