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)