十四、三目运算符、对象克隆、浅拷贝、深拷贝、模块化复习

十四、三目运算符、对象克隆、浅拷贝、深拷贝、模块化复习

一、三目运算符

又叫三元运算符,相当于if的三段式:

var a = 5;
if(a > 0){
    console.log('大于0');
}else{
    console.log('小于等于0');
}

a > 0 ? console.log('大于0') //相当于三段式if
      :console.log('小于等于0');

1.1 三目运算符的特点

可以用一个变量去接收三目运算的结果,即三目运算会默认return结果。

var a = 5;
var str = a > 0 ? '大于0' //相当于这里有return
				: '小于等于0';

console.log(str); // '大于0'

if判断里可以嵌套if,当然三目运算中也可以嵌套三目运算:

var a = 3,
    str = '';
if(a > 0){
    if(a > 3){
        str = '大于3';
    }else{
        str = '大于0小于等于3';
    }
}else{
    str = '小于等于0';
}
console.log(str); //'大于0小于等于3'

用三目运算符来判断:

str = a > 0 ? (
    			a > 3 ? '大于3' 
                      : '大于0小于等于3'
			  )
            : '小于等于0';
console.log(str); //'大于0小于等于3'

一个关于三目的面试题:

var str = 89 > 9 ?(
                    '89' > '9' ? '通过了'
                               : '没通过'
                  )
                 : '外层通过了';
console.log(str);

控制台输出'没通过'

89>9结果为ture,进入冒号前的三目运算嵌套;比较运算符两侧都为字符串时,从第一个字符开始一 一 比较字符编码ASCII码值;字符8的ASCII码值小于字符9的ASCII码值,比较结束,判断为false,返回冒号后面的结果,即'没通过'

二、对象克隆

前导知识:

​ 字面量形式创建的对象实际上是由new Object()创建的

——>所以字面量对象的__proto__指向了0bject.prototype

——>0bject.prototype是所有对象(非自定义原型)的原型对象

——> 所有对象都继承0bject.prototype上的属性

2.1 浅拷贝

使用for in 遍历对象,把一个对象中的所有属性复制到另一个新对象中。

但是for in 遍历对象时,会把对象的原型链上的自定义属性也复制到新对象中,怎么办呢?

使用hasOwnProperty只选择源对象自身的属性。

Object.prototype.num = 1;
var person1 = {
    name: 'white',
    age: 22,
    friends: {
        first: 'jack',
        second: 'perter',
        third: 'rose'
    } 
}
var person2 = {};
for(key in person1){
    if(person1.hasOwnProperty(key)){
        person2[key] = person1[key]
    }
}
console.log(person1);
console.log(person2);

浅拷贝成功,新对象与源对象内容一模一样:

十四、三目运算符、对象克隆、浅拷贝、深拷贝、模块化复习

可以对浅拷贝的过程代码进行一个封装:

var person2 = clone(person1, person2);
function clone(origin, target){
    var target = target || {}; //提高用户体验
    for(key in origin){
        if(origin.hasOwnProperty(key)){
            target[key] = origin[key]
        }
    }
    return target;
}

给我们的新对象增加一个属性,类型为原始值;

在新对象的引用值内增加一个新属性:

person2.height = 180;
person2.friends.forth = 'ning';
console.log(person1);
console.log(person2);

打印源对象和新对象:

十四、三目运算符、对象克隆、浅拷贝、深拷贝、模块化复习

浅拷贝的不足:

浅拷贝之后更改新对象的属性,当属性值为引用值时,会同时更改源对象相应的引用值。新对象和源对象产生了联系!

2.2 深拷贝

解决浅拷贝的不足,使克隆出的新对象与源对象没有任何关系,对新对象的引用值的增删改查都不会影响到源对象。

深拷贝时也可以对拷贝过程进行封装。

深拷贝过程如下:

// 拷贝对象时,都是拷贝数组或者对象
Object.prototype.num = 1;
var person1 = {
    name: 'white',
    age: 22,
    friends: {
        first: {
            name: 'jack',
            age: 22
        },
        second: {
            name: 'perter',
            age: 20
        },
        third: {
            name: 'rose',
            age: 33
        }
    },
    car: ['Benz', 'Mazda']
}

