01基本对象
-
var stu={
-
name:'zsh',
-
age:12,
-
eat:function(){
-
console.log(this);
-
// 在基本对象内部this指的是当前的对象。
-
console.log('吃了。。。。')
-
}
-
}
-
stu.eat();
-
var stu1={
-
name:'ls',
-
age:20
-
}
02工厂方式创建对象
-
var stu1=Student('zs',20);
-
var stu2=Student('ls',13);
-
var tea1=Teacher('aa',34);
03构造函数方式
-
// 如果是构造函数,函数名一般大写。
-
function Student(name,age){
-
this.name=name;
-
this.age=age;
-
this.eat=function(){
-
// 构造函数中的this指的是当前实例化对象
-
console.log(this)
-
}
-
}
-
// 实例化对象
-
var stu=new Student('zs',20);
-
var stu2=new Student('ls',18)
-
stu2.eat();
04构造函数应用
-
var flight=new Product('这是无人机',5999,['白色','渐变色','银色']);
-
console.log(flight);
-
// 直接通过id名可以选择标签
-
title.innerHTML=flight.title;
-
btn.onclick=function(){
-
flight.buy();
-
// 页面跳转
-
location.href="03构造函数方式.html";
-
}
-
flight.buy();
05构造函数+原型方式
-
function Product(title,price){
-
this.title=title;
-
this.price=price;
-
// this.buy=function(){
-
// counsole.log('hello')
-
// }
-
}
-
var flight=new Product('无人机',4999);
-
var mz=new Product('口红',399);
-
// 存储的地址不一样。执行的功能一样。
-
// 每次实例化对象的时候,都会生成一个buy方法。造成资源的浪费
-
// console.log(flight.buy==mz.buy);
-
// 每一个构造函数,都有一个prototype属性/对象,该属性的所有方法和属性都能被构造函数继承。
-
Product.prototype.buy=function(){
-
console.log('购买了。。。。')
-
}
-
// 如果实例对象没有自己对应的方法,会去构造函数的prototype内部寻找。如果能找到,就会执行该方法。
-
console.log(flight.buy==mz.buy);
-
// 我们一般会把属性放置在构造函数内部,方法类的放在原型里面。这种方法封装的就称为构造函数+原型方式
06构造函数相关概念
-
// this在普通位置一般指向的是window
-
console.log(this);
-
// 构造函数的首字母一般大写
-
function Product(title,price){
-
this.title=title;
-
this.price=price;
-
this.joinCar=function(){
-
console.log(this.title);
-
}
-
}
-
// 两个this指的都是实例化对象
-
Product.prototype.buy=function(){
-
console.log(this);
-
console.log('购买了。。。。'+this.title);
-
}
-
var f=new Product('无人机',5999);
-
f.buy();
-
f.joinCar();
-
// 实例对象的__proto__指向构造函数的prototype
-
console.log(f.__proto__==Product.prototype);
-
f.__proto__.buy=function(){
-
console.log('您确认购买'+this.title);
-
}
-
var m=new Product('口红',299);
-
m.buy();
-
var arr=new Array(10,20,30);
-
// 可以通过constructor找到实例对象所属的构造函数
-
console.log(arr.constructor==Array);
-
console.log(m.constructor==Product);
-
// constructor在某些情况下没有那么靠谱,不好用
-
// 官方推荐 使用 a instanceof b 判断a是否是b的实例对象
-
console.log( arr instanceof Array)
07constructor
-
function Product(title,price){
-
this.title=title;
-
this.price=price;
-
this.joinCar=function(){
-
console.log(this.title);
-
}
-
}
-
// Product.prototype.buy=function(){
-
// console.log(this);
-
// console.log('购买了。。。。'+this.title);
-
// }
-
// 相当于重写了Product.prototype 丢失了constructor属性
-
Product.prototype={
-
buy:function(){
-
console.log('买');
-
},
-
joinCar:function(){
-
console.log('加购物车');
-
}
-
}
-
var p=new Product('口红',399);
-
console.log(p.constructor);
-
console.log(Product.prototype);
08构造函数使用场景
html代码
-
<h3 id="title">标题</h3><br>
-
京东价<p id="price"></p><br>
-
选择颜色<p id="color"></p>
-
<script src="common.js"></script>
common.js代码
-
// 创建函数 把对象封装起来
-
function Student(name,age){
-
return {
-
name:name,
-
age:age,
-
eat:function(){
-
console.log(this);
-
// 在基本对象内部this指的是当前的对象。
-
console.log('吃了。。。。')
-
}
-
}
-
}
-
function Teacher(name,age){
-
return {
-
name:name,
-
age:age
-
}
-
}
-
function Product(title,price,color){
-
this.title=title;
-
this.price=price;
-
this.color=color;
-
}
-
Product.prototype.buy=function(){
-
console.log('请问您需要购买'+this.title+'?');
-
}
js代码
-
var p=new Product('kouhong',2199,['粉色','白色']);
-
title.innerHTML=p.title;
-
price.innerHTML=p.price;
-
for(var i in p.color){
-
console.log(i);
-
color.innerHTML+=p.color[i];
-
}
09constructor
-
function Product(name){
-
this.name=name;
-
}
-
Product.prototype={
-
// 重写以后丢失prototype属性,可以自己增加。
-
constructor:Product,
-
buy:function(){
-
alert('您确定了')
-
}
-
}
-
var p=new Product('手机')
-
console.log(Product.prototype);
-
console.log(p.constructor==Product);
10原型链
-
// 原型链:当从一个对象那里调取属性或方法时,如果该对象自身不存在这样的属性或者方法,
-
// 就会去关联的prorotype那里寻找,如果prototype没有。就会去prototype关联的prototype那里寻找。如果还没有,会一直向上寻找
-
// 直到prototype....prototype..为null。从而形成了原型链(根本上来说就是继承)
-
// a.isPrototypeOf(b) 判断a是否存在b的原型链中
-
function Product(name){
-
this.name=name;
-
}
-
console.log(Product.prototype.__proto__==Object.prototype);
-
console.log(Object.prototype.__proto__);
-
var p=new Product('手机');
-
console.log(Product.prototype.isPrototypeOf(p));
-
console.log(Object.prototype.isPrototypeOf(p));
-
var person={
-
name:'zs'
-
}
-
// 通过person创建对象student。类似于继承
-
var student=Object.create(person);
-
student.zid='101';
-
var teacher=Object.create(student);
-
teacher.zid='001';
-
// 自身不能说存在自身原型链中
-
console.log(teacher.isPrototypeOf(teacher));
-
console.log(student.isPrototypeOf(teacher));
-
console.log(Object.prototype.isPrototypeOf(person));
-
console.log(person.isPrototypeOf(teacher));
-
// 如果一个对象既有自有属性,又可以继承。自有属性为准
-
// zid是teacher继承过来的
-
console.log(teacher.zid);
-
// a.hasOwnProperty(b)判断b属性是a自有的还是继承过来的
-
console.log(teacher.hasOwnProperty('zid'));
11get和set
-
var circle={
-
r:20,
-
// get获取值 get 变量名
-
// set设置值 set 变量名
-
get acr(){
-
return Math.PI*this.r*this.r;
-
},
-
set acr(value){
-
this.r=value;
-
}
-
}
-
// 如果是赋值,自动调用set方法
-
circle.acr=100;
-
// 如果是获取值,自动调用get方法
-
console.log(circle.acr);
12属性特征
-
var stu={
-
name:'zs',
-
age:12
-
}
-
// 正常赋值,属性可以直接修改
-
stu.name='小明';
-
// 属性可以被遍历出来
-
// for (var i in stu){
-
// console.log(i)
-
// }
-
// 一般特殊情况才这样使用。
-
// 设置属性的时候,可以配置属性特征
-
Object.defineProperty(stu,'password',{
-
value:123,
-
// 是否可被修改
-
writeable:false,
-
// 是否可以被遍历
-
enumerable:false,
-
//是否可以被重新配置
-
configurable:false
-
})
-
// 修改不成功,但是不会报错。writeable false
-
stu.password=456;
-
console.log(stu.password);
-
// 不能被遍历 enumerable是false
-
for (var i in stu){
-
console.log(stu)
-
}
-
// 不能被重新配置 configurable是false
-
// Object.defineProperty(stu,'password',{
-
// value:123,
-
// // 是否可被修改
-
// writeable:true,
-
// // 是否可以被遍历
-
// enumrable:true,
-
// //是否可以被重新配置
-
// configurable:true
-
// })
13变量提升
-
/变量声明
-
// 如果一个变量声明,会把声明提升到整个作用域的最前面,赋值还是在原来的位置
-
// console.log(a);
-
// var a=10;
-
// 等价于
-
// var a;
-
// console.log(a);
-
// a=10;
-
// 如果变量没有声明,作用域是赋值以后的区域
-
//报错a 没有声明在赋值之前没有办法直接使用
-
// console.log(a)
-
// a=10;
-
// 通过该方法定义函数,会把整个函数提升到作用域最前面。
-
// add()
-
// function add(){
-
// console.log(111)
-
// }
-
// 如果通过该方法定义函数,只是把变量的定义提升到作用域最前面
-
// 报错 add不是一个函数
-
// add()
-
// var add=function(){
-
// console.log(111);
-
// }
-
// var a=10;
-
// function add(){
-
// // 变量提升,会把变量声明提升到整个作用域最前面
-
// // js中只有函数的作用域,变量的作用域,是向上寻找距离其最近的开始的函数的{ 变量的作用范围就是该{以内。
-
// // console.log(a);
-
// // var a=100;
-
// // 等价于
-
// var a;
-
// console.log(a);
-
// a=100;
-
// }
-
// add()
-
// function add(){
-
// var a=100;
-
// }
-
// add();
-
// console.log(a); 报错 a的作用域是函数以内
-
function add(){
-
a=100;
-
}
-
// add(); 如果执行函数相当于给a赋值。a没有声明,作用域是赋值以后都可以使用
-
// 如果不执行函数,相当于不会执行赋值语句.a会报错
-
console.log(a);
14作用域和作用域链
作用域:在js中只有函数的作用域,在函数内部声明的变量,才能称为局部变量
全局和局部只是相对来说
作用域链:在某个作用域内使用变量的时候,首先会在该作用域内寻找该变量,如果没有
会一直向上寻找。这样的一种链式关系就是作用域链。其实指的就是变量的就近原则。
15原型链图
16this指向问题
this指向问题:
事件函数中:指向事件源
普通函数中:指向的是window对象
构造函数中:指向的是实例对象
普通对象中:指向的是当前对象
-
btn.onclick=function(){
-
console.log(this)
-
}
-
function Product(){
-
this.buy=function(){
-
console.log(this)
-
}
-
}
-
var p=new Product();
-
p.buy();
-
var stu={
-
name:'zs',
-
eat:function(){
-
console.log(this)
-
}
-
}
-
stu.eat();
-
function add(){
-
console.log(this)
-
}
-
add()
17call apply和bind
this指向问题:
普通函数中:指向的是window对象
call apply和bind都可以用来修改this指向。只是使用方式不一样
-
var stu={
-
name:'zs',
-
age:12,
-
weight:200
-
}
-
function add(a,b){
-
console.log(a,b,this.age)
-
}
-
// add(1,2);
-
// fn.call(所要指向的对象,参数1,参数2,...) 调用fn函数。修改this指向
-
add.call(stu,1,3);
-
// fn.call(所要指向的对象,[参数1,参数2,...]) 调用fn函数。修改this指向
-
add.apply(stu,[1,2]);
-
// bind不会直接调用函数 返回一个新的函数 修改了this指向
-
var fn=add.bind(stu,1,2);
-
fn();
18变量在内存中的存储
基本数据类型:在内存中以值的形式存在。 字符串、数值、布尔类型、null undefined
复合数据类型:在内存中以地址的形式存在。 对象
-
var a=10;
-
var b=a;
-
a=100;
-
console.log(b);
-
var stu={
-
name:'zs'
-
}
-
// 传递的是地址
-
var stu1=stu;
-
stu.name='ls';
-
console.log(stu1.name);
-
</script>
19深拷贝与浅拷贝
浅拷贝:直接把对象的属性一一赋值,不考虑属性值类型,如果属性值为对象的时候,只要修改一个,其余对象对应数据都会改变
-
var stu1={};
-
stu1.name=stu.name;
-
stu1.age=stu.age;
-
stu1.hobby=stu.hobby;
-
stu1.score=stu.score;
-
stu.name='张三';
-
stu.hobby[0]="弹吉他";
-
console.log(stu1);
深拷贝:如果对象的属性值为基本数据类型,直接拷贝。如果对象属性对应的值对象,需要解析对象,再去拷贝
-
var stu={
-
name:'zs',
-
age:14,
-
hobby:['唱歌','跳舞'],
-
score:{
-
math:89,
-
english:100,
-
lizong:[100,100,200]
-
}
-
}
-
var stu1={
-
}
-
stu1.name=stu.name;
-
stu1.age=stu.age;
-
stu1.hobby=[];
-
stu1.hobby[0]=stu.hobby[0];
-
stu1.hobby[1]=stu.hobby[1];
-
stu1.score={};
-
stu1.score.math=stu.score.math;
-
stu1.score.english=stu.score.english;
-
var stu2={};
-
// 快速实现深拷贝(函数递归调用)
-
function deepCopy(a,b){
-
for(var key in a){
-
var i=a[key];
-
if(i instanceof Array){
-
b[key]={};
-
deepCopy(i,b[key]);
-
}else if(i instanceof Object){
-
b[key]={};
-
deepCopy(i,b[key]);
-
}else{
-
b[key]=i;
-
}
-
}
-
}
-
deepCopy(stu,stu2);
-
console.log(stu2);
-
// 只要调用deepCopy即可实现深拷贝
20高阶函数
-
// 函数作为函数的实参。高阶函数
-
function add(time,color){
-
setTimeout(function(){
-
color();
-
},time)
-
}
-
add(1000,function(){
-
txt.style.color='red';
-
})
-
add(2000,function(){
-
txt.style.background='lime';
-
})
-
$('button').click(function(){})
21闭包
闭包:扩大了变量作用域
闭包:缩小变量作用域,防止变量污染
html:
-
<button>按钮</button>
-
<button>按钮</button>
-
<button>按钮</button>
-
<button>按钮</button>
-
<button>按钮</button>
-
<button>按钮</button>
js:
-
var btns=document.getElementsByTagName('button');
-
for(var i=0;i<btns.length;i++){
-
// btns[i].onclick=function(){
-
// // i全局变量,点击的时候i的值已经是btns.length;
-
// tags[i].style.background='lime';
-
// }
-
(function(b){
-
btns[b].onclick=function(){
-
// i全局变量,点击的时候i的值已经是btns.length;
-
btns[b].style.background='lime';
-
}
-
})(i);
-
}
-
//计数器
-
// 1、可以在函数的外部访问到函数内部的局部变量
-
// 2、让这些变量始终保存在内存中,不会随着函数的结束而自动销毁
-
var add=(function(){
-
var count=0;
-
return function(){
-
return count+=1;
-
}
-
})()
-
console.log(add);
-
console.log(add());
-
console.log(add());
-
console.log(add());
-
console.log(add());
自调用函数 ;( function(){})(); 前后都需要有结尾;
-
(function(){
-
// 放置的是一段有特殊功能的代码
-
var m=10;
-
})();
-
console.log(m)