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>