取顶层对象
同一段代码为了能够在各种环境, 都能取到顶层对象, 现在一般是使用this变量,但是有局限性
全局环境中,this会返回顶层对象。 但是,Node 模块和 ES6 模块中,this返回的是当前模块,严格模式下,这时this会返回undefined。 不管是严格模式,还是普通模式,new Function('return this')(),总是会返回全局对象。
但是,如果浏览器用了 CSP(Content Security Policy,内容安全政策),那么eval、new Function这些方法都可能无法使用。 在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。
// 方法一 (typeof window !== 'undefined' ? window : (typeof process === 'object' && typeof require === 'function' && typeof global === 'object') ? global : this); // 方法二 var getGlobal = function () { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof global !== 'undefined') { return global; } throw new Error('unable to locate global object'); };
垫片库system.global模拟了这个提案,可以在所有环境拿到global。
// CommonJS 的写法 require('system.global/shim')(); // ES6 模块的写法 import shim from 'system.global/shim'; shim(); 上面代码可以保证各种环境里面,global对象都是存在的。 // CommonJS 的写法 var global = require('system.global')(); // ES6 模块的写法 import getGlobal from 'system.global'; const global = getGlobal();
let
1.let 不能预解析 ( 只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。)
2.同作用域内 let声明的变量 不允许重复
3.有块级作用域{ ... } 内部定义变量 外部不能访问
4.只能先声明在使用
const
let 4条规则都适用
声明的常量不允许重新赋值
2.常量必须初始化
const a; //报错 const a ={ }
3.可以改变引用类
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。 const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。
数组解构赋值
let [a, b, c] = [1, 2, 3]; //上面代码表示,可以从数组中提取值,按照对应位置,对变量赋值。 let [foo, [[bar], baz]] = [1, [[2], 3]]; foo // 1 bar // 2 baz // 3 let [ , , third] = ["foo", "bar", "baz"]; third // "baz" let [x, , y] = [1, 2, 3]; x // 1 y // 3 let [head, ...tail] = [1, 2, 3, 4]; head // 1 tail // [2, 3, 4] let [x, y, ...z] = ['a']; x // "a" y // undefined z // [] let [x = 1] = [undefined]; x // 1 let [x = 1] = [null]; x // null
上面代码中,如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined。
对象解构赋值
let {foo:aa,bar="hi"} = { foo:"123"} console.log(foo)//报错 console.log(aa)123 console.log(bar )//hi
foo
是匹配的模式,baz
才是变量。真正被赋值的是变量baz
,而不是模式foo
。
如果p
也要作为变量赋值,可以写成下面这样。
let obj = { p: [ 'Hello', { y: 'World' } ] }; let { p, p: [x, { y }] } = obj; x // "Hello" y // "World" p // ["Hello", {y: "World"}]
字符串扩展
let str = 'Hello Brother!'; //includes 是否包含参数字符串 str.includes('Br'); //true //startsWith 开头是否存在参数字符串 str.startsWith('Hello') //true //endsWith 结尾是否存在参数字符串 str.endsWith('er!')//true
re.repeat(2); //"Hello Brother!Hello Brother!" re.repeat(-2); // Invalid count value re.repeat(Infinity); // Invalid count value //小数会取整 re.repeat(1.9) // "Hello Brother!" re.repeat(-0.9) // ""
//补全开头 padStart 补齐尾部 padEnd let pd = 'Brother!'; pd.padStart(14,'Hello '); //"Hello Brother!" //第一个参数为补齐的最大长度(整串字符) 第二个参数为补齐缺省的字符串 //如果原始字符长度大于等于最大长度,返回原字符串 pd.padStart(7,'Hello ')// 'Brother!' pd.padStart(8,'Hello ')// 'Brother!' //如果最大长度小于补齐长度,则去除超出部分 pd.padStart(9,'Aay ')//'ABrother!' //如果缺省第二个参数则 默认使用空格补齐 pd.padStart(9)//' Brother!'
//以 x 开头,会被当做 16 进制 `\x23` // # //以 u 开头,会被当做 unicode 字符 `\u004F` //"O" //如果无法编译将会报错
模板字符串
let obj={ name:"ww", age:"18" } let tag = "<div><span>"+obj.name +"</span></div>"; let tpl= `<div><span>${obj.name}</span></div>` // 反引号 左上角 ESC键下方 let fn= function (info){ return info } let tpl= `<div><span>${obj.name}</span></div> <div><span>${obj.age}</span></div> <div> <span>${fn("你好")}</span> <span>${1+1}</span> </div>
函数参数解构赋值
一,
function fn(param="ss",age=15){ console.log(param - age); } fn();//ss - 15 fn("nihao",18)//nihao - 18
二,
function fn({name ="ls", age}={}) { console.log(name - age); } fn();//ls - undefind
fn("nihao",18)//nihao - 18
三, rest 参数(... 剩余参数)
function fn (a,...arg){ return arg; } fn(0,2,3,4,5)//[2,3,4,5] function foo (a,...arg,b){ return arg; } //ught SyntaxError: Rest parameter must be last formal parameter
/ 报错 function f(a, b = a) { 'use strict'; // code } // 报错 const foo = function ({a, b}) { 'use strict'; // code }; // 报错 const fn = (...a) => { 'use strict'; // code }; const obj = { // 报错 fn({a, b}) { 'use strict'; // code } };
函数扩展
const fn = (x, y = 'Owen') =>( console.log(x,y)); fn(1) // 1 "Owen" //默认参数 惰性求值 let x = 99; function foo(y = x + 1) { console.log(y); } foo() // 100 x = 100; foo() // 101 //调用一次计算一次
// 默认参数最好定义再尾部,因为使用形参默认参数,那么那个位置的形参必传 function f(x, y = 5, z, ...arg) { return [x, y, z]; } f() // [undefined, 5, undefined] f(1) // [1, 5, undefined] f(1, ,2) // 报错 f(1, undefined, 2) // [1, 5, 2] //length 不包含设置默认值 和后面的形参 的个数, f().length // 1
//函数变量无法访问默认值 function f(y = x) { let x = 2; console.log(y); } f() // ReferenceError: x is not defined //函数中的形参名不能和默认名一样 //参数x = x形成一个单独作用域。实际执行的是let x = x,由于暂时性死区的原因,这行代码会报错 function f(x = x) { console.log(x); } f()// x is not defined var x = 1; function foo(x, y = function() { x = 2; }) { var x = 3; y(); console.log(x); } foo() // 3 x // 1
let fn = () =>console.log(this); let obj = {name:"Owen"}; fn.call(obj) //window fn.bind(obj) fn() //window fn.apply(obj) //window //可以通过改变宿主环境来改变 this 指向 function foo (){ return () =>{ console.log(this); return ()=> {console.log(this)}; } } foo.call(obj)() //{name: "Owen"} foo.call(obj)()() //{name: "Owen"} {name: "Owen"}
//定义简单函数 let fn = () => 'Owen'; fn()// 'Owen' let foo = r => r; foo('Owen') // 'Owen' let f = (num1,num2) => num1 + num2; f(1,2)//3 //如果返回一个对象需要小括号包裹,f否则会报错 let f = (name,age) => ({name,age}); f('Owen',18)//{name: "Owen", age: 18} //如果代码部分大于一条语句,那么需要 大括号包裹,使用return 返回值 let fn1 = r => { let a = 1; console.log(a); return r + a; }
不推荐使用场景
var obj = { gender:"man", getSex: () => {console.log(this.gender)} } obj.getSex() //undefined //this -> global