六种数据类型
弱类型特征
32+'32' //'3232'; '32'-32 //0
- 数据类型
- 原始类型(五种):
number,string,boolean,null,undefined
- 对象类型object:
Function,Array,Date,RegExp,Math...
- 隐式转换
- 类型相同,同===
- 类型不同,尝试类型转换并比较
!!0;//false
null==undefined;
number==string=>number
boolean==?=>number 1==true //true
object==number|string尝试对象转为基本类型 new String('hi')=='hi' //true,
其它:false
- 包装对象:string,number,boolean
JS一切皆对象的体现,即便是基本类型也可以通过包装对象转换成对象类型;且基本类型也可以有对象类型一样有自己的属性和方法,只不过昙花一现即刻销毁(意义。。。)。
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,'x'
- 关键字:
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();obj.fun()
- 对象创建表达式:
new Func(1);new Object //无参数可以省略'()'
;
运算符(表达式之间)
- 操作数:
- 一元:
+num
; - 二元:
a+b;
- 三元:
c?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,with //循环(for in(1.顺序不定,2.enumberable为false时不可用; 3.受原型链影响),do-while)
严格模式
strict
一种特殊的运行模式,修复了部分语言上的不足,提供了更强的错误检查并增强安全性
- NO
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而非忽略
- NO
arguments.caller,arguments.callee
对象
对象结构(原型链)
var obj={};obj.y=2;obj.x=1; function foo(){} foo.prototype.z=3; var obj=new foo(); obj.z;//3
创建对象方法:
- 对象字面量
- new/原型链
function foo(){} foo.prototype.z=3; var obj=new foo(); obj.y=2;obj.x=1; obj.z;//3 obj.x;//1;obj.y;//2 typeof obj.toString;//'function'的一个实例 'z' in obj;//true obj.hasOwnProperty('z');//false
- Object.create()
var obj=Object.create({x:1}); obj.x;//1 typeof obj.toString;//'function' obj.hasOwnProperty('x');//false var obj=Object.create(null); obj.toString();//undefined
属性的操作
- read/write
注意for-in操作符可以把对象原型上属性也遍历出来
- 读写异常
```var obj={x:1};var yz;if(obj.y){yz=obj.y.z};
var yz=obj&&obj.y&&obj.y.z;
- delete(只对未声明即使用的变量返回true,node环境中一个也返回false)
var descriptor=Object.getOwnPropertyDescriptor(Object,'prototype');
descriptor.configurable;//false,是否可配置
var globaVa=1;
delete globalVal;//false
(function (){
var localVal=1;return delete localVal;
})();//false
function fd(){}
delete fd;//false
(function fd(){};return delete fd)();//false
ohNO=1;window.ohNO;//1;delete ohNO;//true
- 属性检测
Object.defineProperty(cat,'price',{
enumerable:false,
value:1000
});
cat.propertyIsEnumerable('price);//false
cat.hasOwenProperty;//true
- 属性枚举
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'
str[1];//e
Array.prptotype.join.call(str,'_');//'h_e_l_l_o'
函数和作用域
一块js代码,定义一次但可以多次调用。js中函数也是对象
函数=函数名+参数列表+函数体
返回值:谨记以下区别
- 如果函数没有return语句或者return基本类型=>返回this
- 如果返回对象类型=>返回此对象的一个实例
重点
- 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.re*this.re+this.im*this.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;//38
- 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 arguments[2]=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 (w){ 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; w.export=export; })(window)
好处:灵活方便,封装;坏处:空间浪费,内存泄漏,性能消耗
作用域
- 类型
- 全局
- 函数
- 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:<ref to function>
}
VO(test functionContext)={
x:30,b:20
}
- 全局执行上下文GEC(Global Execution Context)
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
- 函数中的激活对象AO(Active Object):VO(functionContext)===AO;
AO={ arguments:<Arg0>//函数调用时生成 }; arguments={ callee,length,properties-indexes }
- 变量初始化阶段
VO填充顺序:123
- 函数参数(arguments=arguments||undefined);
- 函数声明(命名冲突则覆盖,函数表达式不影响VO);
- 变量声明(初始化为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:
- 动态修改prototype对象的属性, 会影响创建及已创建的实例
- 修改整个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(args[1]){
this.age=args[1]
}
}
}
}
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);
//expand later
LinkDetector.prototype.detect=function(){
console.log('Loading data'+this.data);
console.log('Link detector started');
console.log('Scaning links'+this.links);
};
ContainerDetector.prototype.detect=function(){
console.log('Loading data'+this.data);
console.log('Containing detection started');
console.log('Scaning containers'+this.containers);
}
//prevent from being altered
Object.freeze(DetectorBase);
Object.freeze(DetectorBase.prototype);
Object.freeze(LinkDetector);
Object.freeze(LinkDetector.prototype);
Object.freeze(ContainerDetector);
Object.freeze(ContainerDetector.prototype);
//export to global object
Object.defineProperties(global,{
LinkDetector:{value:LinkDetector},
ContainerDetector:{value:ContainerDetector},
DetectorBase:{value:DetectorBase},
});
function inherit(subClass,superClass){
subClass.prototype=Object.create(superClass.protottype);
subClass.prototype.constructor=subClass;
}
}(this);
var cd=new ContainerDetector('#abd#def#');
var Id=new LinkDetector('https:www.baidu.com');
cd.detect();
Id.detect();
[1]: http://img.mukewang.com/5899cf7300011e1c08280441.jpg
[2]: http://img.mukewang.com/5899cfd80001d6cb05290393.jpg
[3]: http://img.mukewang.com/5899d0410001527005980329.jpg
[4]: http://img.mukewang.com/5899d324000108a606410289.jpg
[5]: http://img.mukewang.com/5899d52c00013d8206160360.jpg
[6]: http://img.mukewang.com/589babcb0001243408190462.jpg
热门评论
32+'32'结果应该是3232吧,并非64
简单总结下这节内容,实际项目中运用其中的概念太多了;在认识与实践的不断作用下,不断提升对JS语言的深刻认知,并为掌握并能熟练应用ES6/ES7最新语法做铺垫。。。