js学习笔记

js数据类型

  • Number

1.包括:-1,0,1,0.111,NaN
2.NaN:(Not a Number)可以理解为你就不是一个男人(实质上就是一个男人)。
isNaN()方法来检测一个值是不是NaN,为true则不是常规数字,否则为数字[传入的值不是number类型的会将其先转换为number类型,然后判断]
NaN==NaN:false,NaN和任何其他值都不想等*
3.转换方法
Number(),Number(undefined)=NaN,Number(null)=0,Number(false)=0, Number(true)=1,转换过程是将传入参数转换成String类型,然后在转换成Number类型
parseInt(),不同于Number()的是,传入参数第一个字符为非有效数字字符才会返回NaN,从左到右依次查找有效的数字字符,直到遇到第一个非数字字符,然后将找到的数字字符进行转换
parseFloat(),在parseInt的基础上识别小数点

  • String

使用""或''包裹起来的都是字符串类型
常用方法:charAt,charCodeAt,indexOf,lastIndexOf,toUpper,toLower,subStr,subString,
split,replace,slice

  • Boolean

Boolean():js提供该方法将其他数据类型转换为布尔类型,依照以下规则
只有null,空字符串,0,undefined,NaN这五个数据指会被转换为false
!:自动将值转换为Boolean类型然后进行取反操作

  • Null 和 undefined

通常来说null为初始值预期后续会给赋值,而undefined为预料之外的情况

  • Object

每个对象都是有零到多组属性名(key键):属性值(值)的键值对组成的,每一组键值对之间以,隔开。对于引用类型来说,首先在内存栈中开辟一个空间标记为变量名,然后在内存堆中以键值对的形式存储起来,然后将内存堆中的内存地址存储在内存栈中标记为变量名的空间中。
var obj={name:'kerry',age:22}
获取/添加/修改对象属性:obj.kerry或obj['kerry'],obj.sex='male',obj.age=18
移除属性假删除设置属性为nullobj.kerry=null,真删除delete obj.kerry
注意:obj[]中可以使用表达式或者变量,引用表达式或变量是使用其真实的值
obj['a'+'b']="hello":给obj添加一个ab的属性,并为其赋值为hello

  • Function

Function类型也是引用类型,但是在内存堆中是以字符串的形式存储的
执行:函数的执行是以函数名加一对小括号的形式执行。函数的执行其本质是执行函数中的代码块。任何js代码执行都是有自己的执行环境,最基础的执行环境是Window(全局作用域),但是对于函数内部的代码块来说,它们的执行环境是浏览器为这个函数分配的一个私有的环境(私有作用域)
形参:函数提供参数作为入口来供调用时候从这个入口把值传进来,这个参数就叫做形参,只是一个变量,不具有实际的意义。
实参:在调用函数的时候传递给函数的值,是一个具体的实际的值,形参是用来接收实参的。


js检测类型的四种方法

  • typeof:返回结果是一个字符串,字符串内容就是当前检测对象的类型

局限性:
1. typeof null返回结果是"object"而不是"null",因为null虽然是一个单独的数据类型,但是null指的却是空对象指针
2. typeof无法检测具体到底是date还是正则还是数组,返回的都是object

  • instanceof:检测一个实例是否属于这个类,可以做到typeof无法做到的具体类型
function Fn(){}
var fn=new Fn; 
console.log(fn instanceof Fn)//true
  • constructor:构造函数,任何一个js对象(可能是个function,可能是个实例)都具有一个constructor属性,该属性指向的是构造当前对象的函数引用
Object.constructor //Function
Function.constructor //Function
Array.constructor //Array
"".constructor //String
new Fn().constructor //Fn

浏览器执行JS脚本顺序

1.当浏览器加载JS代码的时候,首先会提供一个供全局JS代码执行的环境->全局作用域(window/global)
2. 进行预解释,预解释 在当前的作用域中,JS代码执行之前,浏览器首先会默认的把所有带varfunction的进行提前的声明或定义

