值类型
Number,String,Boolean,Null,undefined
case
var a = 100 var b = a b = 200 // a=100 b=200
值类型中值赋值是不会相互影响
引用类型
对象,数组和函数
case
var a = {age:18} var b = a b.age=19 //a.age=19 b.age=19
引用类型是变量公用一个内存块,节省内存空间,引用类型赋值会相互影响
typeof运算符
只能区分值类型,不能区分引用类型,能区分函数
case
typeof undefined typeof 123 typeof 'abc' typeof true typeof {} typeof [] typeof null typeof console.log
变量计算
会强制类型转换
字符串拼接
== 运算符
if语义
0/NaN/''/null/undefined/fasle在if里面是fasle
逻辑运算符
case
100+10 100+'10' 0=='' 100=='100' null==undefined var a=100 10&&0 ''||'abc' !a !!a
构造函数
function Foo(name, age){ this.name = name this.age = age //return this //默认有这一行 } var foo = new Foo('susan', 18)
1、new Foo
2、this赋值
3、foo具备了name和age值
var a = {} 是var a = new Object()的语法糖
var a = []是var a = new Array()的语法糖
function Foo(){}是var foo = new Foo(){}
使用instanceof判断一个函数是否是一个变量的构造函数
原型规则
1、所有的引用类型(数组,对象,函数),都具有对象特性,即可扩展属性
2、所有的引用类型(数组,对象,函数),都有一个__proto__属性,属性值是一个普通的对象(隐示原型)
3、所有的函数,都有一个prototype属性,属性值也是一个普通对象(显示原型)
4、所有的引用类型(数组,对象,函数),__proto__属性值指向它的构造函数的"prototype"属性值
5、当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么回去它的__proto__(它的构造函数的property)中寻找
case1
var obj={} var arr=[] function fn(){} //第一个规则 obj.a=100 arr.a=100 fn.a=100 //第二个规则 console.log(obj.__proto__) console.log(arr.__proto__) console.log(fn.__proto__) //第三个规则 console.log(fn.prototype) //第四个规则 console.log(obj.__proto__===Object.prototype) console.log(arr.__proto__===Array.prototype)
case2
function Foo(name, age){ this.name=name } Foo.prototype.alertName=function(){ console.log('Hi '+this.name) } var f = new Foo('susan') f.printName=function(){ console.log('Hello '+this.name) } f.printName() //第五个规则,对象没有这个属性,会尝试去它构造函数的property中找 f.alertName()
循环对象自身的属性
for(item in f){ if (f.hasOwnProperty(item)){ console.log(item) } }
hasOwnProperty
原型链
f.__proto__.__proto__
case
function Foo(name, age){ this.name=name } Foo.prototype.alertName=function(){ console.log('Hi '+this.name) } var f = new Foo('susan') f.printName=function(){ console.log('Hello '+this.name) } f.printName() f.alertName() f.toString() // f.__proto__.__proto__中去找,即Object
instanceof
f instance Foo判断逻辑
f.__proto__一层层往上,能否对应到Foo.prototype
再试着判断 f instanceof Object
执行上下文
范围:一段script或一个函数
全局:变量定义,函数声明
函数:变量定义,函数声明,this,arguments
注意 函数声明 和 函数表达式 的区别
case1
console.log(a) var a = 100 fn('susan') function fn(name){ age = 20 console.log(name, age) var age }
case2
fn1() function fn1() {}//声明 fn2() var fn2 = function() {}//表达式
this
this要在执行时才能确认值,定义时无法确认
作为构造函数执行
作为对象属性执行
作为普通函数执行
call apply bind
case1
window.name='window' var a = { name:'A', fn: function(){ console.log(this.name) } } a.fn() a.fn.call({name:'B'}) var fn1 = a.fn fn1()
case2
function Foo(name) { this.name } //作为构造函数执行 var foo = new Foo('susan') foo() var obj = { name:'A', printName: function(){ console.log(this.name) } } //作为对象属性执行 obj.printName() function fn(){ console.log(this) } //作为普通函数执行 fn() function Goo(name){ console.log(name) console.log(this) } //call apply bind Goo.call({x:100}, 'susan')
作用域
无块级作用域
全局和函数作用域
case
//无块级作用域 if (true){ var name = 'susan' } console.log(name) var a = 100 function fn(){ var a = 200 console.log('fn', a) } console.log('global', a) fn()
作用域链
先看下什么是自由变量
case1
var a = 100 function fn() { var b = 200 // 当前作用域没有定义的变量,即 “自由变量” console.log(a) console.log(b) } fn()
case2
var a = 100 function F1(){ var b = 200 function F2(){ var c = 300 console.log(a) // a,b是自由变量 console.log(b) console.log(c) } F2() } F1()
闭包
返回一个函数(函数作为返回值)
函数作为参数来传递
case1
function F1(){ var a = 100 return function(){ console.log(a) } } var f1 = F1() var a = 200 f1()
分析:第一个a是函数作用域,第三个a是全局作用域,f1()函数执行,第二个a是一个自由变量,当前作用域没有a,那么去父级作用域中找,也就是第一个a,那么结果就是100
case2
function F1(){ var a = 100 return function(){ console.log(a) } } var f1 = F1() function F2(fn){ var a = 100 fn() } F2(f1)
异步
场景
定时任务:setTimeout,setInterval
网络请求:ajax请求,动态img加载
事件绑定
case
console.log(100) setTimeout(function(){ console.log(200) },1000) console.log(300)
单线程
case
console.log(100) setTimeout(function(){ console.log(200) }) console.log(300)
分析:第一行打印100,setTimeout是一个异步,不会执行,先放一边等待,然后执行第三行打印300,此刻程序执行完,然后查看是否有异步代码,然后接着打印200