zoukankan      html  css  js  c++  java
  • 红宝书4-第八章对象、类与面向对象编程(2)

    @


    1.对象标识及相等判定

    问题引入:

    es6之前 === 的局限性,如下:

    1.这些是===符合预期的情况
    console.log(true === 1);  // false 
    console.log({} === {});   // false 
    console.log("2" === 2);   // false 
    
    2.这些情况在不同 JavaScript 引擎中表现不同,但仍被认为相等
    console.log(+0 === -0);   // true 
    console.log(+0 === 0);    // true 
    console.log(-0 === 0);    // true 
    
    3.要确定 NaN 的相等性,必须使用极为讨厌的 isNaN()
    console.log(NaN === NaN); // false 
    console.log(isNaN(NaN));  // true
    

    利用 Object.is()进行判定

    这个方法与===很像,但同时也考虑 到了上述边界情形。这个方法必须接收两个参数

    console.log(Object.is(true, 1));  // false 
    console.log(Object.is({}, {}));   // false 
    console.log(Object.is("2", 2));   // false
    // 正确的 0、-0、+0 相等/不等判定 
    console.log(Object.is(+0, -0));   // false 
    console.log(Object.is(+0, 0));    // true 
    console.log(Object.is(-0, 0));    // false 
    // 正确的 NaN 相等判定 
    console.log(Object.is(NaN, NaN)); // true
    

    要检查超过两个值,递归地利用相等性传递即可:

    function recursivelyCheckEqual(x, ...rest) 
    {   return Object.is(x, rest[0]) && (rest.length < 2 || recursivelyCheckEqual(...rest)); } 
    

    2.增强的对象语法

    1. 属性值简写

    简写属性名只要使用变量名(不用再写冒号)就会自动被解释为同 名的属性键。如果没有找到同名变量,则会抛出 ReferenceError

    let name = 'Matt';  
    let person = {   name }; 
    console.log(person); // { name: 'Matt' }
    

    2. 可计算属性

    在引入可计算属性之前,如果想使用变量的值作为属性,那么必须先声明对象,然后使用中括号语 法来添加属性。

    有了可计算属性,就可以在对象字面量中完成动态属性赋值。中括号包围的对象属性键告诉运行时 将其作为 JavaScript表达式而不是字符串来求值:

    const nameKey = 'name'; const ageKey = 'age'; const jobKey = 'job'; 
     
    let person = {    [nameKey]: 'Matt',   [ageKey]: 27,   [jobKey]: 'Software engineer' }; 
     
    console.log(person); // { name: 'Matt', age: 27, job: 'Software engineer' } 
    

    因为被当作 JavaScript表达式求值,所以可计算属性本身可以是复杂的表达式,在实例化时再求值:

    const nameKey = 'name';  
    const ageKey = 'age'; 
    const jobKey = 'job'; 
    let uniqueToken = 0; 
     
    function getUniqueKey(key) {   
    return `${key}_${uniqueToken++}`; 
    } 
     
    let person = {   
    	[getUniqueKey(nameKey)]: 'Matt',   
    	[getUniqueKey(ageKey)]: 27,   
    	[getUniqueKey(jobKey)]: 'Software engineer' }; 
     
    console.log(person);  // { name_0: 'Matt', age_1: 27, job_2: 'Software engineer' } 
    

    注意 可计算属性表达式中抛出任何错误都会中断对象创建。如果计算属性的表达式有副 作用,那就要小心了,因为如果表达式抛出错误,那么之前完成的计算是不能回滚的

    3. 简写方法名

    let person = {    sayName(name) {     console.log(`My name is ${name}`);   } }; 
     
    person.sayName('Matt'); // My name is Matt
    

    简写方法名对获取函数和设置函数也是适用的:

    let person = {    
    	name_: '',   
    	get name() {     
    		return this.name_;   
    		},   
    	set name(name) {     
    		this.name_ = name;   
    		},   
    	sayName() {     
    		console.log(`My name is ${this.name_}`);   
    		} 
    	}; 
    person.name = 'Matt'; person.sayName(); // My name is Matt 
    

    简写方法名与可计算属性键相互兼容:

    const methodKey = 'sayName';  
     
    let person = {   [methodKey](name) {     console.log(`My name is ${name}`);   } } 
     
    person.sayName('Matt'); // My name is Matt 
    

    3.对象解构

    使用解构,可以在一个类似对象字面量的结构中,声明多个变量,同时执行多个赋值操作。如果想 让变量直接使用属性的名称,那么可以使用简写语法,比如:

    let person = {    name: 'Matt',   age: 27 }; 
     
    let { name, age } = person; 
     
    console.log(name);  // Matt console.log(age);   // 27 
    

    解构赋值不一定与对象的属性匹配。赋值的时候可以忽略某些属性,而如果引用的属性不存在,则 该变量的值就是 undefined:

    也可以在解构赋值的同时定义默认值,这适用于前面刚提到的引用的属性不存在于源对象中的 情况:

    let person = {   name: 'Matt',    age: 27 }; 
     
    let { name, job='Software engineer' } = person; 
     
    console.log(name); // Matt console.log(job);  // Software engineer 
    

    解构在内部使用函数 ToObject()(不能在运行时环境中直接访问)把源数据结构转换为对象。这 意味着在对象解构的上下文中,原始值会被当成对象。这也意味着(根据 ToObject()的定义),nullundefined 不能被解构,否则会抛出错误。

    let { length } = 'foobar';  console.log(length);        // 6 
     
    let { constructor: c } = 4; console.log(c === Number);  // true 
     
    let { _ } = null;           // TypeError 
     
    let { _ } = undefined;      // TypeError 
    

    解构并不要求变量必须在解构表达式中声明。不过,如果是给事先声明的变量赋值,则赋值表达式 必须包含在一对括号中

    let personName, personAge; 
     
    let person = {   name: 'Matt',   age: 27 }; 
     
    ({name: personName, age: personAge} = person); 
     
    console.log(personName, personAge); // Matt, 27 
    

    1. 嵌套解构

    解构对于引用嵌套的属性或赋值目标没有限制。为此,可以通过解构来复制对象属性

    let person = {    name: 'Matt',   age: 27,   job: {     title: 'Software engineer'   } }; let personCopy = {}; 
     
     
    ({   name: personCopy.name,   age: personCopy.age,   job: personCopy.job } = person); 
     
    // 因为一个对象的引用被赋值给 personCopy,所以修改 // person.job 对象的属性也会影响 personCopy person.job.title = 'Hacker' 
     
    console.log(person); // { name: 'Matt', age: 27, job: { title: 'Hacker' } } 
     
    console.log(personCopy); // { name: 'Matt', age: 27, job: { title: 'Hacker' } } 
    

    解构赋值可以使用嵌套结构,以匹配嵌套的属性

    在外层属性没有定义的情况下不能使用嵌套解构。无论源对象还是目标对象都一样:

    let person = {    
    	job: {     
    	title: 'Software engineer'   
    	} }; 
    
    let personCopy = {}; 
     
    // foo 在源对象上是 undefined 
    ({   foo: {     bar: personCopy.bar   } } = person); // TypeError: Cannot destructure property 'bar' of 'undefined' or 'null'. 
     
    // job 在目标对象上是 undefined 
    ({   job: {     title: personCopy.job.title   } } = person); // TypeError: Cannot set property 'title' of undefined 
    

    2. 部分解构

    需要注意的是,涉及多个属性的解构赋值是一个输出无关的顺序化操作。如果一个解构表达式涉及 多个赋值,开始的赋值成功而后面的赋值出错,则整个解构赋值只会完成一部分

    let person = {    name: 'Matt',   age: 27 }; 
     
    let personName, personBar, personAge; 
     
    try {   // person.foo 是 undefined,因此会抛出错误   
    ({name: personName, foo: { bar: personBar }, age: personAge} = person); 
    } 
    catch(e) {} 
     
    console.log(personName, personBar, personAge); // Matt, undefined, undefined 
    

    3. 参数上下文匹配

    在函数参数列表中也可以进行解构赋值。对参数的解构赋值不会影响 arguments 对象,但可以在
    函数签名中声明在函数体内使用局部变量:

    let person = {   name: 'Matt',    age: 27 }; 
     
    function printPerson(foo, {name, age}, bar) {   console.log(arguments);   console.log(name, age); } 
     
    function printPerson2(foo, {name: personName, age: personAge}, bar) {   console.log(arguments);   console.log(personName, personAge); } 
     
    printPerson('1st', person, '2nd'); // ['1st', { name: 'Matt', age: 27 }, '2nd'] // 'Matt', 27 
     
    printPerson2('1st', person, '2nd'); // ['1st', { name: 'Matt', age: 27 }, '2nd'] // 'Matt', 27 
    8
    

        感谢您花时间阅读此篇文章,如果您觉得看了这篇文章之后心情还比较高兴,可以打赏一下,请博主喝上一杯咖啡,让博主继续码字……
        本文版权归作者和博客园共有,来源网址:https://blog.csdn.net/weixin_46498102 欢迎各位转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接
  • 相关阅读:
    九度OJ 1185:特殊排序 (排序)
    九度OJ 1184:二叉树遍历 (二叉树)
    九度OJ 1183:守形数 (数字特性)
    九度OJ 1182:统计单词 (计数)
    九度OJ 1181:遍历链表 (链表、排序)
    九度OJ 1180:对称矩阵 (矩阵计算)
    PCH 中定义宏 系统版本
    UIScrollView
    GestureRecognizer
    UITextField 属性
  • 原文地址:https://www.cnblogs.com/jackson1/p/13794786.html
Copyright © 2011-2022 走看看