面向对象
section 1
- 构造函数中的this指的就是通过构造函数实例化出来的具体的某个实例对象。
- 如果构造函数显示的返回基本的数据类型,那么和不返回效果一致,都返回原来的this,就是具体的某个实例对象.
- 如果构造函数显示的返回一个对象,那么实例化出来的实例对象就是你显示返回的对象.
- 函数的本质也是引用的类型,函数的名字实质上是内存的地址。
- 原型方法里的this指的是具体的通过某个构造函数创建的实例。
- 面向对象编程
//面向对象编程
/*创建对象*/
function ChangeStyle(div,btn) {
this.div = document.querySelector(div);
this.btn = document.querySelector(btn);
}
/*在prototype下的方法是所有的实例都可以共用的*/
ChangeStyle.prototype.init = function () {
var _this = this;
this.btn.onclick = function () {
_this.div.style.width = "300px";
_this.div.style.height = "300px";
_this.div.style.backgroundColor = "cyan";
}
}
/*创建实例*/
var cs = new ChangeStyle(".box1","button");
/*共享对象的方法*/
cs.init();
section2
- 可以通过三种方式自定义函数:函数声明、函数表达式、new Function、还有一种系统提供的函数,比如Object、String、Number(主要用前两种自定义函数)。
- 通过函数声明建立的函数可以先调用再申明。
函数有三种调用方式:
普通函数(调用者(this)是window,但是在es5的严格模式中this是undefined)。
function foo(){ 'use strict' console.log(this); } foo();//ES3中,this就是window;ES5的严格模式下,this为undefined
对象方法,{}构造出来的函数也是Object的一个实例,和new Object出来的函数是等效的。
var obj = {}; obj.info = 'hello'; obj.showInfo = function(){ console.log(this.info); } foo.showInfo();//对象方法中的this就是调用方法的对象
构造函数的调用.
function Foo(info) { this.info = info; this.showInfo = function() { console.log(this.info); } } Foo.prototype.fn = function() { //原型对象中的this就是实例对象 console.log(this.info); } var foo = new Foo("hello"); foo.showInfo();//对象方法中的this就是实例对象
call apply. call和apply这两个方法都可以用来调用函数
- 作用:可以改变函数中this的指向,借用别的对象的方法。
- 差异:两者的第一个参数都是传谁this就指向谁,null表示不改变this指向,后面的函数自带的参数apply要以数组的方式传入。
调用严格模式:加上“use strict”。
function foo(a,b){ console.log(a + b); } foo.call(null,1,2); foo.apply(null,[1,2]); //改变this指向 var obj1 = { info : 'Tom' }; var obj2 = { info : 'Jerry' } window.info = 'Spike'; var showInfo = function(){ console.log(this.info); }; showInfo(); showInfo.call(obj1); showInfo.call(obj2); //调用call或apply都会自动执行对应的函数,而bind不会执行对应的函 数,只是返回了对函数的引用
- bind:也是改变this的指向,参数传谁this就指向谁(IE678不兼容)。
- 和call、apply的区别:call、apply需要调用一次函数才能改变this的指向,而bind则不用。
- 属性写在对象里,方法写在原型里。
- new到底做了什么事情?
- 在内存开辟一块存储空间,这块内存地址给了this
- 把构造函数的属性以及传递的参数放到了这块内存空间
- 把this的值返回给实例变量
- 构造函数中的this和原型中的this指向相同,都是指向实例对象。
prototype、constructor、proto之间的联系与区别
- 构造函数中都有一个原型属性prototype,该属性是引用类型.
- 原型对象中有一个属性constructor,该属性指向构造函数。
- 实例当中都有一个属性proto,该属性指向构造函数的原型prototype,改属性不是标准属性,不可以在编程中显示使用,该属性是浏览器自己使用的。
- prototype和proto之间的区别:
- 这两者都是指向同一个对象。
- prototype站在构造函数的角度来说的
- proto站在实例的角度来说的
- 函数也是对象,但是对象不一定是函数
this
A this value is a special object which is related with the execution context. Therefore, it may be named as a context object (i.e. an object in which context the execution context is activated). this是和执行上下文环境息息相关的一个特殊对象。因此,它也可以称为上下文对象(激活执行上下文的上下文)。 a this value is a property of the execution context, but not a property of the variable object. this是执行上下文环境的一个属性,而不是某个变量对象的属性。这个特点很重要,因为和变量不同,this是没有 一个类似搜寻变量的过程。当你在代码中使用了this,这个 this的值就直接从执行的上下文中获取了,而不会从作用 域链中搜寻。this的值只取决中进入上下文时的情况。
section3
高阶函数
作为参数的函数
引用类型传递的是地址,所以在函数内部对引用类型值的修改会同步
function foo(data){ // console.log(data); data.push(5); return data; } var arr = [1,2,3,4]; var ret = foo(arr); console.log(arr,ret); //都是返回[1,2,3,4,5]
基本类型传参传递的是实际的值,所以在函数内部对参数的修改不影响传递进来的参数
function foo(data){ data = 456; return data; } var d = 123; var d1 = foo(d); console.log(d,d1);
- 作为返回值的函数
函数作为参数传参,即是回调函数
```javascript
// 回调函数
var callback = function(data){console.log("通知:"+data);
}
//相当于文员
function ajax(data){//1、创建XHR对象 var xhr = new XMLHttpRequest(); //2、发送前的准备工作 xhr.open('get','http://localhost/abc.php',true); //3、执行发送动作 xhr.send(null); //4、指定回调函数 xhr.onreadystatechange = function(){ //4表示服务器端已经完全返回结果,但是数据是否正确还不确定 if(xhr.readyState === 4){ //200表示服务器返回的数据是正确的 //404表示没有找到请求的资源 //500服务器端错误 if(xhr.status === 200){ // var result = '空调坏了'; // var result = '服务器挂了'; var result = xhr.responseText; data(result); } } }
}
ajax(callback);
数组的排序
给数组排序
var arr = [1,2,3,4,5,6]; arr.sort(function (a,b)) { //如果返回值大于0,则从大到小排序 //如果返回值小于0,则从小到大排序 return a - b; } console.log(arr);
给对象排序
var arr = [1,2,3,4,5,6]; arr.sort(function (a,b)) { //如果返回值大于0,则从大到小排序 //如果返回值小于0,则从小到大排序 return a - b; } console.log(arr);
- 函数的理解
- 简单理解,对象就是键值对的集合
section4
网站的基本知识
- 常见的通信协议
- http/https:超文本传输协议
- ftp:传输协议
- mstp/pop3: 邮件传输协议
- 多个ip地址可以对应一个域名,域名与ip地址是通过DNS域名解析互相连接的
- 端口:用来唯一确定计算机上的应用程序,一个端口就是对应一个应用程序,端口的数值0-65535,一般使用1024-65535的端口
- 同样的域名同时请求地址数量是有限制的
- 静态网站:资源都是静态的(提前准备好的)缺点:可维护性低,无法进行交互
- 动态网站:绝大所数html页面是动态生成的,数据和标签页面是分开的。php/java/.net/nodejs
- MAMP的组成:
- M:Mac系统
- A:Apache 提供网页服务
- M:mysql 数据库(其他数据库oracle,sqlserver,db2,access,nosql,mongodb,redis,memercache)
- P:php 用来开发后台程序(做网站)
- 传统的网站访问方式是同步模式
- 同步和异步发生在客户端和服务器端之间
- ajax达成的效果:实现页面的局部刷新,不阻塞页面
###跨域(jsonp)
- 协议、端口、域名只要有一个不一样,就是跨域。
- ajax出于安全问题的考虑,设计之初就不支持跨域获取数据。
- 因此要通过别的办法解决跨域问题(flash、动态创建script标签(就是jsonp的本质、h5)
- jsonp: json with padding
- 后台返回数据中时间戳的作用:解决缓存问题
- jQuery中ajax方法的jsonp参数的作用:改变url参数的key
- data = JSON.parse(data);将字符串转换为json数据。
数据库简单操作(增删改查)
- 增:insert into 表名(字段信息) values (字段对应的数据)
- 删:delete * from 表名 where 条件
- 改:update 表名 set 字段名 = 字段值,字段名 = 字段值
- 查:select * from 表名 where 条件
section5
构造函数-原型-实例对象-原型链-constructor的关系
- 堆栈
实例对象和原型对象组成了一条链式结构,它们之间通过proto连接
P –> person.prototype –> Object.prototype –> NULL
对象的本质:无序的键值对集合。
- 所有原型链的末端都是Object,即所有的对象都直接或间接的继承自Object。
- 原型链是javascript中继承的本质。
- constructon一般用来区分该对象是谁的构造函数的。
- 所有的方法都是FUnction的实例。
- 实例对象.__proto__ == 构造函数.prototype。
- javascript中的函数是由浏览器根据FFunction实例化来的,
- Math不是方法,不能new 一个实例对象,Math是一个对象。
- 函数一定是对象,对象不一定是函数。
三张图:
- 构造函数-原型-实例对象-constructor-1
构造函数-原型-实例对象-constructor-2 原型链
原型与原型链-1
原型与原型链-2函数与Function的关系
关于constructor
- 构造函数-原型-实例对象-constructor-1
函数的三种角色
- 普通函数
- 构造函数
- 对象
- 所有的函数都有prototype(有构造函数有关)和__proto__(普通函数)属性。
- instanceof:判断是否是指定对象的实例。
- 如果构造函数的原型在原型链上,那么原型链开始的那个实例就是所有原型所属的构造函数的实例。
- 属性判断:判断某个属性是否属于某个对象:
- in:既可以判断对象上的属性,也可以判断原型对象上的属性
- hasOwnproperty:判断对象中是否有某个属性
- 语法:对象名:hasOwnproperty(‘属性名’)
类型判断:
数据类型:
- 基本类型:number/string/boolean/null/undefined
- 引用类型:Object(Function/Array/Date/String/RegExp/Boolean/Error等
- typeof:类型判断,只能判断出string、number、object、undefined、function、boolean
判断Object类型和Array类型
内容总结
- 所有的构造函数都有一个原型属性prototype属性,该属性是一个对象。
- 原型对象都有一个conctructor属性,该属性指向原型所属的构造函数。
- 所有的实例都有一个__proto__属性,该属性指向产生该实例的构造函数的原型对象,该属性不是标准的属性,是给浏览器自己使用的。
- 所有的原型对象都有一个__proto__属性,该属性指向另一个构造函数的原型,构成原型链。
- 所有的函数都有一个属性__proto__,该属性指向Function的原型prototype(所有的函数都是Function的实例)。
- Function函数是本身的实例(Function.__proto__ === Function.prototype)。
- 对象的本质是无序的键值对的集合。
__proto__与prototype的关系
- prototype是从构造函数的角度来说的
- __proto__是从实例对象来说的
- 这两个属性指向同一个对象,都指向原型对象。
函数中的三种角色
- 普通函数
- 对象
- 构造函数
函数是什么角色取决于它的调用方式
function foo(){}; foo(); //作为普通函数,此时比较关心__proto__属性 var f = new foo(); //作为构造函数,此时比较关心prototype属性 foo.info = "hello" //此时就是对象 foo.showInfo = function() { console.log(this.info); }
section6
###jsonp跨域
原生jsonp
- 跨域:只有域名,端口,协议都一样才叫同源,否则有其中一个不同就是跨域。
- ajax不予许跨域获取数据所以需要想办法解决跨域获取数据的问题。
- 解决方案:flash、applet、name、h5等,现在主流的解决方案是jsonp。
jsonp的本质:动态创建script标签,通过script标签的src属性发送请求,请求返回的内容是一段JavaScript代码(函数调用,一个变量)
//本质是动态创建script标签,通过script标签的src属性发送请求 var script = document.createElement('script'); script.src = '要请求文件的路径'; var head = document.getElementTagName('head')[0]; head.appenChild(script);
- 动态创建的script加载数据的方式是异步的。
jQuery中的jsonp
jsonp和jsonpCallback分别是用来重命名
此处有代码 // jsonp-test
url的标准格式
- scheme://host:port/path?query#fragment
- scheme: 协议:http/https/ftp/smtp
- host: 域名/IP
- port: 端口
- path: 路径
- query:从?开始,多个参数之间用?隔开,单个参数用=隔开 ?key1=value1$key2=value2
- fragment: 锚点:
继承
- 原型链:实例对象和原型对象之间通过__proto__联系起来的的链式结构。
- 继承:把别人的拿过来(属性和方法),自己的还是自己的
继承的方式
原型继承:
- 原型继承的缺点:
- 没有办法在不影响所有实例的情况下给要继承的构造函数传参。
- 继承的构造函数中的引用类型对于所有的实例来说是共享的。
function Animal(name) { this.name = name; this.lover = ['meat','cake','cheese','juice']; } Animal.prototype.showName = function () { console.log(this.name); } function Tom(color) { this.color = color; } /*将Tom的原型对象指向Animal的实例对象*/ Tom.prototype = new Animal('Tom'); Tom.prototype.catchMouse = function () { console.log(this.name +"抓到Jerry了!!"); } var tom = new Tom("grey"); tom.catchMouse(); tom.lover.push('peal'); console.log(tom.lover); var jerry = new Tom('green'); console.log(jerry.color); jerry.catchMouse(); /*继承的构造函数的引用类型对于所有的实例来说是共享的*/ console.log(jerry.lover);
- 原型继承的缺点:
借用构造函数继承
- 缺点:只能继承构造函数中的成员,不能继承构造函数中的方法
function Animal(name){ this.name = name; // this.showName = function(){ // console.log(this.name); // } } // Animal.prototype.showName = function(){ // console.log(this.name); // } function Mouse(nickname,name){ //这样调用的话Animal中的this是谁?Mouse的实例对象 Animal.call(this,name); // thia.name = '老鼠'; this.nickname = nickname; } var m = new Mouse('杰瑞','老鼠'); // console.dir(m); // m.showName(); console.log(m.name); console.log(m.nickname); var m1 = new Mouse('贝塔舒克','mouse'); console.log(m1.name); console.log(m1.nickname);
组合继承(原型继承和借用构造函数继承)
目的:属性都使用实例的,方法都使用构造函数的。
function Person(name,sex) { this.name = name; this.sex = sex this.score = [100, 200, 150, 180, 200]; } Person.prototype.showName = function () { console.log(this.name); } Person.prototype.showScore = function () { console.log(this.score); } function Student(name,age,sex) { /*将构造函数Person的this指向构造函数Student的实例对象 * 这样Student的实例对象就可以使用Person的属性 * */ Person.call(this,name,sex); this.age = age; } /*将构造函数Student的原型对象指向构造函数Person的实例对象 * 这样Student的实例对象就可以使用Person的原型对象的方法. * */ Student.prototype = new Person(); Student.prototype.showAge = function () { console.log(this.name+"的年龄为"+this.age); } var stu = new Student("张三","12","男"); console.log(stu.name); console.log(stu.age); console.log(stu.sex); console.log(stu.score); stu.showAge(); stu.showScore();
命名空间
var nihao
面向对象三大特性
封装
继承(代码的重用)
多态: 对于同一种行为的不同表现状态
object.create();
section7
面向对象知识点
- 对象
- 构造函数
- 实例对象
- 原型对象
- 原型链
- 封装继承多态
- 继承方式:原型继承、构造函数继承、组合继承
- 函数的三种角色:
- this
面向过程、面向对象的编程思维
- 面向过程:命名冲突,不方便代码重用。
- 面向对象:从一定程度上避免命名冲突,方便代码重用。
- 面向对象的程序风格:构造函数(属性)+ 原型(方法)、实例化之后可以执行原型上的方法,实例化的时候构造函数也会执行。
原型的另一种写法
- 以对象的方式来写
- 要在最前面加上constructor:构造函数名字
- 一般会体提供一个入口函数init
- 一系列的方法,这些方法是可以相互调用的
- 这些方法也可以不相互调用,通过实例对象直接调用(相互独立的功能)
function Foo(){}; Foo.prototype = { constructor: Foo, init: function(){}, autoplay: function(){}, ...... }
避免命名冲突的终极解决方案:模块化。
- SVN Git(代码托管)。
案例
- 改变div样式
- 选项卡
- 轮播图
- 表格排序
作用域
全局作用域
- 所有在全局作用域中的变量和成员都是window的成员
- delete:删除对象的属性,而不是方法
- 通过var声明的变量是不可以被delete方法删除的,如果不适用var声明的变量是可以被delete删除的
- 全局作用域中的成员对所有的函数都是可见的
delete删除数组元素的时候,数组的长度是不变的,即会删掉那个元素,但该元素仍然有一个占位符在。
var a = 1; b = 2; this.c = 123; var arr = [1, 2, 3, 4, 5]; delete: a; delete: b; delete: this.c; delete: arr[2]; console.log("a" in window); //true console.log("b" in window); //false console.log("c" in window); //true console.log(arr);
in:判断某个属性是否在某个作用域中
console.log("abc" in window); //true or false
函数作用域
- 函数作用域中的变量只能在函数内部使用,对外不可见。
块级作用域
- 花括弧{}形成块级作用域,但是在JavaScript中没有块级作用域的概念.
预解析
1.预解析
- 预解析的时候如果遇到同名的变量或者函数,以函数为准,即函数的优先级高于变量.
- 预解析的时候的优先级:函数》形参》声明。
- 全局作用域:所有的全局变量和函数声明都提前了。
- Javascript中的数据类型是可变的。
- 函数作用域:所有的局部变量和内部的函数声明以及形参都提前了。
变量提前仅仅是变量名提前,但是赋值没有提前。
var a = 456 //等价于 var a; a = 456;
2.执行
- 从上到下逐行执行
作用域链:作用域之间形成的链(嵌套函数)
访问变量的规则是从里到外,不可以反过来
var a = 10; function foo() { var b = 20; function fn() { var c = 30; console.log(a + b + c); //60 } fn(); } foo();
闭包
- 闭包:函数的嵌套形成闭包,里面嵌套的函数一定要有返回值,封闭的包裹。
- 闭包的组成:
- 函数代码块(内层函数)
- 函数的父级作用域
- 闭包的作用:
- 函数外部可以访问函数内部的变量(延长函数变量的生命周期)
- 缓存中间状态值
- (词法作用域)静态作用域:访问变量的时候取决于函数的定义位置,而不是调用位置
闭包可以做什么
- 闭包可以形成一个封闭的环境,然后对外开放一个接口
闭包用来访问函数内部的数据
function foo(rate) { var money = 100000; return function () { return money * rate; } } var fn = foo(0.001); var ret = fn(); console.log(ret);
自执行函数
打印函数时各参数的意思
- length:形参的个数
arguments:实参的个数,它不是数组,叫类数组或者关联数组
- arguments[i]可以用来替代第几个形参
caller: 函数的调用者.
section8
闭包补充
- 垃圾回收机制如果一个数据不存在任何引用,那么这个数据就成了垃圾
C/C++的垃圾回收机制是手动的,(程序员自己分配内存,释放内存)
var obj = {name: 123} obj = null; console.log(obj.name) // undefined //name就成了垃圾,等待被回收
闭包的应用场景:获取函数内部的变量,并且可以修改(通过修改返回来的那个函数).
浏览器
- 浏览器:应用软件(多线程渲染页面,Javascript的解析运行,网络通信)。
- 多线程:一个线程就是处理一个任务。
- 浏览器运行时是多线程的。
- Javascript程序的运行是单线程的。
事件队列
- 如下的三种情况,任务会放到事件队列,但是先不执行
- 定时函数(延时到期)。
- 事件函数(触发事件)。
- ajax的回调函数(服务器端返回正常的数据)。
- 这三种任务的执行条件是(先满足第一个条件,再看是否满足第二个条件)
- 主线程已经空闲(Javascript代码执行完毕)。
- 需要特定的条件来触发。
- 定时器的延时是有浏览器的兼容性的(有的4ms,有的6ms,8ms)
事件对象
- p标签、h标签不可以嵌套块级元素
默认行为
- 系统给标签默认自带的行为:a标签跳转,拖动文字和图片变半透明等行为。
阻止默认行为:
a.onclick = function() { 只能阻止默认行为,不能阻止冒泡,但是jQuery中可以同时阻止两者 return false; } //另一种写法 a.onclick = function() { if(e) { e.preventDefault(); } else { } }
阻止