1).声明和定义:var num=12;
声明(declare) var num;告诉浏览器在全局作用域中有一个新的变量num
定义(defined) num=12;给声明的变量num赋值
2).对于var和function关键字,在预解释的时候是不一样的操作
var 在预解释的时候只是提前的声明
function 在预解释的时候提前的声明和定义都完成了
3).预解释只是在当前作用域下发生,预解释也叫变量提升
4).因为js存在预解释的行为,所以以下代码是始终输出undefined的
if(!("num" in window)){ //判断是否存在全局变量num,不存在声明全局变量并赋值
var num=1;
}
console.log(num);
5).预解释的时候只是预解释"="左边的声明部分,右边的是值,不参与预解释,所以以下代码会报错。匿名函数之函数表达式:把函数定义的部分当作一个值赋值给变量
fn(); //fn只是提前预解释,被声明,但是fn的值此时是undefined,所以报错fn不是一个function
var fn=function(){
console.log(1);
}
6).预解释的时候,只会声明一次,对声明过的变量不会再次声明,自执行函数不会进行预解释。
1. fn();//2
2. function fn(){console.log(1);};
3. fn();//2
4. var fn=10;
5. fn();//报错,fn is not a function
6. function fn(){console.log(2);};
7. fn();//不执行
执行顺序
1.预解释+定义第2行
2.因为已经声明过了不会重复声明,所以第4行不会预解释
3.同样,因为已经声明过了fn,所以第6行不会重复声明,但是会重新定义fn


函数执行顺序

1.形成一个独属于当前函数的私有的作用
2.如果函数有形参,给形参赋值
3.进行当前函数的私有作用域的预解释
4.当前私有作用域的代码由上至下执行

闭包:是一种机制函数形成的一个私有的作用域保护了里边的私有变量不受外界干扰,这种保护机制就叫做闭包


对象创建方式

  • 字面量方式,var obj={}
  • 构造函数方式,var obj=new Object()
  • Object.create(proto,[propertiesObject]),创建一个拥有指定原型和若干指定属性的对象,proto作为新创建对象的原型
    image.png

函数作用域链

1.函数在执行的时候形成一个作用域,作用域始终在栈内存中,函数每执行依次,就形成一个新的作用域
2.如何查找当前作用域的上一级作用域:
看当前函数是在哪一个作用域中定义的,那么它的上一级作用域就是那个作用域,和函数在哪个作用域执行无关。以下代码结果都是输出120。

var num=12;
function fn(){
    var num=120;
    return function(){
        console.log(num);
    }
}
var f=fn();
f();
//自执行函数
(function(){
    var num=1200;
    f();
})();

闭包

闭包:函数中的函数实现外层函数中的变量不释放,如下例:

function a(){                             function a(){
  var i=1;                                   var i=1;
  function b(){                              function b(){
    console.log(i++);                           console.log(i++);
  }                                          }
  b();                                       return b
}                                         }

上述左侧代码,每一次执行a(),都会打印出1,那么想要打印出持续增长的i怎么办呢,采用右侧代码的方式,var c=a();c();c();c(),执行a()创建一个属于a的作用域,在这个作用域中定义了一个变量i,得到一个function b,将其赋值给c,执行c(),创建一个属于c的作用域,c的作用域仅仅执行console.log(i++),当前作用域没有i的定义,那就去上级作用域a中找,以此实现的a中的变量i不释放,就叫做闭包

this

定义:JS中的this代表的是当前行为执行的主体。和函数在哪定义的在哪执行的都没有任何关系。
规律:

  • 1.函数执行,看函数前边是否有".",有的话,"."前面是谁,this就是谁,没有的话就是window
   function fn(){ console.log(this);}
   var obj={fn:fn};
   function sum(){ fn();};
   fn(); //=>window
   obj.fn(); //=>objw
   sum(); //=>window
  • 2.自执行函数中的this永远是window
  • 3.给元素的某一个事件绑定方法,采用元素属性定义的事件,this是window,采用js的on注册的事件,this就是当前元素
  • 4.在构造函数模式中new,当前类(函数)作用域内的this指向的是当前类的实例

