JS深入浅出学习分析总结
慕课网入门Javascript 学习笔记总结
六种数据类型
弱类型:
var num=32;num='str';32+32;//64
32+'32' //64;
'32'-32 //0
- 数据类型
- 原始类型(五种):number,string,boolean,null,undefined
- 对象类型object:Function,Array,Date…
- 隐式转换
- 类型相同,同===
- 类型不同,尝试类型转换并比较
null==undefined;
number==string转number
boolean==?转number 1==true //true
object==number|string尝试对象转为基本类型 new String('hi')=='hi' //true,
其它:false
- 包装对象:string,number,boolean
var str='12';//string
str.length ;//2
str.a=10;//10
str.a;//undefined,临时对象创建后立即销毁
var newStr=new String('12');//Object
- 类型转换
- typeof:基本类型及function类型(null失效)
- instanceof:对象类型,适合自定义对象及原生对象(不同iframe和window间失效)
- Object.prototype:[[Class]]适合内置对象和基元类型(null和undefined失效;IE678返回【object Object】)
- constructor
- duck type
表达式和运算符
###表达式
- 原始表达式:
- 常量,直接量:3.14,‘a’
- 关键字:null,this,true
- 变量:i,j,k
- 复合表达式:原始表达式&原始表达式
- 初始化表达式:[1,2]===new Array(1,2);
- 函数表达式:var foo=function(){};(function(){})()
- 属性访问表达式:var o={x:1};o.x;o[x’]
- 调用表达式:foo()
- 对象创建表达式:new Func(1);new Object //无参数可以省略’()‘;
运算符(表达式之间)
- 操作数:
- 一元:+num;
- 二元:a+b;
- 三元:c?a:b
- 功能:
- 赋值:a+=1 -比较:a==b
- 算数:a-b;
位:a b; - 逻辑:exp1&&exp2 -字符串:‘a’+’b’
- 特殊: -delete obj.x //Object.defineProperty(obj,’x’, {configurable:false,value:1});
- ,:var a,b;
- in: var i in item
- instanceof ,typeof
- new :obj.hasOwnProperty(‘x’);obj.proto.hasOwnProperty(‘x’) //true
- this
- void:void 0
运算符优先级
语句
- 块语句(js无块及级作用域)和var语句
- try catch语句
- function,switch,循环(for in(1.顺序不定,2.enumberable为false时不可用;3.受原型链影响),do-while),with
- 严格模式strict
一种特殊的运行模式,修复了部分语言上的不足,提供了更强的错误检查并增强安全性
- 不允许使用with
- 所有变量必须先声明
- eval中代码不能创建eval所在作用域下的变量函数,而是为eval单独创建一个作用域并在eval返回时丢弃
- 函数中的特殊对象arguments是静态副本(不像非严格模式时修改arguments或者参数变量会相互影响)
- 删除configurable=false的属性会报错而非忽略
- 禁止八进制字面量(010)
- eval,arguments变量为关键字,不可作为变量名函数名
- 一般函数调用时(非对象方法调用,不使用apply/call/bind等修改this)this指向null而非全局对象,若使用apply/call当传入null或undefined时this指向null或者undefined而非全局。
- 试图修改writable=false,在不可扩展对象上添加属性时包TypeError而非忽略
- arguments.caller,arguments.callee禁用
对象
- 对象结构(原型链)
- 创建对象方法:
- 对象字面量
- new/原型链
- Object.create()
- 属性的操作
- 读写
注意for-in操作符可以把对象原型上属性也遍历出来 - 读写异常
```var obj={x:1};var yz;if(obj.y){yz=obj.y.z}; var yz=obj&&obj.y&&obj.y.z;
- 属性删除
var descriptor=Object.getOwnPropertyDescriptor(Object,’prototype’); descriptor.configurable;//false,是否可配置
![图片描述][4]
> node环境中最后一个也是false
- 属性检测
hasOwnProperty(); propertyIsEnumerable()
![图片描述][5]
- 属性枚举
var o={x:1,y:2,z:3}; ‘toString’ in o;//true o.propertyIsEnumerable(‘toString’);//false var key; for(key in o){console.log(key)};x,y,z var obj=Object.create(o); obj.a=4; var key; for(key in obj){console.log(key)};a,x,y,z for(key in obj){if(obj.hasOwnProperty(key){console.log(key)})};a
- get/set方法
var man={ name:’yl’, get age(){return new Date.getFullYear()-1990}, set age(val){console.log(‘np’+val)} } man.age;//27 man.age=12;//np12
- 属性标签
Object.getOwnPropertyDescriptor({pro:true},’pro’); //Object{value:true,writable:true,enumerable:true,configurable:true} Object.getOwnPropertyDescriptor({pro:true},’a’);//undefined var person={}; Object.defineProperty(person,’name’,{ configurable:false, writable:false, enumerable:true, value:’yl’ }); person.name;//yl person.name=1; person.name;//yl delete person.name;//false Object.defineProperty(person,’type’,{ configurable:true, writable:true, enumerable:false, value:’Object’ }); Object.keys(person);//[‘name’] //多个属性 Object.defineProperties(person,{ title1:{value:’fe1’,enumerable:true}, title2:{value:’fe2’,enumerable:true}, title3:{value:’fe3’,enumerable:true,writable:true} }); Object.getOwnPropertyDescriptor(person,’title3’); //Object{value:’fe3’,writable:true,enumerable:true,configurable:false} Object.getOwnPropertyDescriptor(person,’title1’); //Object{value:’fe3’,writable:false,enumerable:true,configurable:false}
- 对象标签,序列
var toString=Object.prototype.toString; function getType(o){return toString.call(o).slice(8,-1)} getType(true) //”Boolean” toString.call(null) //”[object Null]”
- extensible扩展性
var obj={x:1,y:2}; Object.isExtensible(obj);//true Object.preventExtensions(obj); Object.isExtensible(obj);//false obj.z=1; obj.z;//undefined,add new property failed Object.getOwnPropertyDescriptor(obj,’x’); //Object{value:1,writable:true,enumerable:true,configurable:true} Object.seal(obj); Object.getOwnPropertyDescriptor(obj,’x’); //Object{value:1,writable:true,enumerable:true,configurable:false} Object.isSealed(obj);//true Object.freeze(obj); Object.getOwnPropertyDescriptor(obj,’x’); //Object{value:1,writable:false,enumerable:true,configurable:false} Object.isFrozen(obj);//true //caution :not affects prototype chain!!!
- 序列化其他,其它对象方法
//序列化JSON.stringify&JSON.parse var obj={x:1,y:true,z:[1,2,3],nullVal:null}; JSON.stringify(obj);//”{“x”:1,”y”:true,”z”:[1,2,3],”nullVal”:null}” obj={x:undefined,y:NaN,z:Infinity,nullVal:new Date()}; JSON.stringify(obj);//”{“y”:null,”z”:null,”nullVal”:”2017-02-07T23:10:33.107Z”}”,注意undefined和NaN o=JSON.parse(‘{“x”:”1”}’); o.x;//1 //其它对象方法toString()&valueOf()
##数组
- 创建与操作
> 数组是值的有序集合,每个值叫做元素,每个元素在数组中都有数字位置
编号,即索引。js中数组是弱类型的,其中可以含有不同类型元素。
```var arr=[1,true,null,undefined,{},[]] ```
- 创建数组字面量:[]
- new Array()
- 元素读写
```arr.length;arr[i];delete arr[j];//delete 操作不改变原数组 ```
- 元素增删
```push,pop,shift,unshift,delete```
- 数组迭代
```for-in for```
### 二维数组+稀疏数组
- 稀疏数组:并不含有从0开始的连续索引,一般length属性值比实际元素个数多
### 数组方法
//{}=>Object.prototype;[]=>Array.prototype Array.prototype.join; Array.prototype.reverse; Array.prototype.sort; Array.prototype.concat; Array.prototype.slice; Array.prototype.splice;//左闭右开 Array.prototype.forEach;//ES5 Array.prototype.map;//ES5 Array.prototype.map;//ES5 Array.prototype.filter;//ES5 Array.prototype.every;//ES5 Array.prototype.some;//ES5 Array.prototype.reduce/reduceRight;//ES5 Array.prototype.indexOf/lastIndexOf;//ES5 Array.isArray;//ES5;[] instanceof Array;[].constructor===Array;({}).toString.apply([])===’[object Array]’ var arr=[1,2,3]; var sum=arr.reduce(function(x,y){return x+y},0);//6 var max=arr.reduce(function(x,y){return x>y?x:y});//3
###小结
- 数组vs一般对象
同:都可以继承,数组是对象对象不一定是数组,数组拥有对象的一切属性和方法
异:数组自动更新length,按索引访问数组相对对象属性访问迅速。数组对象集成Array.prototype上的大量数组操作方法
- 字符串vs数组
字符串可以堪称类数组
var str=’hello’; str.charAt(0);//’h’ str1;//e Array.prptotype.join.call(str,’_’);//’h_e_l_l_o’
## 函数和作用域
> 一块js代码,定义一次但可以多次调用。js中函数也是对象
- 函数=函数名+参数列表+函数体
> 返回值:
1. 如果函数没有return语句或者return后边是基本类型=>返回this
2. 如果返回一个对象=>返回以此对象作为构造器的一个实例
### 重点
- this
- arguments
- 作用域
- 调用:
- 直接调用:foo()
- 对象方法:o.method()
- 构造器:new Foo()
- call/apply/bind:foo.call
- 创建
- 函数声明:function a(){};会被前置
- 函数表达式:
//function variable var a=function(){} //IEF(Immediately Executed Function) (function(){})() //first-class function return function(){} //NFE(Named Function Expression) var a=function a(){} //FC(Function Constructor)
||函数声明|函数表达式|函数构造器|
|---|---|---|
|前置|Y|N|N|
|允许匿名|N|Y|Y|
|立即调用|N|Y|Y|
|在定义该函数的作用域通过函数名访问|Y|N|N|
|没有函数名|N|N|Y|
### this
- 全局的this(浏览器)
- 一般函数的this
function a(){return this} a()===window;//true ,global,object //严格模式下:a()===undefined
- 作为对象方法的this
var o={ prop:23, f:function(){return this.prop} } o.f();//23 function g(){return this.prop} o.f=g; o.f();//23
- 对象原型链上的this
var o={ f:function(){return this.a+this.b} } var p=Object.create(o); p.a=1;p.b=2; p.f();//3
- get/set方法
function modulus(){ return Math.sqrt(this.rethis.re+this.imthis.im) } var o={ re:1,im:-1, get phase(){ return Math.atan2(this.im,this.re) } } Object.defineProperty(o,’modulus’,{ get:modulus,emumerable:true,configurable:true }) console.log(o.phase,o.modulus);//-.78,1.142
- 构造器中的this
function MyClass(){this.a=22} var o=new MyClass(); o.a;//22 function C2(){this.a=23;return {a:38}} o=new C2() o.a;//23
- call/apply方法与this
function add(a,b){return this.a+this.b+c+d} var o={a:1,b:3} add.call(o,5,7);//1+3+5+7=16 add.apply(o,[10,20]);//1+3+10+20=34 function bar(){ console.log(Object.prototype.toString.call(this)) } bar.call(7);//”[object Number]”
- bind方法
function f(){return this.a} var g=f.bind({a:”test”}) g();//test
### 属性和方法
- arguments属性
function foo(x,y,z){ ‘use strict’; arguments.length;//2 arguments[0];//1 arguments[0]=20; x;//changed to 20,严格模式下仍是1 arguments2=100; z;//still undefined !!! 未传参数失去绑定关系 arguments.callee===foo;//true,严格模式下不可用 } foo(1,2);//foo.name=>函数名 foo.length;//3 ,foo.length=>形参个数,arguments.length=>实参个数
- call/apply方法
function foo(x,y){console.log(x,y,this)} foo.call(100,1,2);//1,2,Number(100) foo.apply(true,[3,4]);//3,4,Boolean(true) foo.apply(null);//undefined,undefined,window(严格模式下null) foo.apply(undefined);//undefined,undefined,window(严格模式下undefined)
- bind方法(IE9以上)
- bind与currying(把整个函数拆成多个单元)
function add(a,b,c){return a+b+c} var func=add.bind(undefined,100); func(1,2);//103 var func2=func.bind(undefined,200) func2(10);//310
- bind与new
function foo(){this.b=100;return this.a} var func=foo.bind({a:1}) func();//1 new func();//{b:100},bind被忽略???
## 闭包作用域
- 闭包
function outer(){ var localVal=30; return function(){ return localVal; } } var func=outer(); func();//30
- 封装
(function (){ var _userId=123; var _typeId=”Item”; var export={}; function converter(userId){ return +userId; } export.getUserId=function(){ return converter(_userId); } export.getTypeId=function(){ return _typedId; } window.export=export; })()
> 好处:灵活方便,封装;坏处:空间浪费,内存泄漏,性能消耗
### 作用域
- 类型
- 全局
- 函数
- eval
- 作用于链
### ES3的执行上下文(EC)
console.log(‘EC0’0); function funcEC1(){ console.log(‘EC1’); var funcEC2=function (){ console.log(‘EC2’); var funcEC3=function(){ console.log(‘EC3’); }; funcEC3(); }; funcEC2(); }; funcEC1(); //EC0 EC1 EC2 EC3
- 概念:变量对象(Variable Object),一个抽象概念中的对象,用于存储执行上下文中的变量,函数声明,函数参数。
- EC与VO
activeExecutionContext={ VO:{ data_var,data_func_declaration,data_func_arguments } } GlobalContextVO VO===this===global //demo var a=10; function test(x){ var b=20; } test(30); //=> VO(gC)={ a:10, test: } VO(test functionContext)={ x:30,b:20 }
- 全局执行上下文GEC
VO(globalContext)===[[global]]; [[global]]={ Math:<…>, String:<>, isNaN:function (){Native Code}, … window:global//applied by browser(host) }; GlobalContextVO (VO===this===global) String(10);//[[global]].String(10); window.a=10;//[[global]].window.a=10 this.b=20;//[[global]].b=20
- 函数中的激活对象
VO(functionContext)===AO; AO={ arguments:
- 变量初始化阶段
> VO填充顺序:
1. 函数参数(arguments=arguments||undefined);
2. 函数声明(命名冲突则覆盖,函数表达式不影响VO);
3. 变量声明(初始化为undefined,命名冲突则忽略)
function test(a,b){ var c=10; function d(){} var e=function _e(){}; (function x(){})(); b=20; } test(10); //AO AO(test)={ a:10,b:undefined,c:undefined,d:<ref to func ‘d’>,e:undefined }
###demo
function test(a,b){ var c=10; function d(){} var e=function _e(){}; (function x(){}) b=30; }
- 变量初始化阶段
test(10); AO(test)={ a:10,b:undefined, c:undefined, d:<ref to func ‘d’> e:undefined }
- 代码执行阶段
AO(test)={ a:10,b:20, c:10, d:<ref to FunctionDeclaration ‘d’> e:function _e{} }
测试
alert(x); var x=10; alert(x);x=20; function x(){} alert(x); if(true){var a=1}else{var b=true} alert(a);alert(b) //function x(){} 10 20 1 undefined
## OOP(封装+继承+多态+抽象)
> OOP:一种程序设计范型,同时也是一种程序开发方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性,灵活性和扩展性。
function Person(name,age){this.name=name;this.age=age;}
Person.prototype.hi=function(){console.log(‘Hi Iam’+this.name+’I am’+this.age+’years old now’)}
Person.prototype.LEGS_NUM=2; Person.prototype.ARMS_NUM=2; Person.prototype.walk=function(){console.log(this.nama+’is walking’)} function Student(name,age,className{Person.call(this,name,age);this.className=className}
Student.prototype=Object.create(Person.prototype);// Student.prototype.constructor=Student; Student.prototype.hi=function (){ console.log(“Hi”+this.name+’,I am’+this.age+’years old ,and from’+this.className+’.’) } Student.prototype.learn=function(subject){console.log(‘my major is’+subject)} //test var tom=new Student(‘Tom’,22,’Class 3’); tom.hi(); tom.LEGS_NUM; tom.walk(); tom.learn();
![再谈原型链][6]
### prototype属性
Student.prototype.x=101; tom.x;//101
Student.prototype={y:3}; tom.y;//undefined tom.x;//101
var jack=new Student(‘Jack’,22,’Class 1’); jack.x;//undefined jack.y;//2
- Thus:
1. 动态修改prototype对象的属性, 会影响创建及已创建的实例
2. 修改整个prototype对象,只影响后续创建的实例
- 内置构造器的prototype
Object.prototype.x=1; var obj={}; obj.x;//1 for(var key in obj){console.log(key)}//x //ES5 Object.defineProperty(Object.prototype,{ writable:true,value:1 }) var obj={}; obj.x;//1 for(var key in obj){console.log(key)}//nothing
### 实现继承的方式
function Person(){} function Student(){} Student.prototype=Person.prototype;//1 bad Student.prototype=new Person;//2===4 Student.prototype=Object.create(Person.prototype);//3,ES5 //check if(!Object.create){ Object.create=function(proto){ function F(){} F.prototype=proto; return new F; }
} Student.prototype.constructor=Person;//4
### 模拟重载,链式调用,模块化
- 模拟重载
function Person(){ var args=arguments; if(typeof args[0]===’object’&&args[0]){ if(args[0].name){ this.name=args[0].name
} if(args[0].age){ this.age=args[0].age
}else{ if(args[0]){ this.name=args[0] } if(args1){ this.age=args1 } } } } Person.prototype.toString=function(){ return ‘name=’+this.name+’,age’+this.age; } var tom=new Person(‘tom’,28); var jack=new Person({name:’Jack’,age:23})
- 调用子类的方法
function Person(name){this.name=name;} function Student(name,className){this.className=className;Person.call(this,name);} var tom=new Student(‘tom’,’NT’);
Person.prototype.init=function(){}; Student.prototypt.init=function(){Person.prototype.init.apply(this,arguments)};
- 链式调用
function ClassManager(){ ClassManager.prototype.addClass=function(str){ console.log(‘Class’+str+’added’); return this;//实现链式调用 } } var manager=new ClassManager(); manager.addClass(‘classA’).addClass(‘classB’).addClass(‘classC’)
- 抽象类
function DetectorBase(){ throw new Error(‘Abstract class can not be invoked directly!’) } DetectorBase.detect=function(){console.log(‘Detector starting…’)}; DetectorBase.stop=function(){console.log(‘Detector stopped.’)}; DetectorBase.init=function(){throw new Error(‘Error’)};
function LinkDetector(){} LinkDetector.prototype=Object.create(Detector.prototype); LinkDetector.prototype.constructor=LinkDetector; //…add methods to LinkDetector…
- defineProperty(ES5)
function Person(name){ Obect.defineProperty(this,’name’,{value:name,enumerable:true}); } Object.defineProperty(Person,”ARMS_NUM”,{value:2,enumerable:true}); Object.seal(Person.prototype); Object.seal(Person); function Student(name,className){ this.className=className; Person.call(this,name) } Student.prototype=Object.create(Person.prototype); Student.prototype.constructor=Student;
- 模块化
var moduleA; moduleA=function(){ var prop=1; function func(){ return{ func:func, prop:prop } } }
var moduleA; moduleA=new function(){ var prop=1; function func(){} this.func=func; this.prop=prop; }
- 实践(探测器)
!function(global){ function DetectorBase(configs){ if(!this instanceof DetectorBase){ throw new Error(‘Do not invoke without new’) } this.configs=configs; this.analyze(); } DetectorBase.prototype.detect=function(){ throw new Error(‘Not implemented’) } DetectorBase.prototype.analyze=function(){ console.log(‘analyzing…’); this.data=’###data###’; } } function LinkDetector(links){ if(!this instanceof LinkDetector){ throw new Error(‘Do not invoke without new’); } this.links=links; DetectorBase.aply(this,arguments); } function ContainerDetector(containers){ if(!this instanceof ContainerDetector){ throw new Error(‘Do not invoke without new’) } this.containers=containers; DetectorBase.apply(this,arguments); } //inherit first inherit(LinkDetector,DetectorBase); inherit(ContainerDetector,DetectorBase); // ```
Leave a Comment