var
- 存在变量提升
- 只有全局作用域与函数作用域
- 不存在块作用域
- 允许在相同作用域内,重复声明同一个变量,后者会覆盖前面的变量声明
/**** 变量提升****/
name = "aa"
var name;
//编译时
var name;
name = "aa"
console.log(name) //aa
console.log(a);//undefined
var a = 3;
/**** 只有全局作用域与函数作用域****/
var name = "abc";
function fn (){
console.log(name)
var name = "fn-abc";
}
fn()
//编译时
var name = "abc";
function fn (){
//当函数中用var 定义变量时 提升至fn 函数作用域中
var name;
console.log(name) //undefined
var name = "fn-abc";
}
fn()
/*******
LHS 查找关系
var a = "ok" 有var 关键字定义 a (有赋值=的操作)都是LHS 左查找
******
/
/**
* 当JavaScript引擎执行LHS查询时,
* 如果在顶层作用域中无法找到目标变量,PS:当前顶层作用域是fn 函数
* 那么,就会在全局作用域查找该变量,如果找到改变量输出,PS:案例函数在全局对象中查找到name1 = 1,所以输出1
* 如果未找到则抛出undefined
*/
var name = "abc";
var name1 = 1
function fn (){
console.log(name1) //1
console.log(name) //undefined
var name = "fn-abc";
}
fn()
/**不存在块作用域 */
for(var i =0;i<3;i++){
console.log(i) //1,2,3
}
console.log(i) //3
//编译时 变量i提前
var i;
for(i =0;i<3;i++){
console.log(i) //1,2,3
}
console.log(i) //3
/**允许在相同作用域内,重复声明同一个变量,后者会覆盖前面的变量声明 */
var name = "abc"
var name = "changename"
console.log(name) //changename
let
- 不存在变量提升,只在定义的本身
- 有块作用域
- 不允许在相同作用域内,重复声明同一个变量。
/**不存在变量提升,只在定义的本身 */
console.log(name) //直接抛出异常报错
let name = "123"
/**有块作用域 */
for(let i =0;i<3;i++){
console.log(i) //1,2,3
}
console.log(i) // i is not defined
/**不允许在相同作用域内,重复声明同一个变量 */
let name = "name"
let name = "changename" //直接跑错,抛出异常
Promise
Promise 是异步编程的一种解决方案
任务状态管理
resolve
成功状态,对应Promise.resolve
reject
失败状态,对应Promise.reject
error
异常状态, 对应Promise.reject
或new Promise().catch(onRejected)
THIS 关键字理解
在浏览器中执行代码时,全局作用域里this和函数中的this 都指向window全局对象。
当函数被new关键字创建对象或被当做对象调用时 this 指向执行对象本身
console.log(this) //指向window
var firstName = "Peter",
lastName = "Ally";
function showFullName () {
//这个函数里的"this"会储存window对象的值
//因为与变量firstName和lastName一样,showFullName()函数是在全局作用域里定义的
console.log (this.firstName + " " + this.lastName);
}
/***
当函数被new关键字创建对象或被当做对象调用时 this 指向执行对象本身
***/
function fn() {
console.log(this) //fn
}
new fn()
var Dog = {
say() {
console.log(this) //Dog
}
}
Dog.say();
this最容易用错的情况
this
关键词在下列情况下最容易被用错:
- 当使用
this
的方法被“借用”时; - 当使用
this
的方法被用作回调函数时; - 当
this
被用于闭包-内部函数里时。
/**
* 当this 的方法被借用时,this 指向借用对象dog
*/
var person = {
name:'小明',
age:18,
say(){
console.log(this.name,this.age) //大黄 1
}
}
var dog = {
name:'大黄',
age:1
}
//采用apply 将say方法中的this 执行dog 对象
person.say.apply(dog)
/**
* 当this 的方法被用作回调函数时
* 当上下文环境改变时,在一个对象(persopn)里定义的方法(say)却到另外一个对象(dog)里执行(say)时,
* this关键词不再指代原对象person,而是指代调用该方法的对象(say()函数),
* 而say()函数本身的this 指向window全局
*/
var person = {
name: '小明',
age: 18,
say() {
console.log(this) //window
console.log(this.name, this.age) //undefined
}
}
var dog = {
name: '大黄',
age: 1,
say(event) {
event()
console.log(this.name, this.age) //大黄,1
}
}
dog.say(person.say)
//解决方案采用apply bind call 解决
dog.say(person.say.bind(person))
/**
* 当this被用于闭包-内部函数里时。
* 匿名函数里的this无法访问外部函数的this,所以在非严格模式下其被绑定了window对象上。
*/
var person = {
name:'小明',
age:18,
say(){
(function(){
console.log(this) //window
})()
}
}
person.say()
Call方法、Apply方法、Bind函数方法、箭头函数方法
call,apply,bind这三个方法其实都是继承自Function.prototype中的
主要作用:都是用来改变函数的this对象的指向的。
call 语法:call(this,args,args)
apply语法:call(this,[args,args])
bind语法:bind(this,args,args)
/**
* @augments apply(this,[args,args])
* @augments call(this,args,args)
* @augments bind(this,args,args)
*/
function jone(name,age,work){
this.name=name;
this.age=age;
this.work=work;
this.say=function(msg,err){
console.log(err)
console.log(msg+",我叫"+this.name+",我今年"+this.age+"岁,我是"+this.work)
}
}
var jack={
name:"jack",
age:'24',
work:"学生"
}
var pet=new jone();
pet.say.apply(jack,["欢迎您","test"])
pet.say.call(jack,"欢迎您","test")
pet.say.bind(jack,"欢迎您","test")()
/**
bind 官方提供的源码
**/
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
// this instanceof fNOP === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fNOP
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// 维护原型关系
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();
return fBound;
};
}
Javascript类的定义与继承
类的创建:
- 字面量静态对象;无需使用new 关键字就可直接使用
- function 构造函数; 使用new 关键字实例化对象
/**
* 字面量创建对象,静态对象无需实例化,直接使用
采用构造函数必须使用new 关键字实例化
*/
var persopn = {
name:"人类",
age:16
}
console.log(persopn.name)
/**
* 构造函数采用new关键字实例化对象
*/
var persopns = function(){
}
persopns.prototype = {
name:"外星人",
age:100
}
console.log(new persopns().name)
/**
* 原型链继承
*/
var persopn = function(){
this.name = "人类"
this.age = 18
this.say = function(){
console.log(this.name,this.age)
}
}
/**
* 构造函数采用new关键字实例化对象
*/
var persopns = function(){
this.name ="外星人"
}
persopns.prototype = new persopn()
Object
Object.create
Object.defineProperty
javascript 类型判断
以下是存在的类型:
typeof 可判断:
有如下可知:typeof 只能判断基本类型,对于引用类型输出都是object 无法判断
- Boolean
- Number
- String
- Function
- Array
- Date
- RegExp
- Object
- Error
console.log(typeof true) //boolean
console.log(typeof 1) //number
console.log(typeof "a") //string
console.log(typeof function(){}) //function
console.log(typeof []) //object
console.log(typeof new Date()) //object
console.log(typeof /\s/) //object
console.log(typeof {}) //object
console.log(typeof new Error()) //object
Object.prototype.toString.call 方法可判断引用类型:
console.log(Object.prototype.toString.call([])) //[object Array]
console.log(Object.prototype.toString.call(new Date())) //[object Date]
console.log(Object.prototype.toString.call(/\s/))//[object RegExp]
console.log(Object.prototype.toString.call({})) //[object Object]
console.log(Object.prototype.toString.call(new Error())) //[object Error]
instanceof 可判断 A是否为B的实例:
console.log([] instanceof Array) //true
constructor 使用constructor属性返回是否是创建此对象函数的引用。
console.log([].constructor==Array) //true
封装一个统一返回类型的方法:
/**
*
* @param {*} obj 需判断类型的对象 如:[],"aaa",123,{}等。
*/
let getType = (obj)=>{
return Object.prototype.toString.call(obj).match(/object\s*(\w*)/)[1]
}
console.log(getType([])) //Array
javascript 函数的柯里化
柯里化通常也称部分求值,其含义是给函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,这中间可嵌套多层这样的接受部分参数函数,直至返回最后结果。
因此柯里化的过程是逐步传参,逐步缩小函数的适用范围,逐步求解的过程。
/**
*
* @param {*} a
* @param {*} b
* 函数分步传递参数,每次传递参数后部分应用参数,并返回一个更具体的函数接受剩下的参数,
* 并进行处理
*/
function A(a) {
return function(b){
console.log(a+b)
}
}
A(1)(2)
javascript 原型链 prototype 与 __proto__
prototype 与 __proto__ 的作用,让实例都拥有原型对象的属性与方法。原型对象共享属性与方法
不同之处:
- 每个对象都有
__proto__
属性来标识自己所继承的原型 - 只有函数才有
prototype
属性
//每个对象都有__proto__属性来标识自己所继承的原型
var obj = {}
console.log(obj.__proto__) //{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
console.log(obj.prototype) //undefined
//只有函数才有prototype属性
function dog (){
}
console.log(dog.__proto__) //Function 原型对象
console.log(dog.prototype) //{constructor: ƒ dog(), __proto__:Object}
prototype 与 __proto__ 深入理解
prototype
当你创建函数时,JS会为这个函数自动添加prototype
属性,值是空对象 值是一个有 constructor 属性的对象,不是空对象。
function dog (){
}
/**
* 当你创建函数时,JS会为这个函数自动添加prototype属性,值是空对象 值是一个有 constructor 属性的对象,不是空对象。
* prototype 指向原型对象(既创建函数的本身)dog 函数作为new dog()实例的原型对象
*/
dog.prototype.name = "大黄" //在dog 对象下添加公用属性name 并且赋值
console.log(new dog().__proto__ == dog.prototype) //true
而一旦你把这个函数当作构造函数(constructor
)调用(即通过new
关键字调用),那么JS就会帮你创建该构造函数的实例,实例继承构造函数prototype
的所有属性和方法(实例通过设置自己的__proto__
指向承构造函数的prototype
来实现这种继承)
/**
* 当你创建函数时 dog,
* JS会为这个函数dog自动添加prototype属性,
* prototype属性中有个constructor 属性的对象,通常称作构造函数
* {constructor:function dog()}
*/
function dog (){
}
/**
* 那么JS就会帮你创建该构造函数的实例,function dog()
* 实例继承构造函数prototype的所有属性和方法
* 实例通过设置自己的__proto__指向承构造函数的prototype来实现这种继承
*/
console.log(new dog())
console.log(new dog().__proto__ == dog.prototype) //true
详情:
__proto__
__proto__ 是一个实例指针,指向它的原型对象
function dog (){
}
dog.__proto__ //dog 函数实例 指向它的原型对象Function
console.log(dog.__proto__ ==Function.prototype) //true
详情:
FUNCTION.LENGTH
//调用时想拿到参数集合 使用argumnet
function add(a,b,c){
console.log(arguments)//[1,2,3]
}
//表示拿到定义函数时的参数总的数量,但并不能拿到参数具体值
console.log(add.length) //3
add(1,2,3)
JAVASCRIPT 闭包