练习题:

var num=20;
var obj={
    num:30,
    fn:(function(num){
        this.num * = 3;
        num+=15;
        var num=45;
        return function(){
            this.num *= 4;
            num+=20;
            console.log(num);
        }
    })()
};
var fn=obj.fn;
fn();
obj.fn(); 

构造函数模式

构造函数模式不同于普通函数模式,在于构造函数模式是通过new FunctionName执行,而普通函数是functionName()来执行,对于使用new关键字,我们认为是FunctionName一个类,但是它本质上还是一个函数,并且对于类习惯首字母大写。new FunctionName返回的结果,是FunctionName这个类的一个实例。
异同
相同:都是形成一个私有的作用域,然后进行 形参复制->与解释->顺序执行 的过程
不同:普通函数的执行如果需要得到一个对象,需要使用诸如字面量{}的方式创建一个对象并返回;而构造函数模式的类不同,在new的时候,浏览器会在这个作用域里创建一个该类的当前实例,在这里this指向这个默认的实例。并会忽略return的值

 function person(name,age){
     var obj={};
     obj.name=name;
     obj.age=age;
     return obj;//如果没有明确返回,那么不会得到任何对象
}
function Person(name,age){
     this.name=name;
     this.age=age;
}

原型模式

基于构造函数的原型模式解决了方法或者属性公有的问题,把实例之间相同的属性和方法提取到类的prototype上即可
1.每一个函数数据类型(普通函数、类)都有一个天生自带的属性:prototype(原型),用于存放该类共有的一些属性,prototype是一个对象数据类型的值
2.在prototype上浏览器给它附加了一个属性constructor(构造函数),值是当前函数(类)本身
3.每一个对象数据类型(普通的对象、实例~~~)也天生自带一个属性:__proto__,值是当前实例所属类型的原型(prototype)

上例中var per=new Person('kerry',18),per instanceof Object=true原因:per是一个实例,per.proto指向per所属类型(Person)的原型prototype,prototype是一个Object类型的实例,prototype.proto指向prototype所属类型(Object)的原型prototype,per.__proto__===Person.prototype Person.prototype.__proto__==Object.prototype

对象.属性通过以下流程查找:


image.png

image.png

原型链继承

通过原型模式一级级指定类型原型来实现

function Parent(){}
function Child(){}
Child.prototype=new Parent() //通过指定类型Prototype来实现继承
var c=new Child()
c.__proto__=Child.prototype
Child.prototype.__proto__=Parent.prototype

原型链工作模式:
如上例,想要在c中查找一个属性,需要如下步骤

  • 1.首先在c自身查找,找不到,进入下一步
  • 2.在c.__proto__中查找,而c.__proto__指向的是所属类型Child的原型Child.prototype,还找不到,进入下一步
  • 3.在Child.prototype.__proto__中查找,而Child.prototype=new Parent(),实质就是在Parent实例p的__proto__查找,而p.__proto__=Parent.prototype,还找不到,进入下一步
  • 4.在Parent.prototype.__proto__查找,而Parent.prototype是一个Object类对象,所以它的__proto__最终指向所属类型Object的原型

Call继承

原理:把父类私有的变成子类私有的,与父类隔离开,示例如下

function Parent(){ this.x=100; }
function Child(){}
var c=new Child();
console.log(c.x);//undefined 
Parent.call(c);
console.log(c.x);//100

第一遍输出c.x的时候,因为在c中找不到x,所以输出undefined;
执行了Parent.call(c),意思是:执行new一个Parent的实例,并将其中的this赋值为c;
第二遍输出c.x,因为在new一个Parent实例的时候已经执行了this.x=100了,所以可以输出100

Apply

用法基本等同于Call,function.apply(obj,arguments),执行function函数,并将其中的this指向obj,不同于call的是function的若干个参数通过一个数组arguments传递,而call是通过function.call(obj,argument1,argument2,argument3)逐个传递参数

JS操作DOM

向一个ul列表中追加li元素
1.拼接DOM元素(dom结构发生10次变化)

