存储的就是数据本身的变量就是值类型的数据
值类型的赋值:
直接将存储的数据复制一份进行赋值,两份数据在内存中是完全独立的
值类型做函数的参数:
函数内部的变量,也就是形参和实参只是简单的赋值操作,两个数据独立存储于内存中的
在函数内部对形参进行修改,不会影响外面的变量
2、引用类型:object
存储的是数据在内存中的地址,数据在内存中单独存储,就是引用类型的数据
引用类型赋值:
引用类型赋值的时候,是将变量中存储的地址复制一份单独存储,但是两个变量共享同一个对象
修改其中一个对象,另外一个引用来访问的时候,也会访问到修改后的对象
引用类型做函数的参数:
还是把实参存储的地址赋值给了形参,在函数内部,形参同样也指向该对象,
所以,在函数内部对该对象进行修改,会影响到外面的变量
注意:如果在函数内部重新创建对象,为该形参赋值,那么两个对象将不再有关系
修改其中一个,另外一个不受影响
3、新增属性、方法的方式有:
1.点语法
2.通过 [] 的形式去添加。
obj["[object Object]"] = function () {
console.log("我添加成功了");}
obj["[object Object]"]();
4、in关键字:
1. 最常用的是在for in 循环中 遍历对象的键
2. 判断属性是否存在于对象中
//语法 属性名 in 对象
对象的键为字符串类型
var propName = "name";
var isExsit = propName in obj;
console.log(isExsit);
for(var k in obj){
console.log(typeof k);
}
var arr = [4, 6, 3, 4];
console.log(0 in arr);
//这里会做一个隐式的类型转换
console.log("0" in arr);
//注意: in关键字操作数组的时候判断的是索引是否存在,而不是值
console.log(6 in arr);
//如何判断数组中是否存在指定的值
//1. for循环 如果找到了就输出
//2. indexOf 返回值为指定的数对应的索引,如果没有找到 返回-1
console.log(arr.indexOf(9));
5、delete关键字:
可以用来删除对象的属性,还有未使用var声明的变量
delete关键字有返回值 用来表示删除属性是否成功
如果删除的是不存在的属性,返回值为true
如果删除的属性存在原型当中,那么返回值为true,但是并未删除
console.log(obj.name);
var result = delete obj.name;
console.log(obj.name, result); // undefined true
var num = 10;
var result = delete num;
console.log(result);//false
6、break和continue:
7、DOM操作:
//增:document.createElement、appendChild
//删:removeChild
//改:style、id、className、innerHTML、innerText
//查:getElementById、getElementsByTagName、getELementsByClassName
8、异常处理:
// //异常捕获语句的完整形式
// try{
// //可能出现异常的代码
// xyz();
// }
// catch(e){
// //出现异常后的处理代码
// }
// finally{
// console.log("我是finally中的代码");
// //不管有没有出现异常,这里的代码都会执行
// //node.js
// //做释放资源的操作。
// }
function sum(num1, num2){
if(num1 == undefined || num2 == undefined){
throw {
errMsg: "能不能好好玩耍了,乖乖给我传参!!",
errCode: 13888888888
};
}else{
return num1 + num2;
}
}
// sum(0);
try{
sum(0);
}
catch(e){
console.log(e.errMsg);
}
9、使用函数进行封装:
优势:将代码封装,使得复用性更高
缺点:1.全局变量污染 2.代码结构不够清晰,维护不方便
使用对象进行函数封装:
1.暴露在全局的只有一个对象名 不会造成全局变量污染
2.使用对象将代码进行功能模块的划分,有利于日后的维护
window.onload = function () {
var divs = itcastQuery.tag("div");
itcastQuery.setStyle(divs);
var ps = itcastQuery.tag("p");
itcastQuery.setStyle(ps);
}
var itcastQuery = {
//获取dom元素的方法们
getEle:{
tag: function (tagName){
return document.getElementsByTagName(tagName);
},
id: function (id){
return document.getElementById(id);
}
//通过classname获取元素的方法
//....
},
//设置样式的方法们
setCss: {
setStyle: function (elements){
for (var j = 0; j < elements.length; j++) {
var ele = elements[j];
ele.style.border = "1px solid red";
}
},
css:function(option){},
addClass:function(){},
//..
}
//事件处理模块
}
10、面向对象三大特性:
封装:
继承:一个对象没有一些方法和属性,但是另外一个对象有,把另外一个对象的属性和方法,拿过来使用,就是继承(继承在两个内存空间中, 改了一个,另一个不会变)
var obj = {};
var obj1 = {
name : "张学友",
sayHello: function () {
console.log("你好,我是张学友");
}
}
// obj.sayHello();
//混入式继承(mix-in) for in
for(var k in obj1){
//k可以获取到对象的每一个属性
//obj1[k]可以获取到对象的每一个属性的值
//这里使用k给对象新增属性的时候,不可以使用点语法
obj[k] = obj1[k];
}
obj.sayHello();
多态:
//多态是在强类型语言中比较常用,JavaScript中没有相应的体现
//Animal 父类 父类的属性和方法供所有的子类共享 但是父类不能访问子类的属性和方法
//Dog 子类
//Cat 子类
//Animal an = new Animal();
//Dog dog = new Dog();
//Animal an = new Dog();
//使用父类的引用(指针)指向子类的对象 就叫做多态
//使用多态来隐藏不同
11、创建对象方式:
1.对象字面量 {key:value,key:value...}
2.使用内置构造函数
var obj = new Object();
obj.name = "哈哈哈";
3.封装简单的工厂函数 (不推荐使用)
function createSong(songName,singerName){
var o =new Object();
o.name = songName;
o.singer = singerName;
o.sing = function () {
console.log("让我来唱首歌");
}
return o;//{name:"",singer:"",sing:function...}
}
var obj = createSong("演员","哈哈");
var obj1 = createSong("一言难尽","哈哈哈");
4.自定义构造函数:构造函数其实也是函数,但是通常用来初始化对象,并且和new关键字同时出现
function Person() {
//默认隐含的操作,把刚才用new新创建出来的对象赋值给this
this.name = "尼古拉斯凯奇";
this.age = 50;
this.sayHello = function () {
console.log("Hey man");
}
//如果这里写其他的代码,会执行吗? 肯定会
return null;
}
var p = new Person();//new Object();
console.log(p);
p.sayHello();
//构造函数的执行过程
//1.使用new关键字创建对象
//2.调用构造函数,把新创建出来的对象赋值给构造函数内的this
//3.在构造函数内使用this为新创建出来的对象新增成员
//4.默认返回新创建的这个对象 (普通的函数,如果不写返回语句,会返回undefined)
//构造函数的返回值
//1.如果不写返回值,默认返回的是新创建出来的对象 (一般都不会去写这个return语句)
//2.如果我们自己写return语句 return的是空值(return;),或者是基本类型的值或者null,都会默认返回新创建出来的对象
//3.如果返回的是object类型的值,将不会返回刚才新创建的对象,取而代之的是return后面的值
12、自定义构造函数:
构造函数存在问题
构造函数中的方法,每新创建一个对象的时候,该对象都会重新的创建一次这个方法,每个独享独占一个方法但是该方法内容完全相同,所以造成资源浪费
1.解决办法1
将构造函数内的方法,进行提取,放在构造函数外面,在构造函数内部进行引用赋值
那么创建出来的对象,都会指向构造函数外面的这个函数,达到共享的目的
问题:全局变量增多,造成全局变量污染,代码结构混乱,不容易维护
2.解决办法2
使用原型
13、原型:在构造函数创建出来的时候,系统会默认的帮构造函数创建并关联一个神秘的对象,这个对象就是原型
原型默认的是一个空的对象
原型的作用:原型中的属性和方法,可以被使用该构造函数创建出来的对象使用
原型是什么?
在构造函数创建出来的时候,系统会默认的创建并关联一个对象,这个对象就是原型,原型对象默认是空对象
默认的原型对象中会有一个属性constructor指向该构造函数
#### 原型的作用
原型对象中的成员,可以被使用和它关联的构造函数创建出来的所有对象共享
#### 原型对象的使用
1. 使用对象的动态特性,为原型对象添加成员
2. 直接替换原型对象
注意事项:
直接替换原型对象,会导致替换之前创建的对象的原型和替换之后创建的对象的原型不一致
function Person(name, status) {
this.name = name;
this.status = status;
this.act = function () {
console.log("演戏");
};
this.exercise = function () {
console.log("就不强身健体,就要保卫祖国");
}
}
var p = new Person("xyz","single");
Person.prototype.exercise = function () {
console.log("强身健体,保卫祖国");
}
p.exercise();
14、经典继承方式:
function create(obj){
if(Object.create){
return Object.create(obj);
}else{
function F() {
}
F.prototype = obj;
return new F();
}
}
15、原型继承:
//原型继承
//利用原型中的成员可以被和其相关的对象共享这一特性,可以实现继承
//这种实现继承的方式,就叫做原型继承
//1.给原型对象中添加成员(通过对象的动态特性) 不是严格意义上的继承
// function Person(name, age){
// this.name = name;
// this.age = age;
// }
// Person.prototype.sayHello = function () {
// console.log("我想死你了");
// }
// var p = new Person("冯巩",50);
// p.sayHello();
// //这里的p对象就继承原型
// //2.直接替换原型对象
// function Person(name, age){
// this.name = name;
// this.age = age;
// }
// Person.prototype.sayHi = function () {
// console.log("Hey man");
// }
// var parent = {
// sayHello : function () {
// console.log("我想你死了");
// }
// }
// //
// Person.prototype = parent;
// var p = new Person("冯巩",50);
// p.sayHello();
// console.log(p.name);
// p.sayHi(); 替换之后,sayHi方法不复存在
//p对象继承了原型对象(parent对象)
//注意:使用替换原型的方式实现继承的时候,原有原型中的成员就会丢失
//3.利用混入的方式给原型对象添加成员
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function () {
console.log("Hey man");
}
var parent = {
sayHello : function () {
console.log("我想你死了");
}
}
for(var k in parent){
Person.prototype[k] = parent[k];
}
var p = new Person("冯巩",50);
p.sayHello();
console.log(p.name);
//也是实现了继承 p继承自原型对象
16、原型链:
每个构造函数都有原型对象
每个对象都会有构造函数
每个构造函数的原型都是一个对象
那么这个原型对象也会有构造函数
那么这个原型对象的构造函数也会有原型对象
这样就会形成一个链式的结构,称为原型链
原型链结构的基本形式
function Person(name){
this.name = name;
}
var p = new Person();
//动物--->人---->老师---->坏老师
function Animal(){
this.gender = "male";
}
Human.prototype = new Animal();
Human.prototype.constructor = Human;
function Human(){
this.actionWay = "走路";
}
Teacher.prototype = new Human();
Teacher.prototype.constructor = Teacher;
function Teacher(){
this.skill = "教书";
}
BadTeacher.prototype = new Teacher();
BadTeacher.prototype.constructor = BadTeacher;
function BadTeacher(){
this.name = "吕超";
}
var t = new BadTeacher();
console.log(t);
17
:eval函数可以用来将字符串转换成JavaScript代码并且运行
18、 静态成员:是指构造函数的属性和方法 实例成员:是指实例的属性和方法
19、构造函数的**原型**是否在该对象的原型链上!
console.log(p instanceof Person);
20、
//Function也可以被当做一个构造函数
//通过Function new出来函数可以被当做是实例化的对象
//那么Function这个构造函数也有原型对象
//Function的原型对象是一个空的函数
//Function的原型对象的原型对象是Object.prototype
var foo = new Function();
console.log(Function.prototype);
console.log(Function.prototype.__proto__);
21、数组增删改查:push()、splice()、
22、面向对象封装歌曲管理:
function SongManager(){
this.songList = null;
}
//在当前对象的方法中,调用当前对象的其他方法,需要使用this
//例如 在 removeSong方法中调用 selectSong this.selectSong
SongManager.prototype = {
init:function (songList) {
this.songList = songList;
},
addSong: function (song){
this.songList.push(song);
},
removeSong:function (songName){
var song = this.selectSong(songName);
if(song == null){
throw "您要删除的歌曲不存在!请重新尝试";
}
var index = this.songList.indexOf(song);
this.songList.splice(index, 1);
},
updateSong: function (songName, singer) {
var song = this.selectSong(songName);
if(song == null){
throw "您要修改的歌曲不存在!请重新尝试";
}
song.singer = singer;
},
selectSong: function (songName) {
for (var k = 0; k < this.songList.length; k++) {
var song = this.songList[k];
if(song.songName == songName){
return song;
}
}
return null;
}
};
var pwbDEManager = new SongManager();
pwbDEManager.init([
{
songName:"青藏高原",
singer:"潘文斌"
},
{
songName:"我的换板鞋,摩擦摩擦最时尚",
singer:"约翰逊,庞麦郎"
}
]);
pwbDEManager.addSong({
songName:"东风破",
singer:"Jay Chou"
})
23、递归:在函数内调用函数自己,就是递归,没有递归结束条件的递归,就是死递归
function sum(n){
if(n == 1)
{
return 1;
}
//return 1+2+3
//return 1+2
return sum(n-1) + n;
}
var num = sum(100);
console.log(num);
function factorial(n) {
if(n == 1){
return 1;
}
//return factorial(2) * 3 6
//return factorial(1) * 2 2
return factorial(n-1) * n;
}
斐波那契 数列
function fibonacci(n){
if(n <= 2){
return 1;
}
return fibonacci(n-1) + fibonacci(n-2);
}
console.log(fibonacci(10));
递归遍历后代元素:
//给页面中所有的元素添加一个边框 1px solid pink
//DOM中,没有提供直接获取后代元素的API
//但是可以通过childNodes来获取所有的子节点
//先找body的所有子元素
//再找body的子元素的所有子元素
var allChildren = [];
function getChildNode(node){
//先找子元素
var nodeList = node.childNodes;
//在用子元素再找子元素 这里就可以递归了
//for循环中的条件,就充当了结束的条件
for (var i = 0; i < nodeList.length; i++) {
//childNode获取到到的节点包含了各种类型的节点
//但是我们只需要元素节点 通过nodeType去判断当前的这个节点是不是元素节点
var childNode = nodeList[i];
//判断是否是元素节点
if(childNode.nodeType == 1){
childNode.style.border = "1px solid pink";
getChildNode(childNode);
}
}
}
getChildNode(document.body);
}
24、作用域:
1.块级作用域:JavaScript中没有块级作用域
2.词法作用域:就是在代码写好的那一刻,变量的作用域就已经确定了,这种作用域,就是所谓的词法作用域
3.在JavaScript中唯一能产生作用域的东西是 函数!
25、作用域链条:
只要是函数就可以创造作用域
函数中又可以再创建函数
函数内部的作用域可以访问函数外部的作用域
如果有多个函数嵌套,那么就会构成一个链式访问结构,这就是作用域链
26、闭包:一个具有封闭的对外不公开的, 包裹结构, 或空间,闭包的原理就是作用域访问原则
js中的闭包就是函数
闭包要解决什么问题?
1.闭包内的数据不允许外界访问
2.要解决的问题就是间接访问该数据
闭包的作用:
闭包的作用
最基本的作用:可以通过闭包返回的函数或者方法,来修改函数内部的数据
创建一个私有的空间,保护数据
外部想要访问数据,只能通过函数提供的方法
在提供的方法中,我们可以设置一些校验逻辑,让数据变得更加安全
//1.函数内部的函数中可以访问该函数中的变量
//2.但是我们需要在函数外部去访问函数中变量
function foo(){
var num = 123;
return function(a){
//1.如果传参数,这里的a肯定不是Undefined,所以条件判断为true
if(a !== undefined){
num = a;
}else{
//如果不传参,代表要获取这个值,直接return
return num;
}
};
}
var func = foo();
//设置值
func(789);
//理想状态下的获取值
var x = func();
console.log(x);
func(987);
console.log(func());
//1.闭包基本模式
//在外部函数(foo)内创建函数(inner),在这个内部函数(inner)中,可以操作foo中的数据
//将外部函数的返回值设置为内部函数
//在外部调用外部函数(foo),就可以接受到返回值(内部函数)
//使用这个内部函数,就可以在外部对外部函数里的变量进行修改
27、使用闭包获取多个数据:
function foo() {
var name = "张国荣";
var age = 18;
return [
function(){
return name;
},
function(){
return age;
}
]
}
var getName = foo();
console.log(getName[0]());
console.log(getName[1]());
var obj = foo();
console.log(obj.getName());
console.log(obj.getAge());
27、使用闭包获取多个数据:变量提升JS代码的运行分两个阶段
* 预解析阶段
* 变量名和函数提升
将var声明的变量名和function开头的函数进行提升
提升到当前作用域的最上方
* 执行阶段
28、注册事件
1.ele.on事件类型 = function(){}
2. addEventListener(事件类型,事件处理函数,useCapture) 第三个参数默认是false,冒泡阶段执行
3. attachEvent(事件类型,事件处理函数)
function registeEvent(target, type, handler){
if(target.addEventListener){
target.addEventListener(type,handler)
}else if(target.attachEvent){
target.attachEvent("on"+type,handler)
}else{
target["on"+type] = handler;
}
}
function createEventRegister(){
if(window.addEventListener){
return function(target, type, handler){
// this ---> window
target.addEventListener(type,handler)
}
}else if(window.attachEvent){
return function(target, type, handler) {
target.attachEvent("on" + type, function(){
handler.call(target, window.event);
})
}
}else{
return function(target, type, handler) {
target["on" + type] = handler;
}
}
}
var registeEvent = createEventRegister();
window.onload =function () {
var div = document.getElementById("div1");
registeEvent(div,"click",function(e){
console.log(e);
console.log(this);
//this---->该事件的触发对象
alert("太阳天空照,花儿对我笑,小鸟说:完了")
})
}
兼容性:
//通用的
// div.onclick = huidiao;
//ie9以上才支持
// div.addEventListener("click",huidiao)
//ie9(不包括9)以下支持的
// div.attachEvent("onclick",function(){
// huidiao.call(div, window.event);
// })