JS高级(一)

拷贝继承

var obj1={
    age:20
    cat:["大黄","加菲猫"]
};

var obj2 = obj1; // 拷贝继承

obj2.age = 100;
console.log(obj1.age); // 100
console.log(obj2.age); // 100

// 另一种写法
var obj1={
    a:10,
    b:20,
    c:30
};

var obj2={
    a:obj1.a,
    b:obj1.b,
    c:obj1.c
}

obj2.a = 100;
console.log(obj1.a); // 10
console.log(obj2.a); // 100

两种方式继承都是拷贝继承,第二种可以理解成深拷贝,上面一种方式就是浅拷贝

深拷贝

深拷贝:实际上还是复制,把一个对象中的所有的属性或方法,一个一个的找到,并且在另一个对象中开辟相应的空间,一个一个的存储到这个新的对象中。

// 递归
var obj1={
     age:10,
     sex:"男",
     car:["奔驰","宝马","特斯拉","奥拓"],
     dog:{
         name:"大黄",
         age:5,
         color:"黄色"
     }
};

// 通过深拷贝把数据拷贝到另一个对象中

// 空对象
var obj2={};
// a---当前的对象,b是一个目标对象,把a对象中所有的内容复制到b对象中
function extend(a,b){
    // 遍历
    for(var key in a){
        // 先获取a对象中每个属性值
        var item = a[key];
        // 判断这个属性是不是数组
        if(item instanceof Array){
            // 如果数据是数组,就在b对象中添加一个新的属性,并且这个属性的值也是数组
            b[key]=[];
            // 把对象a中的数据一个一个的复制到b对象这个数组中
            extend(item,b[key]);
        }else if(item instanceof Object){
            // 如果这个数组是对象,那么b对象中添加一个属性,也是对象类型的
            b[key]={};
            extend(item,b[key]);
        }else{
            b[key]=item; // 直接赋值
        }
    }
}

// 调用方法
extend(obj1,obj2);
obj2.age=100;
console.log(obj1.age); // 10
console.log(obj2.age); // 100

浅拷贝:第一个对象和第二个对象的地址是相同的(类似于指针),其中一个对象的属性值改变,另一个对象的属性值也会改变

深拷贝:两个对象之间发生拷贝后,属性的值是不会相互影响的

对象冒充

对象冒充:看起来是继承,实际上是假的,继承一个类的时候需要用到“对象冒充”

// 构造函数
function Animal(name,color){
    this.name=name;
    this.color=color;
}
// 通过原型添加方法
Animal.prototype.eat=function(){
    console.log("今晚吃的是鱼")};

// 构造函数
function Dog(name,color,age){
    // this.name=name;
    // this.color=color;
    this.age=age;
    // 对象冒充 --- 仅仅是盗用了别人的构造函数实现属性的继承
    this.Animal=Animal; // 借用
    this.Animal(name,color);
    delete this.Animal; // 删掉了(可以省略)
}

// 实例化
var dog = new Dog("大黄","黄色",20);
console.log(dog.name,dog.age,dog.color);

// dog.eat(); 没有继承
 

原型的不同写法

// 构造函数
function Person(){
    
}
// 通过原型添加属性和方法
Person.prototype.name="乔峰";
Person.prototype.age="20";
Person.prototype.sex="男";
Person.prototype.eat=function(){
    console.log("吃的饭");
}
Person.prototype.play=function(){
    console.log("玩的好累");
}
Person.prototype.sleep=function(){
    console.log("一个人睡觉");
}

// 用对象的方法,改变原型的执行,在这个对象中直接添加属性和方法 
Person.prototype={
    constructor:Person, // 一定要加,不加有问题
    name:"卡卡西",
    age:20,
    sex:'男',
    eat:function(){
        console.log("吃")},
    play:function(){
        console.log("玩")}
}

动态原型

动态原型:会让这种写法看起来更像面向对象语言中类的写法

function Person(name,age){
    this.name=name;
    this.age=age;
    // 每次把原型的方法写在构造函数外部很麻烦,所以可以这样写
    // 在构造函数初始化的时候直接添加原型方法
    if(typeof Person.init=="undefined"){
        // 原型方法
        Person.prototype.sayHi=function(){
            console.log("hi");
        }
        Person.init=true; // 标识
    }
}
var p = new Person("小白",20);
p.sayHi();

通过原型为系统对象添加方法

// 沙箱写法  不会污染全局
    (function(){
       // 通过原型的方式为系统的对象添加原型原型方法
       // 字符串有没有可以干掉字符串中所有的空格的方法呢?
       
       String.prototype.myTrim=function(){
           return this.replace(/\s*/ig,"");
       } 
    })();


Object中的三个常见方法

function Person(name,sex){
    this.name=name;
    this.sex=sex;
}
// 原型添加方法
Person,prototype.height="170";
Person.prototype.eat=function(){
    console.log("吃");
};
// 构造函数
function Student(age){
    this.age=age;
}
Student.prototype=new Person("小明")
// 对象 
var stu = new Student(10);
console.log(stu.hasOwnProperty("age")); // 返回布尔值,判断该属性是不是当前对象