for(var i=0;i<10;i++){
    var li=document.createElement("li")
    li.innerText=i;
    ul.appendChild(li)
}

2.通过innerHtml追加(dom结构发生一次变化,但是会影响原有的ul内部结构)

var html="";
for(var i=0;i<10;i++){
    html+="<li>"+i+"</li>"
}
ul.innerHtml=html;

3.文档碎片(最好的方式,只发生一次dom结构变化,并且不会影响原有的ul内部结构)

var frg=document.createDocumentFragment();
for(var i=0;i<10;i++){
    var li=document.createElement("li");
    li.innerText=i;
    frg.appendChild(frg);
}
ul.appendChild(frg);
frg=null    //需要注意手动释放堆内存

回流:在dom操作中,如果dom结构发生变更(增加、删除、调整位置),浏览器都需要重新计算dom结构,然后重新构造dom树,重新绘制页面,(DOM操作十分耗性能
重绘:当某个元素的样式发生变化(颜色、字体等)会重新绘制这个元素

DOM映射机制

猜猜下边代码执行完页面还有几个元素

<html>
  <body>
  <ul><li>3</li><li>2</li><li>4</li><li>1</li></ul>
  </body>
</html>
<script type="javascript">
var lis=document.getElementsByTagName("li")
lis.sort(function(a,b){
  return int.parse(a.innerText)-int.parse(b.innerText);
})
var frg=document.createDocumentFragment();
for(var i=0;i<lis.length;i++){
  frg.appendChild(lis[i]);
}
document.getElementsByTagName("ul")[0].appendChild(frg);
frg=null;
</script>

页面还是原来的四个li,为什么呢,DOM映射机制,什么是DOM映射机制呢?

页面中的HTML标签和JS中获取刀的对象(单个元素或元素集合)是绑定在一起,一一对应的,页面中的元素的结构或属性变了,js中不需要重新获取元素,对象也会跟着变化。同样,js中改变了元素的结构或属性,HTML中的元素也会跟着变化。

Class

ES6中的Class关键字用于创建一个类,作用等同于构造函数,但是class不同于function的是不会声明提升。

class Person{
    constructor(name){
        super(); //通过super调用父类的构造器
        this.name=name;
    }

    instanceMethod(){
    }

    static staticMethod(){
    }
}
  • 1.constructor:类的构造器,用于创建和初始化类中创建的一个对象的一种特殊方法。new一个类的时候,会优先执行构造器函数并得到一个当前类的实例。在一个类中只能有一个constructor的特殊方法,constructor的参数用于接收new类实例传入的参数new Person('kerry')
  • 2.实例属性和方法:挂载于this上的属性或方法(通过new一个类得到的实例访问的属性或方法)叫做实例属性/方法,如name,instanceMethodinstanceMethod等同于构造函数中挂在于property上的属性/方法。
  • 3.静态属性和方法:如下,在ES5的构造函数中,直接挂载在构造函数(原型的constructor)上的属性就是静态属性。那么在class中,通常用static关键字修饰的就是类的静态属性/方法(ES6 明确规定, Class 内部只有静态方法, 没有静态属性。ES7 有一个静态属性的提案, 目前 Babel 转码器支持。),如staticMethod,可以直接通过类来访问Person.staticMethod
function Person(){}
Person.staticProperty='静态属性';
Person.property.instanceProperty='实例属性';
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,450评论 1 45
  • chapter 2 JavaScript概览 介绍 js是基于原型,面向对象, 弱类型的的动态脚本语言。 Java...
    ShallLi阅读 1,484评论 1 2
  • 未知的否认以反思 如何定义所谓的成功人士,是他的外貌,家庭背景,还是他的个人修养以及为人处世的风格?一个人怎样才能...
    小乐涵畅阅读 153评论 0 0
  • 2018-03-21 夏阳 妈妈宝宝日记 这个世界上有一种焦急叫娃生病,有一种煎熬是娃生病时的日子。有一种痛只有生...
    勤径99阅读 649评论 0 1