JavaScript学习笔记
之所以学习JS是想更清楚的了解这门语言,记得上学那会就感觉j真难学,工作了几年了一直从事后端,但偶尔也会用前端开发,这时候就会手忙脚乱, 好多东西都是默默糊糊,还有就是,我想知道这门语言真的很难学吗?抱着好奇的心态开始了一个月的学习历程,下面整理一下一个月的学习笔记.跟着<<JavaScript前端开发案例教程>>
JavaScript背景
1994年随着互联网的发展,网景公司由马克·安德森创建,主要产品就是浏览器. SUN公司就有一句名言——网络就是计算机。如果将网络看成计算机,那浏览器就是操作系统,而单个计算机的操作系统将失去意义。盖茨不愿意让Windows成为没有意义的系统。微软做到了,它迅速而果断地从别处购买了浏览器技术,并成功开发了自己的IE浏览器,IE浏览器与网景公司的浏览器展开了竞争. SUN公司当时也是微软的竞争对手. 当时网景公司浏览器需要与网页交互,需要一种新的脚本语言, SUN公司和网景他们一拍即合开发了JavaScript, 由布兰登·艾克编写. 但最后网景没能竞争过微软, 微软市场很大.为了生存Mozilla项目代码开源了, 之后又被美国在线公司收购.SUN公司也参与了这桩生意,它承诺负责销售美国在线公司不需要的网景公司的软件. 网景公司的Mozilla项目已经是个开源产品,任何人都可以浏览源代码.
一.基本语法
- 变量 标识符 关键字与保留字 let 作用域块 var 全局作用域
const
声明的是常量 - 数据类型分类 1.基本数据类型 2.复合数据类型 obj
- 数据类型转换 Boolean()函数会将任何非空字符串和非零的数值转换为true; parseInt()值转换为数值.
- 数值转换 数据转换成字符型时toString()方法
- 运算符
- 流程控制
二.数组
- 数组的创建 var arr4 = ['one', 'two', 'three', 'four'];
- 数组的访问与遍历 for ; for in; for of
- 数组的属性与方法 pop(); push();
三.函数基础
- 函数的使用方法
- 变量的作用域
- 匿名函数与闭包函数
- 函数用于封装一段完成特定功能的代码。函数用于封装一段完成特定功能的代码。相当于将一条或多条语句组成的代码块包裹起来,用户在使用时只需关心参数和返回值,就能完成特定的功能,而不用了解具体的实现. 类似于java的方法.
- 普通函数 function 函数名(参数,参数.....){表达式};
- 函数表达式 所谓函数表达式指的是将声明的函数赋值给一个变量 let 变量名= function 函数名(n1, n2) { },此时函数名不可用,只能使用变量名调用方法.
- 匿名函数指的是没有函数名称的函数,可以有效地避免全局变量的污染以及函数名的冲突问题 let 变量名= function (n1, n2) {}, 调用时 变量名(n1,n2); 自调用方式: (function (num1, num2) {return num1 + num2;})(2, 3);处理事件:document.body.onclick = function () {}; 箭头函数 (p1, p2, …, pN) => { statements }
- 回调函数 若想要函数体中某部分功能由调用者决定,此时可以使用回调函数.
- 闭包函数 在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量.
四.对象
- 面向对象思想,面向对象与面向过程的区别
- JavaScript常用内置对象的使用方法
- 自定义对象的定义和基本操作,理解构造函数的概念
- 封装、继承、多态的设计思想,理解原型链机制
- 错误的处理,如何在浏览器中调试JavaScript程序
- js中同样, 面向对象的三个特点 封装,继承和多态.
- js创建对象很简单 let 变量名 = {}; 不用提前将属性写好 而是使用时直接 变量名.属性;私有成员 构造函数中声明的成员变量, 无法在对象实例化后 , 通过对象.成员名 访问, 此时可以使用成员方法访问成员变量;
- 构造函数 实例化对象时可以给对象属赋值. 前期没有class 概念,可以通过函数实现. 例如 声明一个函数, 内部声明一个对象, 对象的属性 返回这个对象;
/*构造函数 * 用来创建对象时 给属性赋值 * */ function factory(name, age) { let obj = {}; obj.name = name; obj.age = age; return obj; } let o1 = factory('jc', 11);
-
JavaScript内置的构造函数 Object、String、Number等构造函数 使用new 创建 var obj = new Object(); var str = new String('123'); 内置就是提前给创建了构造函数,所以使用时不用自己创建构造函数
- 自定义构造函数 1.构造函数名大写 2.构造函数内 this代表刚刚创建的对象; 另外构造函数可以return 这点和java构造不一样;
function Person(name, age) { //person的自定义构造放方法 this.name = name; this.age = age; this.methodTest = function () { alert('实例化对象后,调用对象的该方法' + this.name); } } let jack = new Person('jack', 55); let ma = new Person('ma', 52); jack.methodTest(); //对象调用方法 ma.methodTest();
- class关键字 这种写法几乎和java一样的
class Dog { constructor(name, age) { //构造方法 this.name = name; //有参构造 参数赋值 this.age = age; } methodEat() { //类里面的 其它方法 console.log(this.name + " " + this.age) } } let dog = new Dog('哈士奇', 3); //有参构造 实例化对象 dog.
methodEat(); //对象调方法 , 执行对象的行动
- 构造函数 实例化对象时可以给对象属赋值. 前期没有class 概念,可以通过函数实现. 例如 声明一个函数, 内部声明一个对象, 对象的属性 返回这个对象;
-
function Person() { var name = 'Jim'; this.getName = function () { return name; }; } var p = new Person(); // 创建实例对象 pconsole.log(p.name); // 访问私有成员,输出结果:undefinedp.getName(); // 访问对外开放的成员,输出结果:Jim
- 函数中的this指向
- 使用new关键字将函数作为构造函数调用时,构造函数内部的this指向新创建的对象。
- 直接通过函数名调用函数时,this指向的是全局对象(在浏览器中表示window对象)。
function foo() { return this; } var o = {name: 'Jim', func: foo}; console.log(foo() === window); // 输出结果:true console.log(o.func() === o); // 如果将函数作为对象的方法调用,this将会指向该对象。输出结果:true
-
如果将函数作为对象的方法调用,this将会指向该对象。
- 内置对象
- String对象 利用一对单引号或双引号创建的字符型数据,可以像对象一样使用;
- Number对象 用于处理整数、浮点数等数值,常用的属性和方法, toFixed()....
- Math对象 用于对数值进行数学运算,与其他对象不同的是,该对象不是一个构造函数,不需要实例化就能使用; var num = 10.88; Math.ceil(num); //结果是11; 有些类似于java的静态方法无需实例化 类名.方法名 直接调用.
- Date对象
- 原型与继承 难点
- 类.prototype.方法名/属性名 = function(); 为一个类创建原型方法, 实例化的对象默认带有此方法/属性.
- 静态成员 静态成员指由构造函数所使用的成员,与之相对的是由构造函数创建的对象所使用的实例成员。与java几乎一样的使用方式类.静态方法名 ,类.静态成员变量
function Person(name){ this.name = name; this.smile = function (){ console.log(this.name) } } //添加静态成员 Person.age = 19; Person.smile2 = function (){ console.log(this.age) } console.log(Person.age); //使用静态属性 Person.smile2(); //使用静态方法 let person = new Person('hello'); console.log(person.name); //实例成员name person.smile(); //实例方法
- 属性搜索原则 当对象访问某一个属性的时候,首先会在当前对象中搜索是否包含该成员,如果包含则使用,如果不包含,就会自动在其原型对象中查找是否有这个成员,这就是属性搜索原则。在搜索属性时,如果当前对象没有,原型对象中也没有,就会寻找原型对象的原型对象,一直找下去。如果直到最后都找到,就会返回undefined
console.log('---------属性搜索原则-------------'); function Pig() { this.name = '猪大肠'; } Pig.prototype.name = '猪九转'; let pig = new Pig(); console.log(pig.name); //输出:猪大肠 先查找成员, 然后查找原型里 delete pig.name;// 删除成员 console.log(pig.name); //输出:猪九转 delete Pig.prototype.name;// 删除原型 console.log(pig.name); //输出:undefined
- 原型链 对象有原型对象,原型对象也有原型对象,这就形成了一个链式结构,简称原型链。
- 1.对象的构造函数 在原型对象中,存在一个constructor属性,指向该对象的构造函数
function Person1() {} console.log(Person1.prototype.constructor === Person1);// 返回结果:true console.log(new Person1().constructor === Person1);// 返回结果:true
- 2.对象的原型对象 由于对象可以通过constructor属性访问构造函数,构造函数可以通过prototype属性访问原型对象,因此使用“对象.constructor.prototype”的方式即可访问对象的原型对象
-
View Code
- 3.函数的构造函数 由于函数本质上就是对象,所以函数也有构造函数。在 JavaScript 中,自定义函数以及String、Number、Object等内置构造函数的构造函数都是Function函数,而Function函数的构造函数是Function自身。通过toString()方法可以查看函数的信息
console.log('--- 3.函数的构造函数---'); function Person2() {} console.log(Person2.constructor.toString()) //function Function() { [native code] } console.log(Person.constructor === Function) //true console.log(String.constructor === Function) //true console.log(Object.constructor === Function) //true
-
- 4.原型对象的原型对象 访问对象的原型对象可以使用“对象.constructor.prototype”。由于构造函数的prototype属性指向原型对象,原型对象的constructor属性又指回了构造函数,这就构成了一个循环。因此,通过这种方式无法访问到原型对象的原型对象。
console.log('--- 4.原型对象的原型对象---'); function Person3() {} console.log(new Person3().__proto__ === Person3.prototype);//true console.log(Person3.prototype.__proto__ === Object.prototype);//true //继续访问 Object.prototype 的原型对象,则结果为 null console.log(Object.prototype.__proto__);//true //另一方面,构造函数 Object的原型对象是构造函数Function的原型对象 console.log(Object.__proto__ === Function.prototype);//true
- 5.原型链的结构
- ① 自定义函数,以及Object、String、Number等内置函数,都是由 Function 函数创建的, Function函数是由Function函数自身创建的。
- ② 每个构造函数都有一个原型对象,构造函数通过prototype属性指向原型对象,原型对象通过constructor属性指向构造函数。
- ③ 由构造函数创建的实例对象,继承自构造函数的原型对象。通过实例对象的__proto__属性可以直接访问原型对象。
- ④ 构造函数的原型对象,继承自Object的原型对象,而Object的原型对象的__proto__属性为null。
-
- 对象.constructor.prototype”访问到的是该对象当前继承的原型对象的构造函数的原型对象,并不一定是实际构造函数的原型对象
function Person6() { } function Func() { } Person6.prototype = new Func(); var p1 = new Person6(); p1.constructor === Func;// 返回结果:true p1.constructor.prototype === Func.prototype; // 返回结果:true p1.__proto__ === Person6.prototype; // 返回结果:true /* *通过比较可以看出,在更改了构造函数Person的prototype属性后, * 新创建的对象p1继承的原型对象是构造函数Func的实例对象,因此 * 通过p1.constructor访问到的是构造函数Func,而不是p1的实际 * 构造函数Person。在这种情况下,使用p1.__proto__访问到的才 * 是实际构造函数Person的原型对象。 * * instanceof 运算符用来检测一个对象的原型链中是否含有某个构 * 造函数的prototype属性所表示的对象,如果存在返回true * */ function Person() { } var p11 = new Person(); console.log(p11 instanceof Person); // 输出结果:true
- 4.原型对象的原型对象 访问对象的原型对象可以使用“对象.constructor.prototype”。由于构造函数的prototype属性指向原型对象,原型对象的constructor属性又指回了构造函数,这就构成了一个循环。因此,通过这种方式无法访问到原型对象的原型对象。
- 继承
- 1.利用原型对象实现继承: 原型对象是 JavaScript 实现继承的传统方式。如果一个对象中本来没有某个属性或方法,但是可以从另一个对象中获得,就实现了继承
function Person3(name) { //1.利用原型对象实现继承 this.name = name; } Person3.prototype.sayHello = function () { console.log('你好,我是' + this.name); } let p11 = new Person3('Jim'); let p22 = new Person3('Tom'); p11.sayHello(); p22.sayHello();
- 2.替换原型对象实现继承:可以将构造函数的原型对象替换成另一个对象A,基于该构造函数创建的对象就会继承新的原型对象; 和1不同的是1是类.prototype.方法名, 而2是类.prototype = 对象
function Person4() { } // 构造函数Person原本有一个原型对象 Person4.prototype = { // 将构造函数的prototype属性指向一个新的对象 sayHello: function () { // 在新的对象中定义一个sayHello()方法用于测试 console.log('你好,我是新对象'); } } let p = new Person4(); p.sayHello(); // 输出结果:你好,我是新对象
- 3.利用Object.create()实现继承:
let obj3 = { sayHello: function () { console.log('我是一个带有sayHello方法的对象'); } }; let newObj = Object.create(obj3); newObj.sayHello();
-
4.混入继承: 混入就是将一个对象的成员加入到另一个对象中,实现对象功能的扩展。实现混入继承最简单的方法就是将一个对象的成员赋值给另一个对象. java只有 extends实现类与类之间的继承, 或者间接的使用implement 实现接口实现继承, js有继承方式有点多而且不易记忆;
var o11 = {}; var o12 = {name: 'Jim ma'}; o11.name = o12.name; console.log(o11.name);
当对象的成员比较多时,属性赋值.
function extend(o1, o2) { for (var k in o2) { o1[k] = o2[k]; } } let sonObj = {name: '小明'}; //对象1 let fatherObj = {age: 17, sex: '男'};//对象2 extend(sonObj, fatherObj); //将fatherObj对象属性值赋值给sonObj console.log(sonObj.name + sonObj.age + sonObj.sex);
混入式继承和原型继承还可以组合在一起使用,实现以对象的方式传递参数,或以对象的方式扩展原型对象的成员
function Cat(o){ extendMethod(this, o); } Cat.fn = Cat.prototype; Cat.fn.extendMethod = function (obj) { extendMethod(this, obj); } Cat.fn.extendMethod({ eat: function () { console.log((this.name||'谁?') +'---' + '吃'); } }); function extendMethod(o1, o2) { for (var k in o2) { o1[k] = o2[k]; } } let cat = new Cat(); let mimi = new Cat({name: '咪咪', age: 2}); cat.eat();//谁?---吃 mimi.eat();//咪咪---吃
- 1.利用原型对象实现继承: 原型对象是 JavaScript 实现继承的传统方式。如果一个对象中本来没有某个属性或方法,但是可以从另一个对象中获得,就实现了继承
五.BOM
- 由于window对象是BOM中所有对象的核心,同时也是BOM中所有对象的父对象。所以定义在全局作用域中的变量、函数以及JavaScript中的内置函数都可以被window对象调用
- setTimeout() 可以在一个固定时间段内执行JavaScript程序代码, setInterval() 指定的时间后,自动重复执行代码
- history 对象
- navigator对象
- screen对象
六.DOM
- 元素与样式的操作
- 文档节点的操作
- 简介 DOM(Document Object Model,文档对象模型)可以用于完成HTML和XML文档的操作。其中,在JavaScript中利用DOM操作HTML元素和CSS样式则是最常用的功能之一.
七.事件
- 事件的绑定方式
- 事件对象的使用
- 常用事件的实现
- 简介 事件被看作是JavaScript与网页之间交互的桥梁,当事件发生时,可以通过JavaScript代码执行相关的操作。
- 事件流 事件发生时,会在发生事件的元素节点与DOM树根节点之间按照特定的顺序进行传播,这个事件传播的过程就是事件流。网景(Netscape)和微软(Microsoft)IE 浏览器对于事件流的传播顺序,提供了两种不同的解决方案
- 事件捕获方式(网景),它指的是事件流传播的顺序应该是从 DOM 树的根节点到发生事件的元素节点
- 事件冒泡方式(微软),它指的是事件流传播的顺序应该是从发生事件的元素节点到DOM树的根节点
- W3C对网景和微软提出的方案进行了中和处理,规定了事件发生后,首先实现事件捕获,但不会对事件进行处理;然后进行到目标阶段,执行当前元素对象的事件处理程序,但它会被看成是冒泡阶段的一部分;最后实现事件的冒泡,逐级对事件进行处理
- 绑定方式
- 1.行内绑定式 <标签名 事件="事件的处理程序">
- 2.动态绑定式 DOM元素对象.事件 = 事件的处理程序;
- 3.事件监听 给同一个DOM对象的同一个事件添加多个事件处理程序,DOM2级事件模型中引入了事件流的概念,可以让DOM对象通过事件监听的方式实现事件的绑定。
- 事件对象 当发生事件时,都会产生一个事件对象event,这个对象中包含着所有与事件相关的信息,包括发生事件的DOM元素、事件的类型以及其他与特定事件相关的信息
- 阻止事件冒泡 事件的响应像水泡一样上升至最顶级对象,因此把这个过程称之为“事件冒泡” stopPropagation()
- window.onload = function () { } 当HTML文本全部加载到浏览器中时,才会触发load事件
- 焦点事件 onblur失焦点触发
- 鼠标事件
八.Ajax
- Ajax和HTTP的基本概念
- Ajax对象的创建、常用方法和属性的使用
- XML和JSON数据格式的使用
- Cookie操作和Ajax跨域请求
- 简介 Ajax是Asynchronous JavaScript And XML的缩写,即异步JavaScript和XML技术。它并不是一门新的语言或技术,而是由JavaScript、XML、DOM、CSS等多种已有技术组合而成的一种浏览器端技术,用于实现与服务器进行异步交互的功能。
- 创建Ajax对象 new XMLHttpRequest();
- open()方法 创建一个新的HTTP请求,并指定请求方式、请求URL等
- setRequestHeader()方法 用于单独指定某个HTTP请求头
- send()方法 方法用于发送请求到Web服务器并接收响应。
- 处理服务器返回的信息
- readyState属性 属性用于获取Ajax的当前状态,状态值有5种形式
- onreadystatechange属性用于感知readyState属性状态的改变,每当readyState的值发生改变时,就会调用此事件
- status属性用于返回当前请求的HTTP状态码,值为数值类型。
-
数据交换格式 在进行前后端应用程序的数据交换时,需要约定一种格式,确保通信双方都能够正确识别对方发送的信息。目前比较通用的数据交换格式有XML和JSON
- 跨域请求 端口 域名 协议 符合任意一个就要跨域
- WebSocket 实现了全双工通信,在建立连接后,服务器可以将新消息主动推送给客户端,这种方式实时性更强,效率更高。
九.jQuery
- 元素的与文档节点的操作
- 事件与动画特效的实现
- jQuery中插件机制的使用
- 简介 Query 是一款优秀的 JavaScript 框架库,它通过 JavaScript 的函数封装,简化了HTML 与JavaScript之间的操作,使得DOM对象、事件处理、动画效果、Ajax等操作的实现语法更加简洁,同时提高了程序的开发效率,消除很多跨浏览器的兼容问题。
- 元素操作
- 基本选择器
- 层级选择器
- 基本过滤选择器
- 内容选择器
- 可见性选择器
- 属性选择器
- 子元素选择器 $("span:first-child") 获取<span>元素的第1个子元素
- 表单选择器
- 操作元素内容的方法,主要包括html()和text()方法。html()方法用于获取或设置元素的HTML内容,text()方法用于获取或设置元素的文本内容
- 元素样式
- 元素筛选
- 元素属性 基本属性操作 class属性操作
- 文档节点操作
- 节点追加
- 节点替换
- 节点删除
- 节点复制
- 事件操作 表单事件、鼠标事件、键盘事件以及页面加载事件等
- 动画特效
- jQuery操作Ajax
$.ajax( url, { data: user, success: function (s) {// 请求成功后执行的函数 $('p')[0].innerText = s; } }, );