基本对象
var stu={
name:'zsh',
age:12,
eat:function(){
console.log(this);
// 在基本对象内部this指的是当前的对象。
console.log('吃了。。。。')
}
}
创建方式
- 工厂方式创建
var stu1=Student('zs',20);
var stu2=Student('ls',13);
- 构造函数方式
// 如果是构造函数,函数名一般大写。
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();
注意: 在该构造函数中,Student函数每次实例化对象的时候,都会生成一个eat方法。造成资源的浪费
构造函数概念
每一个构造函数,都有一个prototype属性/对象,该属性的所有方法和属性都能被构造函数继承。
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();
function Product(name){
this.name=name;
}
Product.prototype={
// 重写以后丢失prototype属性,可以自己增加。
constructor:Product,
buy:function(){
alert('您确定了')
}
}
var p=new Product('手机')
console.log(Product.prototype);//{constructor: ƒ, buy: ƒ}
console.log(p.constructor==Product);//true
原型链
prototype是函数才有的属性
__proto__是每个对象都有的属性,但不是规范属性,部分浏览器可实现
例如:
var a = {};
console.log(a.prototype); //undefined
console.log(a.__proto__); //Object {}
var b = function(){}
console.log(b.prototype); //b {}
console.log(b.__proto__); //function() {}
__proto__只取决于对象创建时实现方式
构造器方式
var A = function(){};
var a = new A();
console.log(a.__proto__); //A {}
console.log(a.__proto__ === a.constructor.prototype); //true
原型链查找
var A = function(){};
var a = new A();
console.log(a.__proto__); //A {}(即构造器function A 的原型对象)
console.log(a.__proto__.__proto__); //Object {}(即构造器function Object 的原型对象)
console.log(a.__proto__.__proto__.__proto__); //null
内部函数
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);
属性特征
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)
}
// 'password' 不能被重新配置 会报错
Object.defineProperty(stu,'password',{
value:123,
// 是否可被修改
writeable:true,
// 是否可以被遍历
enumrable:true,
//是否可以被重新配置
configurable:true
})
变量提升,变量存储
//如果一个变量声明,会把声明提升到整个作用域的最前面,赋值还是在原来的位置
/*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)
}
基本数据类型:在内存中以值的形式存在。 字符串、数值、布尔类型、null undefined
复合数据类型:在内存中以地址的形式存在。 对象
作用域
作用域:在js中只有函数的作用域,在函数内部声明的变量,才能称为局部变量
全局和局部只是相对来说
作用域链:在某个作用域内使用变量的时候,首先会在该作用域内寻找该变量,如果没有,会一直向上寻找。这样的一种链式关系就是作用域链。其实指的就是变量的就近原则。
深拷贝,闭包
function deepCopy(obj){
let objClone=Array.isArray(obj)?[]:{}
console.log(objClone)
if(typeof obj==="object"){
for(let key in obj){
//判断是否为对象自身属性
if(obj.hasOwnProperty(key)){
//判断ojb子元素是否为对象,如果是,递归复制
if(typeof obj[key] ==="object"){
//递归复制完成后储存到相同key值对象里
objClone[key]=deepCopy(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
console.log(obj[key])
}
}
}
}
return objClone
}
//闭包扩大了变量作用域
function fn() {
//中场情况下 add的作用域是fn内部
return function add(x,y){
console.log(x+y);
}
}
var fn1=fn()
fn1(1,2)
//闭包:缩小了变量作用域,防止变量污染
(function(){
//放置的是每一段有特殊功能的代码
var m=10
});
console.log(m)
//函数作为函数的实参。就是高阶函数
function add(time,color) {
setTimeout(function(){
color()
},time)
}
add(1000,function () {
txt.style.color='red'
})
add(2000,function(){
txt.style.background="lime"
})