JavaScript
ECMAScript
NaN不等于任何东西,包括自己。
JS数据类型
(原始值和引用值)其中原始值包括:number, string, boolean, undefined, null,引用值包括:array, object, function
逻辑运算符:&& || !
1、&&(与):先看第一表达式转换成布尔值的结果,如果结果为真,那么会看第二个表达式转换为布尔值的结果,然后如果两个表达式的化,只看到第二个表达式,就可以返回该表达式的值了。以此类推。在充当判断条件时,可称为并且。
var a = 1 && 2;
document.write(a);
2
//undefined, null, NaN, "", 0, false
从第一个开始遇到值为false的表达式,则返回表达式本身,否则返回最后一个表达式
2、||(或):碰到真则停。
var num = 0 || 3;
document.write(num);
3
3、!(非):对目标的布尔值取反。
if语句
基础语法:if(<条件>){######}else if{#####}else{#####}
在使用else if时,<条件>必须互斥。
如:
var score = parseInt(window.prompt('input'))
if(score > 90 && score < 100){
document.write('alibaba');
}else if(score > 80 && score < 90){
document.write('tencent');
}else{
document.write('11111');
}
循环语句
for循环:for(<1>;<跳出条件>;<执行语句>){}其中<1>可放到for前面,<执行语句>可放到{}里。
如:
for(var i = 1; i < 10; i ++){
//省略
}
while循环:while(<条件>){<执行条件>}( 同for循环类似用法)。
如:
var i = 0;
while(i < 100){
if(i % 7 == 0 || i % 10 == 7):
document.write(i + " ");
i ++;
}
do···while循环:没卵用。
条件语句补充
switch case:switch(条件){case <判断>}
当执行成功后,后边的语句会继续执行,可用break来跳出循环。
如:
var n = 3;
switch(n){
case 1:
console.log('a');
break;
case 2:
console.log('b');
case 3:
console.log('c');
}
break:终止循环。
continue:终止此次循环,执行下次循环。
初识引用值
数组(arr):用中括号表示[变量, 变量, 变量······]
长度用arr.length来表示。
对象(object):
如:var obj = {
lastName : “111”;
}
**typeof:**可用来判断变量的类型,可用来返回number, string, boolean, object, undefined, function。
用法:typeof(变量)或typeof 变量,typeof判断未声明的变量并不会报错,返回undefined
typeof(null)返回object
类型转换
类型转换一般没有特别强调都转换为数字,若无法转为数字则转为NaN
除+以外,其余均会把符号两侧的变量转化为数字类型
1、Number(mix)将目标转化为数字类型。
2、parseInt(string, “num”),以目标数字为基底转化为十进制。
3、parseFloat(string)将目标转化为浮点型数字。
4、toString,用法···.toString(),undefined和null不可用。数据.toString(n), 将num转化为n进制数并转换为字符串。
5、String(),将目标转化为字符串。
6、Boolean()转换位布尔类型。
7、isNaN(),判断数据是否为NaN,执行过程为先对数据进行Number()操作,然后将执行后的数据跟NaN进行对比看是否相同。
function(函数)
创建方式:
1、function name(形式参数){};
2、var test = function(形式参数){};又叫函数表达式。
3、var test = function name(形式参数){}; 其中name为test函数的别名,可用test.name进行打印;
调用方法:
test(实际参数)
形参的定义大致同变量的定义(var name)是一个意思。
return:a、终止函数;b、返回值。
str.charAt(num)可用来选择字符串中的某位字符。
str.charcodeAt(num)可以返回字符串中某位字符在ASCII码中的序号,若序号小于等于255则其字节长度为1,否则其字节长度为2。
function mul(n) {
//n的阶乘
if (n == 0) {
return 1;
}
return n * mul(n - 1);
}
function fb(n) {
//斐波那契数列
//fb(n) = fb(n-1) + fb(n-2)
if (n == 1 || n == 2) {
return 1;
}
return fb(n - 1) + fb(n - 2);
}
作用域
当出现嵌套函数的时候,内部函数可以访问外部函数,但外部函数不可以访问内部函数。
预编译(JS的特点:单线程、解释性语言)
//函数声明整体提升:即构建的函数会提升到逻辑的最前边
//变量声明提升
1、暗示全局变量:imply global,即如果变量未经声明就赋值,则该变量就为全局对象所有。
2、一切声明的全局变量,都是window的属性。
预编译过程(预编译发生在函数执行的前一刻/同时发生在全局(区别为全局创建的叫GO(Global Object)对象==window,同AO对象一样))
1、创建AO对象(Active Object)(即执行期上下文)
2、找形参和变量声明,值为undefined
3、将实参值和形参值统一
4、在函数体里找函数声明,值赋予函数体
例:
function fn(a){
console.log(a);
var a = 123;
console.log(a);
function a(){
}
console.log(a);
var b = function(){
}
console.log(b);
function d(){
}
}
fn(1);
//输出为function, 123, 123, function即函数fn中的function a(){}提升到前边
作用域精解
AO数据即时的存储空间,在每次函数执行完成后会被删除
[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合
查找变量时从作用域链的顶端依次向下查找。
例:
function a(){
function b(){
}
}
var glob = 100;
a();
//当函数执行时,所产生的AO放在作用域链的最顶端,在使用嵌套函数的时候子函数跟父函数使用的是同一个AO,不过在调用子函数的过程中,将AO的引用指向子函数,在子函数执行完后,AO重新指向父函数
闭包
当内部函数被保存到外部时,会产生闭包,闭包会导致原有作用域链不释放,造成内存泄漏。
例:
function a(){
function b(){
var bbb = 234;
console.log(aaa);
}
var aaa = 123;
return b;
}
var glob = 100;
var demo = a();
demo();
内存泄漏:即占用内存多了之后,剩余内存减小
闭包的作用:
1、实现公有变量,如:函数累加器
function add() {
var count = 0;
function demo() {
count++;
return count;
}
return demo;
}
var counter = add();
counter();
2、可以做缓存(存储结构)
function eater(){
var food = "";
var obj = {
eat : function(){
console.log("I am eating " + food)
}
push : function(myfood){
food = myfood;
}
}
return obj;
}
var eater1 = eater();
eater1.push('banana');
eater1.eat();
3、可以实现封装,属性私有化
function Deng(){
var prepareWife = "xiaozhang";
this.name = wife;
this.divorce = function(){
this.wife = prepareWife;
}
this.changePrepareWife = function(target){
prepareWife = target;
}
this.sayPrepareWife = function(){
console.log(prepareWife);
}
}
var deng = new Deng();
//利用deng.prepareWife无法访问到“xiaozhang”
4、模块化开发,防止污染全局变量(命名空间)
闭包在定义过程中不会去访问所要保存的函数体内部的内容,只有在执行的时候才会去访问其函数内部结构。
如:
function test(){
var arr = [];
for(var a = 0; i < 10; i ++){
arr[i] = function b(){
document.write(i + " ");
}
}
return arr;
}
for(var i = 0; i < arr.length; i ++){
arr[i]();
}
立即执行函数
仅执行一次便释放空间的函数即为立即执行函数。
创建方式
1、(function(){}())
2、(function(){})()
一般建议使用第一种,立即执行函数的原理同(1 + 2)* 3中括号的作用类似,即利用()的作用来实现执行符号(即函数后边的括号)对函数的调用。
对象(Object)
对象的创建方法:
1、var obj = {} plainObject 对象字面量/对象直接量
2、构造函数
1) 系统自带的构造函数 Object
2) 自定义
如:var obj = new Object();
在使用构造函数创建对象的时,也可通过传形参的形式直接给对象的属性进行赋值。
构造函数自定义采用大驼峰式写法:即每个单词的首字母都用大写字母。
如:function Person(){}
function Car(){
this.name = "BMW";
this.heigth = "1400";
this.lang = "4900";
this.weight = 1000;
this.health = 100;
this.run = function(){
this.health --;
}
}
var car = new Car();
对象属性的修改通过obj. = 来进行修改
对象属性的删除可通过delete obj.
在对象内部修改属性值时可用this. = value来实现
注:在向对象的属性传值时,尽量采用单引号。
构造函数内部原理
1、在函数体最前面隐式的加上this = {};(即var this = {})
2、执行this.xxx = xxx;(即this = {xxx: xxx})
3、隐式的返回this;(即return this)
包装类:使用new创建的数字或字符串、布尔类型数据不仅可当数字或字符串使用,还拥有对象的功能,可以增加属性。
new Number();new String();new Boolean()。
原型
1、原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法,原型也是对象。
原型也是对象即通过<构造函数名>.prototype所打印出的为对象,而用<构造函数名>.prototype.<属性名>打印出来的为原型的属性值。
2、利用原型的特点,可以提取公有属性。
3、注:原型创建后自带constructor属性,其属性值为构造函数名,利用这个属性,可以查看子对象的父类,
4、原型中还会自带一个__proto__属性,这个属性是用来存储对象的原型,子对象可通过该属性替换父对象,即子对象的__proto__指向父对象的prototype,如person.proto = <构造函数名>。
原型的创建方法,<构造函数名>.prototype.<属性名> = “<属性值>”
也可利用对象赋值方式对原型进行属性赋值
如:Person.prototype = {}
构造函数产生的子对象也可以调用其祖先的原型。
如:
Person.prototype.LastName = "Deng";
Person.prototype.say = function(){
console.log("hehe");
}
function Person(name, age, sex){
this.name = name;
this.age = age;
this.sex = sex;
}
var person = new Person('xuming', 35, 'male');
console.log(preson.LastName);
输出结果:Deng
例题:
Person.prototype.name = 'sunny';
function Person(){
}
var person = new Person();
Person.prototype = {
name : 'cherry';
}
console.log(person.name);
//输出为sunny
Person.prototype.name = 'sunny';
function Person(){
}
var person = new Person();
Person.prototype.name = 'cherry';
console.log(person.name);
//输出为cherry
题解:在1中,person对象创建后通过Person.prototype = {name = ‘cherry’}相当于将其原型指向了另外一个空间,而在2中,通过Person.prototype.name = 'cherry’是在原对象的原型属性中进行修改,所以创建的对象也会跟着修改。
其思路同以下代码类似:
obj = {
name : 'a'}
obj1 = obj;
obj.name = 'b'/obj = {
name : 'b'}
原型链
原型连原型再连原型生成的链式结构即为原型链,通过prototype连接,所有对象的最终原型为Object