var person2 = deepClone(person1,person2);
person2.height = 180;
person2.friends.forth = {
    name: 'ning',
    age: 49
}
person2.car.push('audi');

console.log(person1,person2);

function deepClone(origin, target){
    var target = target || {};//用户体验
    var toStr = Object.prototype.toString,//缓存方法
        arrType = '[object Array]';

    for(var key in origin){
        // 先判断要复制的是对象自身的属性,不要原型链上的自定义属性
        if(origin.hasOwnProperty(key)){
            // 判断属性值数据类型是不是引用值 且 引用值不等于null
            if(typeof(origin[key]) === 'object' && origin[key] !== null){
                if(toStr.call(origin[key]) === arrType){
                    // 如果引用值是数组,那新对象的属性就声明为一个空数组
                    target[key] = [];
                }else{
                    // 如果引用值是对象,那新对象的属性就声明为一个空对象
                    target[key] = {};
                }
                // 对于引用值的内容进行递归
                deepClone(origin[key], target[key])
            }else{
                // 不是引用值就直接赋值
                target[key] = origin[key];
            }
        }
    }
    
    return target;
}

十四、三目运算符、对象克隆、浅拷贝、深拷贝、模块化复习

深拷贝后的新对象和源对象没有任何关系。

2.3 JSON深拷贝(不推荐)

使用JSON.stringify把对象变成字符串,再使用JSON.parse把字符串变成JSON对象。

Object.prototype.num = 1;
var person1 = {
    name: 'white',
    age: 22,
    friends: {
        first: {
            name: 'jack',
            age: 22
        },
        second: {
            name: 'perter',
            age: 20
        },
        third: {
            name: 'rose',
            age: 33
        }
    },
    car: ['Benz', 'Mazda']
}

var str = JSON.stringify(person1);
var person2 = JSON.parse(str);
person2.height = 180;
person2.friends.forth = {
    name: 'ning',
    age: 49
}
person2.car.push('audi');
console.log(person2,person1);

三、模块化复习

3.1 协同作业

每个人单独创建一个作用域,把IIFE返回的函数保存到全局的变量中,等待执行。

每个人写的模块不是立即执行的,需要一些条件后再执行;

模块化的好处也不仅是防止污染全局变量,创建独立的空间;而且把返回的函数保存到GO中等待执行。

/* 实现三个功能:
 *打印一个参数值以内能被 3 或 5 或 7 整除的数
 *打印斐波那契数列的第 n 位
 *打印从 0 到一个数的累加值 
 */

//窗口执行完毕以后执行init

// 如果不是这么写,而是init()时是不能执行的
// 因为变量还未被赋值,值为 undefined ,执行到赋值时,才变成函数表达式
window.onload = function(){
    init();
}
//  初始化函数
function init(){
    console.log(divided(50));
    console.log(fbnq(5));
    console.log(add(100));
}
//  IIFE + 闭包
// 打印一个参数值以内能被 3 或 5 或 7 整除的数
var divided = (function(){
    return function(j){
        var arr = [];
        for(var i = 0; i <= j; i++){
            if( i % 3 == 0 || i % 5 == 0 || i % 7 == 0){
                arr.push(i);
            }
        }
        return arr;
    }
})();
// 打印斐波那契数列的第 n 位
var fbnq = (function(){
    return function fn(n){
        if(n <= 0){
            return 0
        }
        if(n <= 2){
            return 1;
        }
        return fn(n-1) + fn(n-2);
    }
})();
// 打印从 0 到一个数的累加值 
var add = (function(){
    return function(n){
        var sum = 0;
        for(var i = 0; i <= n; i++){
            sum += i;
        }
        return sum;
    }
})();

十四、三目运算符、对象克隆、浅拷贝、深拷贝、模块化复习

3.2 插件

出现即执行。例如轮播图插件,打开网页就执行。

所以插件的标准形式是IIFE+构造函数相关+原型+window暴露到全局/用全局变量接收

等待全局执行或者就直接让它执行。

;(function(){
    //函数声明或者函数表达式都可以
   var Test = function(){
       
   }
   Test.prototype = {
       
   }
    
   window.Test = Test;
})()

总结:模块化的重点在于把IIFE返回的结果保存到GO中等待执行;而插件可以立即执行达到效果。

上一篇:check List是否有相同的数据


下一篇:Day2-JS-this 关键字