Student.prototype=new Person("小明")这个代码出来就是代表有继承了,原型指向改变

因为js中并没用对hasOwnProperty方法做保护,所以,我们可以私自更改这个方法

var myObj={
    age:20,
    hasOwnProperty:function(str){
        return false;
    }
}
console.log(myObj.hasOwnProperty("age")); //false

此时这个方法不是很容易辨别属性是不是属于某个对象的了,如果担心上面问题,这样解决

console.log(Object.prototype.hasOwnProperty.call(myObj,"age"));

判断对象p是不是实例对象的原型
function Teacher(){
    
}
var p =  new Person("小明"20); // 实例对象
Teacher.prototype=p;// 原型指向改变了
var t= new Teacher();// 实例对象
// 用来判断当前对象是不是另一个对象的原型 
console.log(p.isPrototypeOf(t));

判断这个属性是不是当前对象可以枚举的属性
// 能够被for-in遍历的属性是可枚举的
var p1= new Person("小明"10);
// 遍历
for(var key in p1){
    console.log(key);
}

// 判断这个属性是不是当前对象可以枚举的属性
console.log(p1.propertyIsEnumerable("weight"));
// 这个属性必须是属于实例对象的,并且不属于原型中
// 这个属性必须是可枚举的,也就是自定义的属性
// 如果对象没有指定的属性,返回false 

作用域和预解析

  • 作用域:变量的使用范围
  • 全局作用域和局部作用域
  • 全局作用域:整个页面或者都可以理解为script标签内部
  • 局部作用域:函数内部
  • 作用域链:变量在使用时候会层层搜索
var num = 10;// 全局变量,在全局作用域中

function f1() {
    var number = 20 ;  // 局部变量
}

f1();
console.log(number); //报错
作用域链
var age = 10;
// 0 级
function f1(){
// 1 级
    var age = 20;
    function f2(){
    // 2 级
        var age = 20;
        function f3(){  
        // 3 级
            var age = 40;
            console.age(age);  // 40
        }
        f3();
    }
    f2();
}
f1();

会从当前一直找到全局,全局没有就报错

预解析

预解析:在解析代码之前,变量和函数的声明会提前

console.log(num); // undefined
var num = 100 ;

// 上面等价于
var num;
console.log(num);
num = 100; // 赋值不会提前 

console.log(a);
console.log(b);
var a = b = 10;

// 等价于
var a ;
console.log(a);
console.log(b);
 a = b = 10;

闭包

  • 闭包:一个函数A中包含了另一个函数B,函数B中可以访问函数A中的变量,一般是嵌套关系
  • 闭包模式:函数式闭包,对象式闭包
  • 闭包的优点和缺点:延长作用域链,缓存数据(这也是缺点)
闭包演示
// 函数式闭包:函数中有函数
function a(age){
    return function(){
        return age+10;
    }
} // 这就是一个闭包

// 对象式闭包:函数中有对象
function f1(age){
    return{
        age:age+20
    }
}
通过闭包缓存数据
function f1(){
    var num = parseInt(Math.random()*10+1);
    return num;
}
console.log(f1());
console.log(f1());
console.log(f1());

// 通过闭包实现,把每次产生的随机数都是一样的来进行缓存
function f2(){
    var num = parseInt(Math.random()*10+1);
    return function(){
        return num;
    }
}
var ff = f2();
console.log(ff());
console.log(ff());
console.log(ff());
console.log(ff());
通过闭包实现点赞

html和css就算了,上js

// 点击按钮实现点赞
function my$(tagName){
    return document.getElementsByTagName(tagName);
}
// 闭包缓存数据
function getValue(){
    var value = 2; // 用来记录赞的次数
    return function(){
        this.value="赞("+(value++)+")";
    }
}

// 遍历所有的按钮
for(var i = 0; i<my$("input").length;i++){
    my$('input')[i].onclick=getValue();
}

Memorization 记忆化

用处是优化递归

示例:

var fib=(function(){
    var arr=[]; // 定义一个数组来缓存数据
    return function(n){
        if(n==0||n==1){
            return n;
        }else{
            // 从数组中获取查询结果,如果没有重新计算
            arr[n-1]=arr[n-1]||fib(n-1);
            arr[n-2]=arr[n-2]||fib(n-2);
            return arr[n-1]+arr[n-2];
        }
    }
})();

沙箱

沙箱:在虚拟的世界里模拟外面真实的世界,结果会和真实的世界的效果是一样的,但是不会对外面的世界造成影响,为了避免变量污染的一个问题,就是一个函数的自调用----jQuery中都是这样的

// 函数的自调用
(function(){
    var num = 20 ; // 本身是局部变量
    console.log(num);
    win.num=num;// 此时这个就是一个全局变量
})(window)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值