属性私有化,数据保护javascript
let _gender = Symbol('gender') function Person(name, gender) { this.name = name; this[_gender] = gender } Person.prototype.say = function () { console.log(this[_gender]); } p1.say()
不支持变量声明预解析(先声明后使用)html
支持块做用域前端
不容许重复声明(暂存死区)java
定义的变量不会给window增长属性node
let c; "c" in window //false
chrome
不支持变量声明预解析(先声明后使用)数组
支持块做用域promise
不容许重复声明(暂存死区)缓存
常量(值一旦肯定,不容许修改,全部必须初始化)数据结构
<button class="active">选项一</button> <button>选项二</button> <button>选项三</button> <p class="active">内容一</p> <p>内容二</p> <p>内容三</p> <script> var buttons = document.querySelectorAll('button') var ps = document.querySelectorAll('p') for (let i = 0; i < buttons.length; i++) { buttons[i].onclick = function () { for (let i = 0; i < buttons.length; i++) { buttons[i].className = ''; ps[i].className = ''; } this.className = 'active'; ps[i].className = 'active'; } } <script>
解构赋值
let [a,b,c]=[1,2,3] let {left:L,top:T}={left:100,top:200} let [a]='miaov'
扩展运算符
... let a = [1, 2, 3, 4]; console.log(...a); console.log(Math.max(...a)); let b = ['a', 'c', 'v']; console.log([...a, 'skd', ...b]); let obj1 = {left: 100, right: 200}; let obj2 = {top: 200, height: 200} let obj3 = { ...obj1, ...obj2 }; console.log(obj3);
字符串扩展
\u{1F602} unicode 表示法
``
${表达式}
进制
二进制 0b
八进制 0o(ES6以前:0开头表示八进制)
十进制 非0开头
十六进制 0x
迭代
for... in: 以原始插入的顺序迭代对象的可枚举属性
for... of 根据迭代对象的迭代器具体实现迭代对象数据
let arr = ['a', 'b', 'c']; for (let string of arr) { console.log(string); }
箭头函数
//当参数只有一个的时候小括号能够省略 let fn = (x) => { console.log('fn1') }; let fn = x => { console.log('fn1') }; //若是多于1条语句,或者返回的是一个对象 let fn = x => { return { x: 1, y: 2 } }; 箭头函数的this在函数建立件就绑定好了,箭头函数的this指向建立该做用域的对象 箭头函数的注意事项 内部this对象指向建立上下文对象 不能做用构造函数 没有arguments 不能做为生成器函数 let obj8={ name:'zfpx', getName:()=>{ console.log(this.name); }, }; console.log(obj8.getName());// undefined //箭头函数的this是定死的,指向外层的this
类
class Person { //类 constructor(name) {//构造函数: 对象初始化的时候执行的函数 this.name = name } getName() { console.log(this); } } // 继承 class Student extends Person { constructor(name, type) { //super super(name); //若是子类须要有本身的初始化过程, // 有本身的constructor函数,须要在子类调用父类的构造函数 this.type = type; } }
promise
避免回调地狱(就是回调嵌套回调无限嵌套) 接受一个参数:callback,咱们把要执行的异步任务放置在这个callback中 Promise对象内部会维护一个状态 默认是:pending 成功:resolved 失败:rejected Promise对象下有一个方法:then,该方法在Promise对象的状态发生改变的时候触发then的回调 catch let p1 = new Promise((resolove, reject) => { setTimeout(function () { resolove(2) }, Math.random() * 1000) }) let p2 = new Promise((resolove, reject) => { setTimeout(function () { resolove(3) }, Math.random() * 1000) }) Promise.all([p1, p2]).then(data => { console.log(data); }, err => { console.log(err); })
迭代器
yield* 后面跟的是可遍历的结构,它会调用该结构的遍历器接口 function* fn() { console.log(0); yield console.log(1); yield* [1,3,4]; yield console.log(2); } //返回一个迭代器函数 let f = fn(); f.next() f.next()
代码规范(这一大推写着写着就变成这样了)
在let和const之间优先使用const 尽管const声明的变量不能直接修改值,可是对于对象和数组,倒是不受保护能够修改的 静态代码一概使用单引号或者反引号 解构 const [a,b]=1,2 cosnt {first,last}=obj 对象 单行定义的对象最后不以逗号结尾 多行定义的对象最后以逗号结尾 const a = { k1: v1, k2: v2 }; const b = { k1: v1, k2: v2, }; 对象尽可能静态化 cosnt a={x:null} a.x=3 对象的属性和方法简写 // 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; }, }; 数组 const itemsCopy=[...items] Array.from方法 将相似数组的对象转为数组 const foo = document.querySelectorAll('.foo'); const nodes = Array.from(foo); 箭头函数 [1,2,3].map((x)=>{ return x*x }) 能够指定原型 cosnt anObject={y:'y'} const x={ __proto__:anObject } super() const anObject = {y: 'y', test: () => 'zoo'}; const x = { __proto__: anObject, test() { return super.test() + 'x' } }; console.log(x.test()); 动态属性 const x = { ['a' + '_' + 'b']: 'z' } x.a_b //z reduce 有点难理解 第三个参数能够是索引,默认给值,能够给{} ,[] JSON.stringfiy('第一个参数是序列化的参数', '第二个参数是一个函数key,value操做', '让代码清晰些4至关于4个空格') JSON.parse() 同样也具备这个特色 //indexOf 若是找不到返回-1 若是重复返回第一个的索引 箭头函数 let getTempItem = id => ({ id: id, name: "Temp" });//若是不加括号会报错 若是不须要返回值 void let fn = () => void console.log(2); 箭头函数注意点 函数体内的this对象,就是定义时所在的对象,而不是使用所在的对象 不能够看成构造函数,就是说不能new 箭头函数没有本身的做用域 不可使用arguments 不可使用yield 也就是说,this对象的指向是可变的,可是在箭头函数中,this的指向是固定的 由于箭头函数没有this ,若是真的须要this须要重写定义this function foo() { var _this = this; setTimeout(function () { console.log('id:', _this.id); }, 100); } 箭头函数里面根本没有本身的this,而是应用外层的this 箭头函数是的this从动态变成静态,全部须要引用动态this的时候不要使用箭头函数 Array.from 能够将各类值转为真正的数组,而且还提供map功能 Array.from({ length: 2 }, () => 'jack') //[ 'jack', 'jack' ] Array.of 用于将一组值,转换为数组 Array.of(3, 11, 8) // [3,11,8] 好比 Array(3)//[,,,] 一个值得时候表示的是数组的长度 Array.of 至关于 [].slice.call(arguments) n**m 指数运算符 双冒号运算符 取代call apply bind f::b 等同于 b.bind(f); b.apply(f,arguments); find 找到第一个复合条件的数组,参数是一个回调函数,返回第一个返回值为true的成员 [1,2,3,4,5,6].find(a=>a>3) //4 entries() Object.keys() Object.values() entries() 对键值对遍历 keys() 对键名遍历 values() 对键值遍历 includes 用于表示数组是否包含特定的值 第二个参数是起始位置默认为0 [1,3,4].includes(3,2) //false 对象的扩展 const rest = (a, b) => ({a, b}); console.log(rest('张三', '李四')); // { a: '张三', b: '李四' } let a = { fun () { return 'leo'; } } // 等同于 let a = { fun : function(){ return 'leo'; } } Object.assign() 深拷贝须要使用其余方法,由于Object.assign() 拷贝的是属性值, 假如原对象的属性值是一个指向对象的引用,它也只拷贝那个引用值 let obj1 = { a: 0 , b: { c: 0}}; let obj2 = Object.assign({}, obj1); console.log(JSON.stringify(obj2)); // { a: 0, b: { c: 0}} 合并对象,合并属性的时候后续参数中具备相同属性的覆盖 var o1 = { a: 1 }; var o2 = { b: 2 }; var o3 = { c: 3 }; var obj = Object.assign(o1, o2, o3); console.log(obj); // { a: 1, b: 2, c: 3 } Set 数据结构 全部成员惟一性 add 添加新成员 size 成员总数 delete has clear Map 提供了"值-值"的对应关系,是一种更完善的hash结构实现 set get size has delete clear for... of 当遇到next返回值得done属性为true就会终止,return 返回的不包括在for...of 循环中 function * f(){ yield 1; yield 2; yield 3; yield 4; return 5; } for (let k of f()){ console.log(k); } // 1 2 3 4 没有 5 当变量值为null时,布尔值环境为false ,值类型为0 当变量值为undefined,布尔值环境为false,值类型为NaN ES6开始所有变量和顶层对象(window)的属性是分开的 let b = 'leo'; window.b; // undefined 字面量 简单理解就是变量赋值是右边的都是字面量 let a='hi len' `hi len` 为字符串字面量 a为变量名 var n=1;//字面量建立方式 var num=new Number(1); //构造函数建立方式 闭包 闭包的函数继承了父级容器的参数和变量,内部函数包含外部函数的做用域 内容函数只能在外部函数中访问 内部函数造成闭包:能够访问外部函数的参数和变量, 但外部函数却不能使用这个内部函数的参数和变量 外部函数的返回值为内部函数名 function f(a) { function g(b){ return a + b; } return g; } //默认参数 剩余参数 function f(a,b=1,...c) { } Proxy???
正则 gi g全局i区分大小写 exec 注意分组的参数 若检索成功,返回匹配的数组,不然返回null let result = /len/g.exec('hello len!!'); //[ 'len', index: 6, input: 'hello len!!' ] test 若匹配成功返回true不然返回false let str = "hello leo!"; let res = /leo/.test(str); // true search 若检索成功,返回第一个与正则对象匹配的字符串的起始位置,不然返回-1 let str = "hello leo!"; let res = str.search(/leo/g); // 6 match 若检索成功,返回与reg匹配的全部结果的一个数组,不然返回null str.match(regSS)
Object.defineProperty
定义新属性或者修改原有的属性 let obj={ test: 'hello' }; //对象已有的属性添加特性 Object.defineProperty(obj,'test',{ value:"张三", writable:true,//属性的值是否能够被重写,设置为true能够被重写 enumerable:false,//属性是否能够被枚举(for...in或者object.keys()) configurable:true, //目标属性是否可使用delete删除,目标属性是否能够再次设置特性 }); //定义的新属性,特性中configurable,enumerable,writable都为默认的false //当使用get或者set方法,不容许使用writable和value这两个属性 var obj = {}; Object.defineProperty(obj,"newKey",{ get:function (){} | undefined, set:function (value){} | undefined, configurable: true | false, enumerable: true | false, }); //getter 得到属性值的方法,setter设置属性值的方法 //get或者set不是必须成对出现的,任写一个就能够
this的调用
var f = function () { console.log(this.x); } var x = 1; var obj = { f: f, x: 2, }; // 单独执行 f() // 1 // obj 环境执行 obj.f() // 2
hasOwnProperty函数 为了判断一个对象是否包含自定义属性而不是原型链上的属性 惟一一个处理属性可是一查找原型链上的函数 使用外部的hasOwnProperty函数获取正确的结果 Object.hasOwnProperty.call(foo,'bar')//指向的对象,属性->返回true,false this是基于原型赖以生存的土壤
let obj1={name:'张三', age: 4}; let {name:myname,age:myage}=obj1; // let myname=obj1.name // let myage=obj1.age console.log(myname); //默认解构 let obj2={name:'zfpx', age: 9}; let {name,age=8}=obj2; console.log(name, age);
function replaces(dec) { return dec.replace(/\$\{([^}]+)\}/g,function (arguments,key) { console.log(arguments); console.log(eval(key)); }) } eval() 能够执行一段javascript 语句 var str = "if (x == 5) {alert('z is 42'); z = 42;} else z = 0; "; var str1="1+4"; 返回值是最后的结果
对于基本类型进行赋值操做,两个变量互不影响 let a='alex'; let b=a; a='alex02'; console.log(a);//alex02 console.log(b);//alex //对于引用类型 let a = { name: "muyiy", book: { title: "You Don't Know JS", price: "45" } } let b = a; b.name="张三"; 浅拷贝 * object.assign() //若是说它是深拷贝是不许确的 用于将全部可枚举属性的值从一个或者多个源对象赋值到目标对象 let a = { name: "muyiy", book: { title: "You Don't Know JS", price: "45" } } let b = Object.assign({}, a); console.log(b); * 展开语法 ... * Array.prototype.slice() let a = [0, "1", [2, 3]]; let b = a.slice(1); console.log(b); // ["1", [2, 3]] a[1] = "99"; a[2][0] = 4; console.log(a); // [0, "99", [4, 3]] console.log(b); // ["1", [4, 3]] 浅拷贝:第一层为基础数据类型不会是原数据一同改变, 可是原数据子对象会发现改变 深拷贝 JSON.stringify() JSON.parse() 都不会发生改变 在遇到函数、 undefined 或者 symbol 的时候,该对象也不能正常的序列化 let a = { age: undefined, sex: Symbol('male'), jobs: function() {}, name: 'yck' } let b = JSON.parse(JSON.stringify(a)) console.log(b) // {name: "yck"} 你会发如今上述状况中,该方法会忽略掉函数和 undefined和symbol 可使用lodash中的cloneDeep或者使用30s中的deepClone
* 访问构造函数里的属性 * 访问到原型里的属性 注意 不能使用new Symbol();由于Symbol是基本数据类型,每一个Symbol()返回的symbol值都是惟一的 第一种状况 实例中只能返回返回对象中的属性 function Car(color, name) { this.color = color; return { name: name } } var car = new Car("black", "BMW"); car.color; // undefined 第二种状况 没有return 返回undefined 且 实例只能访问构造函数中的属性 function Car(color, name) { this.color = color; } var car = new Car("black", "BMW"); car.color; // black car.name; // undefined 总结 * 建立了一个全新的对象 * 这个对象会被执行__proto__连接 * 生成的新对象会绑定到函数调用的this * 经过new 建立的每一个对象将最终被__proto__ 连接到这个函数的prototype对象上
函数柯里化 多个参数的函数换成接受一个单一参数 用闭包把参数保存起来,当参数的数量足够执行函数了,就开始执行函数 let curry=(fn,...args)=>{ fn.length <= args.length ? fn(...args) : curry.bind(null, fn, ...args); }; function sum() { if (arguments.length === 1) { let sum01=arguments[0]; let add=function (arg) { sum01+=arg; return add }; add.valueOf=function () { return sum01 }; return add; }else{ let sum3=0; for (let i = 0; i < arguments.length; i++) { sum3+=arguments[i]; } return sum3; } } console.log(sum(1)(2)); //toString valueOf均可以
控制台上 $0 是当前选中的html $1 是咱们上一次选择的节点的应用...一直到$4 --- Array.from(document.querySelectorAll('dic'))===$$('div') -- $_ 上一次执行的结果的引用 -- 控制台右键点击save 以文件的形式查看错误信息 + '123' // 123 + 'ds' // NaN + '' // 0 + null // 0 + undefined // NaN Boolean过滤数组中的全部假值 双位操做符替换Math.floor() 可是负数来讲就不相同了 ~~4.9 取整 |0 返回多行语句 须要用()包裹起来 clas=dir=>( Math.PI* diameer; )
bind方法与call/apply最大的不一样是前端返回一个绑定上下文的函数,后两个直接执行函数 var value = 2; var foo = { value: 1 }; function bar(name, age) { return { value: this.value, name: name, age: age } }; bar.call(foo, "Jack", 20); // 直接执行了函数 // {value: 1, name: "Jack", age: 20} var bindFoo1 = bar.bind(foo, "Jack", 20); // 返回一个函数 bindFoo1(); // {value: 1, name: "Jack", age: 20} 能够指定this 返回一个函数 能够传入参数 柯里化 this存在的问题 var nickname = "Kitty"; function Person(name){ this.nickname = name; this.distractedGreeting = function() { setTimeout(function(){ console.log("Hello, my name is " + this.nickname); }, 500); } } var person = new Person('jawil'); person.distractedGreeting(); //Hello, my name is Kitty 解决方案1: 缓存this var nickname = "Kitty"; function Person(name){ this.nickname = name; this.distractedGreeting = function() { var self = this; // added setTimeout(function(){ console.log("Hello, my name is " + self.nickname); // changed }, 500); } } var person = new Person('jawil'); person.distractedGreeting(); // Hello, my name is jawil 第二种bind var nickname = "Kitty"; function Person(name){ this.nickname = name; this.distractedGreeting = function() { setTimeout(function(){ console.log("Hello, my name is " + this.nickname); }.bind(this), 500); } } var person = new Person('jawil'); person.distractedGreeting(); // Hello, my name is jawil 验证是不是数组 var toStr = Function.prototype.call.bind(Object.prototype.toString); function isArray(obj){ return toStr(obj) === '[object Array]'; } isArray([1, 2, 3]); // true // 使用改造后的 toStr toStr([1, 2, 3]); // "[object Array]" toStr("123"); // "[object String]" toStr(123); // "[object Number]" toStr(Object(123)); // "[object Number]" 柯里化 只传递给函数一部分参数来调用,让它返回一个函数去处理剩下的参数 var add=function(x){ return function(y){ return x+y } } var increment=add(1); increment(2) 这里定义一个add函数,它接受一个参数并返回一个新的函数,调用add以后,返回的函数 就经过闭包的方法记住add的第一个参数,全部bind自己也是闭包的一种使用场景 this问题 一个绑定函数也能使用new操做符建立对象,这种就想把原函数当成构造函数 提供的this被忽略,同时调用时的参数被提供给模拟函数 var value = 2; var foo = { value: 1 }; function bar(name, age) { this.habit = 'shopping'; console.log(this.value); console.log(name); console.log(age); } bar.prototype.friend = 'kevin'; var bindFoo = bar.bind(foo, 'Jack'); var obj = new bindFoo(20); // undefined // Jack // 20 console.log(obj.habit); // shopping console.log(obj.friend); // kevin
将函数的实际参数转换成数组 Array.prototype.slice.call(arguments) [].slice.call(arguments,0) //默认从0开始日后截取 Array.from() //ES6
会遇到一些频繁的事件触发好比: window: resize,scroll, mousedown mousermove keyup keydown... 当持续触发事件是,必定时间内没有再触发事件,处理函数才会执行一次 //第一个参数是函数,第二个参数是定时器的时间 function debounce(func, wait) { var timeOut; return function () { if(timeOut) { clearTimeout(timeOut); } // 保存this上下文,参数 var that = this, args = arguments; //event的问题 timeOut = setTimeout(function () { func.apply(that, args); }, wait) } }
toString(): 返回对象的字符串表示 valueOf(): 返回对象的字符串,数值或者布尔值表示 //先看看toString()方法的结果 var a = 3; var b = '3'; var c = true; var d = {test:'123',example:123} var e = function(){console.log('example');} var f = ['test','example']; a.toString();// "3" b.toString();// "3" c.toString();// "true" d.toString();// "[object Object]" e.toString();// "function (){console.log('example');}" f.toString();// "test,example" //再看看valueOf()方法的结果 var a = 3; var b = '3'; var c = true; var d = {test:'123',example:123} var e = function(){console.log('example');} var f = ['test','example']; a.valueOf();// 3 b.valueOf();// "3" c.valueOf();// true d.valueOf();// {test:'123',example:123} e.valueOf();// function(){console.log('example');} f.valueOf();// ['test','example'] 特殊的地方 表示对象的时候,toString-> [object Object] 而valueOf 返回自身 //例子一 var example = {test:'123'}; console.log(+example);// NaN //例子二 同时改写 toString 和 valueOf 方法 var example = { toString:function(){ return '23'; }, valueOf:function(){ return '32'; } }; console.log(+example);// 32 经过例子一和例子二中,在有一元加操做符,会先调用valueOf,再调用Number()
无论操做多频繁,我始终固定时间触发一次 function throttle(func,wait) { let timeout; return function () { let context=this; let args=arguments; if(!timeout){ timeout=setTimeout(function () { timeout=null; func.apply(context,args); },wait) } } }
function uniq(array){ var temp = []; //一个新的临时数组 for(var i = 0; i < array.length; i++){ if(temp.indexOf(array[i]) == -1){ temp.push(array[i]); } } return temp; } //filter 第一个参数迭代的对象 第二个是下标,第三个数组自己 array.filter((item, index, array) => array.indexOf(item)===index); Array.from(new Set(array)) //排序去重 array.concat().sort((a,b)=>a-b)).filter((item,index,array)=>{ //a||b,a为true返回a //a&&b,a为true返回b return !index||item!==array[index-1] }) [...new Set(array")]
typeof 检测六种基础类型+object+function Undefined null Boolean String number Symbol function Object Object.prototype.toString.call(obj)=> [object 类型]
Maxs=arr=>{ let res=arr[0]; for(let i=0;i<arr.length;i++){ res=Math.max(res,arr[i]); } return res; } Math.max.apply(null,arr) Math.max(...arr) arr.reduce((r, v) => Math.max(r, v))) arr.sort((a,b)=>b-a)[0] arr.reduce((r,v)=r>v?r:v)
flatten=arr=>arr.reduce((r,s)=>{ return r.concat(Array.isArray(s)?flatten(s):s) },[]) flatten=arr=>arr.toString().split(',').map(item=>Number(item)); flatten=arr=>arr.join('.').split(',').map(item=>parseInt(item)); flatten=arr=>{ let res=[]; return arr.map(item=>{ return arr.isArray(item)?res=res.concat(flatten(item)):res.push(item); }) } //some至少有一个 function flatten(arr) { while(arr.some(item=>Array.isArray(item))) { arr = [].concat(...arr); } return arr; } //Array.from toString split
indexOf //ES6 findIndex 返回符合条件的第一个元素的索引 findLastIndex 倒序
数组是对象,函数是对象,对象仍是对象,对象里面的一切都是属性,只有属性,没有方法,方法也是属性
一切(引用类型)都是对象,对象是属性的集合
null是js中一个基本数据类型,之因此显示"Object",是由于对象在底层被表示为二进制,在js中中二进制前三位为0会被判断为object类型,null的二进制都是0,天然前三位也是0,因此返回对象
对象都是经过函数建立的
function Fn() { this.name = '王福朋'; this.year = 1988; } var fn1 = new Fn(); //var obj = { a: 10, b: 20 }; 语法糖 //var arr = [5, 'x', true]; 语法糖 var obj = new Object(); obj.a = 10; obj.b = 20; var arr = new Array(); arr[0] = 5; arr[1] = 'x'; arr[2] = true;其中Object 和Array都是函数
console.log(typeof (Object)); // function console.log(typeof (Array)); // functionprototype原型
Fn.Prototype.constructor=Fn
隐式原型
__proto__
每一个函数function都有一个prototype,每一个对象都有一个
__proto__
obj.__proto__===Object.prototype
实例出来的对象都有一个
__proto__
属性,指向建立这个对象的函数的prototype可是Object.prototype是一个特例,它的
__proto__
指向的是null函数也是一种对象,函数也有
__proto__
吗?function fn(x,y){ return x+y; } var fn1=new Function('x','y','return x+y;') 第一种是传统的函数建立方式,第二种是new Function建立的, 第二种不推荐 ---- fn.__proto__===Fuction.prototype
对象的
__proto__
指向建立它的函数的prototypeObject.__proto__=== Function.prototype var a = Function.prototype; //将Function.prototype看做一个基本对象a,此时: a.constructor === Function; a.__proto__.constructor === Object; //a.__proto__指向Object.pototype instanceof 是作类型检测的 "abc" instanceof String //false 左边不是Object类型直接返回false "abc".__proto__ instanceof String.prototypeinstanceof判断规则是
沿着A 的
__proto__
这条线来找,若是B的prototype在这条线上,那么返回true,不然返回falsefunction Foo(){} var f1 = new Foo(); console.log(f1 instanceof Foo); // true console.log(f1 instanceof Object); // true 分析方法: f1的__proto__路线A: (1) f1.__proto__ === Foo.prototype (2) Foo.prototype.__proto__ === Object.prototype (3) Object.prototype.__proto__ === null //到终点Object函数也是Fucntion建立出来的,并且Fucntion是被自身建立的
访问一个对象的属性时,先在基本属性中查找,若是没有,再沿
__proto__
这条链往上找
执行上下文环境或者叫执行上下文,
- 变量,函数表达式---变量声明默认为undefined
- this
- 函数声明
把类数组转换成真正的数组
- Array.prototype.slice.call(arguments)
- Array.from(arguments)
判断对象是什么引用类型
- Object.prototype.toString.call(obj)
toNumber()
- 基本类型值true=1,false=0,undefined=NaN,null=0,处理失败返回NaN
- 若是有valueOf方法先进行强制转换,若没有则用toString进行强制转换
toBoolean()
- 假值:undefined ,null,false,+0,-0,NaN," ",假值之外都是真值
取整
~~
取整,负数向上取整,正数向下取整- x|0 也能够取整,规则同上
强制转换成Boolean
- !!
==
- NaN不等于NaN,+0不等于-0
- null==undefined,由于null,undefined是假值转化为boolean值都是0
- 下面通常状况下为true
"0" == false //隐式转化 false == 0 false == "" false == [] //[]的length为0=>array(0) []为0 "" == 0 "" == [] 0 ==[]
- 若是两边的值中有[],"",0 尽可能不要用==,两边有true和false也不要用==
{}+[]
- {} 被看成一个独立的空代码块,+[]强制类型转换为0
[]+{}
- []会转换为"" ,+{}后,会强制转换为"[object object]"
优先级
- &&>||>?> :
函数会首先被提高,而后才是变量
console.log(a);//因为上面已声明a,相同的变量名声明会被直接忽略掉 // [Function a] var a = "孙悟空"; function a(){ console.log("小钻风"); } var a=1; var a; console.log(a);//1自执行函数不会进行变量提高的
等号右边没有变量提高的
console.log(ff);//ff is not defiend var f= funciton ff(){}无论条件是否成立都要变量提高,可是var和function声明不定义,当条件成立第一步先给函数赋值
console.log(a); //undefined console.log(F); //undefined if(true){ var a=1; function F() { } } //---------------- f=function(){return true} g=function(){return false} (function(){ if(g()&&[]==![]){ //g=undefined ,g()会报错,已经条件判断,只声明不定义 f=function f(){return false} function g(){return true} } })
没理解
let obj={a: 1};// b:xxxFFFF111 let obj1=obj; obj1.b=obj={x: 1}; console.log(obj.b);// undefined console.log(obj1.b);//{x:1} function fn() { this.name = '张三'; } console.log(fn.name); //fn console.log((new Function('res', 'return res')).name);//anonymous function fn3(y,x='你好',z) { } //函数的length是形参的长度,可是默认值不算在里面,并且书写规范,默认值应该写在最后, //若是默认值等于return, 后续不会执行,会影响默认值 console.log(fn3.length);//1 //函数声明 num()//报错 var num = function (){ console.log(1); }
var a=1; var b=2; function AA(a){ a++; //NaN b++; //3 console.log(a); //NaN console.log(b); //3 } AA() console.log(a); //1 console.log(b); //3 ----- var a=3; function B(a,b) { a++; console.log(a + b); //7 } B(a,a++); a++因为是后++ ,全部传入给b依然是3 console.log(a); a=4 //---------------------------- var code=null; function fn1(n) { n=n||code++; //n=0 return ++code; //code =2 } var n=fn1();//2 console.log(n);//2 //--------------- n=f2(m); var m=0; function f2(n){ n=isNaN(n);//isNaN(undefined)==>true return n; } console.log(window.n) //------ var ary = [1, 2, 3]; function FF(ary) { ary.push(100); ary.shift(); ary = ary[ary.length - 1]; return ary; } console.log(FF(ary));//100 console.log(ary);//[ 2, 3, 100 ]