<html>

<body>
  <script>
    // 1. let 在同一个作用域下不可重复声明
    // 2. let不会提升,会产生一个暂时性死区 
    // 3. let 只能在当前的作用域下生效
    // for (var i = 0; i < 10; i++) {
    //   i = 'a';
    //   console.log(i) // a
    // }

    // for (var i = 0; i < 10; i++) {
    //   var i = 'a';
    //   console.log(i); // a
    // }

    // for(let i = 0; i < 10; i++) {
    //   var i = 'a'; // i被提升了
    //   console.log(i); // Uncaught SyntaxError: Identifier 'i' has already been declared
    // }

    // for (let i = 0; i < 10; i++) {
    //   let i = 'a';
    //   console.log(i); // 10个 a
    // }

    // for (let i = 0; i < 10; i++) {
    //   i = 'a'; // 拿父级的i
    //   console.log(i); // a
    // }

    // var arr = {};
    // var _loop = function(i) {
    //   arr[i] = function() {
    //     console.log(arr[i]);
    //     console.log(i);
    //   }
    // }

    // for(var i = 0; i < 10; i++) {
    //   _loop(i);
    // }

    // for(var k = 0; k < 10; k++) {
    //   arr[k]();
    // }

    // const 一旦定义必须赋值,值不能修改
    // 有块级作用域,不能提升,有暂时性死区 
    // 与let一样不能重复声明

    // const obj = [];
    // Object.freeze(obj); // 冻结obj属性修改
    // obj.name = 'zhangsan';


    //函数的形参如果有默认值,则形参和实参(argument)的对应关系就不存在了


    // var x = 1;
    // function foo(x, y = function(){ x = 2; console.log(x)}) { // 执行时, x = 2,修改的是形参x, 输出:2
    //   var x = 3;
    //   y();
    //   console.log(x); // 3
    // }

    // foo();
    // console.log(x); // 1


    // 第二种:
    // var x = 1;
    // function foo(x, y = function () { var x = 2; console.log(x) }) { // 执行时, var x = 2,修改的不是形参x, 输出:2
    //   // var x = 3;
    //   y();
    //   console.log(x); // undefined
    // }

    // foo();
    // console.log(x); // 1

    // 第三种
    // var x = 1;
    // function foo(x, y = function () { let x = 2; console.log(x) }) { // 执行时, var x = 2,修改的不是形参x, 输出:2
    //   // var x = 3;
    //   y();
    //   console.log(x); // undefined
    // }

    // foo();
    // console.log(x); // 1


    //  var x = 1;
    //   function foo(x = 1, y = function () { x = x + 2; console.log(x) }) { // 执行时, var x = 2,修改的不是形参x, 输出:2
    //     // var x = 3;
    //     y();
    //     console.log(x); // undefined
    //     x = 5;
    //     y();
    //   }

    //   foo();
    //   console.log(x); // 1


    // this:
    // 1. 默认绑定规则:默认指向window, 但是在严格模式下,默认是undefined
    // 2. 隐式绑定:谁调用,指向谁
    // 3. 显示绑定: call, apply, bind
    // 4. new

    // apply(null/undefined,[...]) // null/undefined可以让this指向失效,指向window

    // 箭头函数中没有auguments

    // let fn = (a, b, ...c) => { // ...c, rest收集,将实参收集成一个数组, 必须是最后一个参数,输出c: [3, 4, 5, 6, 7]
    //   console.log(a, b, c)
    // }

    // fn(1, 2, 3, 4, 5, 6, 7)


    // console.log(function(b, c, d = 0, ...a){}.length); //2 默认值和收集运算符都不能被length拿到

    //   箭头函数的特性:
    //  1.  this,由外层的函数作用域决定, this指向是固化的,函数的内部并没有自己的this,只能通过父级函数来获取this
    //   2. 箭头函数不能作为构造函数来使用
    //   3. 没有arguments对象,用rest代替
    //   4.  yield命令不能生效,在generator函数中

    // const person = {
    //   eat() {
    //     console.log(this);
    //   },
    //   drink: () => {
    //     console.log(this); //
    //   }
    // };

    // person.eat(); // 输出this指向person
    // person.drink(); // 输出this指向window



    // function foo() {
    //   return () => {
    //     return () => {
    //       return () => {
    //         console.log('id', this.id);
    //       }
    //     }
    //   }
    // }

    // var f = foo.call({id: 1}); // 1
    // var f1 = f.call({id: 2})()(); // 1
    // var f2 = f().call({id: 3})(); // 1
    // var f3 = f()().call({id: 4}); // 1


    // 箭头函数使用场景:
    // 1. 简单的函数表达式,得出唯一的return的计算值,函数每部没有this的引用, 没有递归,事件绑定,解绑定,用重构 =〉的方式
    // 2. 内层函数表达式,需要调用this, var self = this, bind(this),确保适当的this指向的时候
    // 3. var args = Array.prototype.slice.call(arguments);
    // 4. 不适合用箭头函数的情况:函数声明,执行语句据较多, 需要递归,需要引用函数名,事件绑定,解绑定







    // 对象拓展:

    // var myObj = {};
    // myObj[true]  = 'foo'; // Boolean.prototype.toString.call(true) => "true"
    // myObj[3] = 'bar'; // Number.prototype.toString.call(3) => "3"
    // myObj[myObj] = 'baz'; // Object.prototype.toString.call(myObj) => "[object Object]"
    // console.log(myObj[{}]); // Object.prototype.toString.call({}) => "[object Object]", 输出baz

    // console.log(Object.getOwnPropertyDescriptor(myObj, '[object Object]'));
    // // configurable: true
    // // enumerable: true
    // // value: "baz"
    // // writable: true

    // var options = {
    //   configurable: false, //如果设置成false,则不能删除该属性
    //   enumerable: true,
    //   value: 'test',
    //   writable: false // 如果设置成false,则用myObj.myProterty = 'hi', 在正常模式下,不能修改, 在严格模式下,报错 
    // }

    // Object.defineProperty(myObj, 'myProterty', options); // 默认option中的值全是false

    // myObj.myProterty = 'update';
    // // delete myObj.myProterty;

    // console.log(myObj);

    // 总结:
    // 1. configurable: true && writable: true, 可编辑可删除
    // 2. configurable: true && writable: false, 不可编辑可删除
    // 3. configurable: false && writable: true, 可编辑不可删除
    // 3. configurable: false && writable: false, 不可编辑不可删除

    // let obj = {a: 1};

    // obj.a;// 属性的获取,[[Get]]默认操作,查找当前属性,如果没有,查找原型

    // obj.a = 3;
    // 赋值操作 [[Put]], 默认操作
    // 1. getter; setter;
    // 2. writable, false, 不让改
    // 3. 赋值

    // get 用法
    // var myObj = {
    //   get a() {
    //     return 2;
    //   }
    // };

    // Object.defineProperty(myObj, 'b', { // 默认
    //   get: function() {
    //     return this.a * 2;
    //   },
    //   enumerable: true,
    //   // writable: false
    //   // value: 'test'
    //   // writable和value不能配置, 因为get方法就是修改值的,和writable/value矛盾,所以如果有get设置writable/value会报错
    // });

    // console.log(myObj.a);
    // console.log(myObj.b);

    // set 用法
    // var language = {
    //   set current(name) {
    //     this.log.push(name)
    //   },
    //   log: []
    // }

    // language.current = 'Chinese';
    // language.current = 'English';
    // console.log(language); // ['Chinese', 'English']

    // get/set例子
    // var obj = {
    //   get a() {
    //     return this._a;
    //   },
    //   set a(value) {
    //     this._a =  value * 2;
    //   }
    // };

    // obj.a = 3;

    // console.log(obj.a); // 6

    // var obj = {
    //   a: 2
    // };

    // Object.preventExtensions(obj); // 禁止向对象中添加属性
    // Object.isExtensible(obj); // false 不可拓展, true可拓展
    // Object.seal(obj); // 对象的密封
    // Object.isSealed(obj);
    // Object.freeze(obj); // 被冻住
    // Object.isFrozen(obj);
    // Object.is(NaN, NaN); // true , is判断是否相等
    // Object.is(+0, -0); // false
    // Object.assign(tar, ...sources)
    // Object.defineProperties(obj, {a: {value: 'a', writable: true}, b: {value: b, enumerable: true}}); // 定义多个属性,descriptors默认值都是false


    // obj.a = 3;
    // obj.b = 4;

    // console.log(obj); // {a: 3}


    // let obj = {a: 1};
    // let obj2 = {a: 2};
    // let tar = {};
    // let copy = Object.assign(tar, obj, obj2); // 从前往后覆盖 tar = {a: 2}; tar必须是一个对象,null和undefined会报错
    // console.log(copy === tar); // true, Object.assign返回tar对象

    // let tar2 = {},
    //   tar3 = {};

    // console.log(Object.assign(1, obj)); // Number {a: 1}
    // console.log(Object.assign(tar2, 1)); // {}
    // console.log(Object.assign(tar3, '123')); // {0: "1", 1: "2", 2: "3"}
    // object.assign 
    // 1. 继承属性和不不可枚举属性 不能拷贝
    // 2. 拷贝是属于浅拷贝 
    // 3. target和 source里面有相同属性,target会被source的属性值替换 
    // 4. 数组的拷贝,会根据下标相同被替换 object.assign([1,2,3],[4, 5]) => [4, 5, 3]
    // 5. 可以在原型上扩充方法和属性


    // 修改对象原型
    // obj.__proto__ = {} // 不推荐这个方法修改属性
    // 1. 语义化,是内部属性
    // 2. 访问效率慢
    // 3. 所有继承自该原型的对象都会被影响到

    // 推荐使用的方法:
    // Object.setPrototypeOf(); // 设置原型属性
    // Object.getPrototypeOf(); // 访问原型属性

    // let proto = {
    //   y: 20,
    //   z: 40
    // };

    // let obj = {x: 0};

    // Object.setPrototypeOf(obj, proto);

    // console.log(obj);


    // let obj = Object.setPrototypeOf(1, {a:1, b:2});  // 不是对象的参数,设置prototype时,会直接将参数转换成包装类的原型,而原本设置的{a:1, b:2}会设置失败
    // // => Object.setPrototypeOf(Number(1), {a: 1, b: 2});

    // console.log(Object.getPrototypeOf(1) === Number.prototype);

    // let obj = Object.setPrototypeOf('test', {a:1, b:2});
    // console.log(Object.getPrototypeOf(obj) === String.prototype);

    // let obj = Object.setPrototypeOf(true, {a:1, b:2});
    // console.log(Object.getPrototypeOf(obj) === Boolean.prototype);

    // let obj = Object.setPrototypeOf(null, {a:1, b:2}); // 报错: Object.setPrototypeOf called on null or undefined
    // let obj = Object.setPrototypeOf(undefined, {a:1, b:2}); // 报错: Object.setPrototypeOf called on null or undefined

    // Object.keys()
    // Object.values()
    // Object.entries()


    // const foo = {
    //   a: 1,
    //   b: 2,
    //   c: 3
    // };

    // Object.defineProperties(foo, {
    //   d: {
    //     value: 4,
    //     enumerable: true
    //   },
    //   f: {
    //     value: 5,
    //     enumerable: false
    //   }
    // });

    // console.log(Object.keys(foo)); // [a, b, c, d] 获取自身的可枚举键名,不含继承属性,返回成数组
    // console.log(Object.values(foo)); // [1, 2, 3, 4] 获取自身的可枚举键值,不含继承属性,返回成数组
    // console.log(Object.entries(foo)); // [{a: 1}, {b: 2}, {c: 3}, {d: 4}]

    // Object.keys(1); // []
    // Object.keys('abc'); // ['0', '1', '2']
    // Object.keys(true); // []
    // Object.values(1); // []
    // Object.values('abc'); // ['a', 'b', 'c']
    // Object.values(true); // []
    // Object.keys(null); // 报错:Cannot convert undefined or null to object
    // Object.keys(undefined); // 报错: Cannot convert undefined or null to object
    // Object.values(null); // 报错:Cannot convert undefined or null to object
    // Object.values(undefined); // 报错: Cannot convert undefined or null to object



    // Super(指向的是对象的原型对象) --> this
    // super只能在对象的简写的写法的方法内部才能生效
    // let proto = {
    //   y: 20,
    //   z: 40
    // };

    // let obj = {
    //     x: 0,
    //     // foo: super.y // Uncaught SyntaxError: 'super' keyword unexpected here
    //     // foo: function() {
    //     //   console.log(super.y)  // Uncaught SyntaxError: 'super' keyword unexpected here
    //     // }
    //     foo() {
    //       console.log(super.y)
    //     }
    //   };

    // Object.setPrototypeOf(obj, proto);
    // console.log(obj);







    // Symbol 
    // 1. (原始值类型的值)
    // 原始类型: string, number, boolean, null, undefined, symbol
    // 引用类型: Object Array Function
    // 2. 为了解决对象属性名重复的问题存在的
    // 3. 挂不上属性

    // let s1 = Symbol('b');
    // let s2 = Symbol('b');
    // s1.a = 1;
    // console.log(s1 === s2); // false
    // console.log(typeof(s1)); // symbol
    // console.log(s1.a); // undefined

    // console.log(Symbol(1)); // Symbol(1)  => Object.prototype.toString()
    // console.log(Symbol('abc')); // Symbol(abc)
    // console.log(Symbol(true)); // Symbol(true)
    // console.log(Symbol(null)); // Symbol(null)
    // console.log(Symbol(undefined)); // Symbol()

    // let s1 = Symbol(null);
    // console.log(String(s1)); // Symbol(null)
    // console.log(Boolean(s1)); // true
    // console.log(Number(s1)); // 报错: Cannot convert a Symbol value to a number

    // let s1 = Symbol('abc')
    // console.log(Object.getPrototypeOf(s1));
    // console.log(s1.toString()) // Symbol(abc)

    // let name = Symbol();
    // let age = Symbol('age');
    // let eat = Symbol();
    // let person = {
    //   [age]: 14,
    //   [eat]() {
    //     console.log(this[age]);// 14
    //   }
    // };
    // person[name] = 'zhangsan';

    // Object.defineProperty(person, Symbol('age'), {
    //   value: 18
    // })

    // console.log(person); 
    // // {Symbol(): "zhangsan",
    // // Symbol(age): 14,
    // // Symbol(age): 18}
    // // Symbol类型的属性名的访问:
    // console.log(person[age]);

    // let s1 = Symbol.for('foo');
    // let s2 = Symbol.for('foo');
    // console.log(s1 === s2); // true
    // console.log(Symbol.keyFor(s1)); // foo

    // let s3 = Symbol('foo');
    // let s4 = Symbol('foo');
    // console.log(s3 === s4); // false
    // console.log(Symbol.keyFor(s4)); //  undefined

    // 遍历: 
    // for in 不能遍历Symbol属性的对象, 但是能遍历出来所有自身和原型上的可枚举属性
    // Object.key() 只能遍历自身不包含Symbol的可枚举属性
    // Object.getOwnPropertySymbols(obj); // 只能遍历Symbol类型的属性
    // Object.assign(); // 遍历自身可枚举的,包含Symbol类型的属性


    // 迭代器:对数据结构(下面的数据结构)的读取的一种方式,有序的,连续的,给予拉取的一种消耗数据的组织方式

    // array, arguments, nodeList, Map, set, weakMap, weakset 类数组, TypeArray

    // function makeInterator(arr) {
    //   var nextIndex = 0;
    //   return {
    //     next() {
    //       if(nextIndex < arr.length) {
    //         return { value: arr[nextIndex++], done: false };
    //       } else {
    //         return { value: undefined, done: true };
    //       }
    //     }
    //   }
    // }

    // 对象的数组迭代器
    // let obj = {
    //   start: [1, 2, 3],
    //   end: [4, 5, 6],
    //   [Symbol.iterator]() {
    //     var nextIndex = 0,
    //     arr = [...this.start, ...this.end],
    //     len = arr.length;
    //     return {
    //       next() {
    //         if(nextIndex < len) {
    //           return  { value: arr[nextIndex++], done: false };
    //         } else {
    //           return { value: undefined, done: true };
    //         }
    //       }
    //     };
    //   }
    // };

    // for(var value of obj) {
    //   console.log(value);
    // }

    // 对象属性的迭代器
    // let obj2 = {
    //   a: 1,
    //   b: 2,
    //   c: 3,
    //   [Symbol.iterator]() {
    //     let map = new Map(),
    //      nextIndex = 0;
    //     for(let [key, value] of Object.entries(this)) {
    //       map.set(key, value);
    //     }
    //     console.log(map.entries());
    //     let mapEntries = [...map.entries()];
    //     return {
    //       next() {
    //         return nextIndex < mapEntries.length ? { value: mapEntries[nextIndex++], done: false}: {value: undefined, done: true}
    //       }
    //     }
    //   }
    // }

    // for(let i of obj2) {
    //   console.log(i);
    // }

    // 调用iterator的情况: ...拓展运算符, for...of, Array.from(), map, set, promise.all(), promise.race, yield

    // function* test() { 
    //   yield 'a';
    //   console.log(1);
    //   yield 'b';
    //   yield 'c';
    //   return 'd';
    // }
    // let iter = test(); // 返回值是迭代器对象
    // console.log(iter.next()); // 代码执行到第一个yeild处
    // console.log(iter.next()); // 代码执行到第二个yeild处, 并且会打印1
    // console.log(iter.next());
    // console.log(iter.next());
    // console.log(iter.next());






    // set 类似数组,但是不存在相同的值(NaN除外)
    // add 添加值,返回值是set本身
    // delete 返回是否删除成功
    // clear 删除所有值,返回值是undefined
    // has 是否存在, true/false
    // keys 键名和键值相同, 返回一个键名的迭代器
    // values 返回一个键值的迭代器
    // entries 返回一个键名和键值的迭代器
    // size

    // let set = new Set([{a: 1}, {b: 1}]);
    // console.log(set.keys())
    // console.log(set.values())
    // console.log(set.entries())
    // console.log(Set.prototype[Symbol.iterator] === Set.prototype.values);

    // 数组去重
    // var arr = [1, 2, 3, 5, 5, 3, 2, 6];
    // console.log([...new Set(arr)]);

    // .map方法只有数组才有

    // let a = new Set([1, 2, 3]);
    // let b = new Set([3, 5, 4]);

    // // 交集
    // let intersect = new Set([...a].filter(x => b.has(x)))
    // // 并集
    // let union = new Set([...a, ...b])
    // // 差集
    // let difference = new Set([...a].filter(x => !b.has(x)))



    // Map 用法

    // let m  = new Map();
    // var x = {id: 1},
    //     y = {id: 2};
    // m.set(x, 'foo');
    // m.set(y, 'bar');

    // console.log(m);


    // let m1 = new Map([['name', 'zhangsan'], ['title', 'dev']]);
    // // m1.set('name', 'lisi');
    // console.log(m1)

    // let m2 = new Map();
    // // m1.forEach((value, key) => {m2.set(key, value)})
    // // m1.forEach((value, key) => {console.log('value:'+ value, 'key:'+ key)})
    // m1.forEach(([value, key]) => {console.log('value:'+ value, 'key:'+ key)});


    // let m3 = new Map();
    // m3.set(true, '1');
    // m3.set('true', '2');
    // m3.set(undefined, 3);
    // m3.set(null, 4);
    // m3.set(NaN, 5);
    // m3.set([], 6);
    // m3.set({}, 7);

    // console.log(m3.get(true)); // 1
    // console.log(m3.get('true')); // 2
    // console.log(m3.get(undefined)); // 3
    // console.log(m3.get(null)); // 4
    // console.log(m3.get(NaN)); // 5
    // console.log(m3.get([])); // undefined
    // console.log(m3.get({})); // undefined

    // NaN
    // console.log(NaN === NaN); // false
    // console.log(Object.is(NaN, NaN)); // true
    // console.log(m3.get(NaN)); // 5
    // console.log(m3[Symbol.iterator] === m3.entries);

    // Map 方法:
    // get
    // set
    // size
    // clear
    // delete
    // has
    // keys
    // values
    // entries


    // 数组 map 相互转换
    // let map1 = new Map();
    // map1.set(true, 7);
    // map1.set('id', 'a');

    // // map -> array
    // let arr = [...map1];
    // console.log(arr);

    // // array->map
    // // let map2 = 

    // // map -> obj // map key must be a string not obj
    // function mapToObj(map) {
    //   let obj = {};
    //   for([key, value] of map.entries()) {
    //     obj[key] = value;
    //   }
    //   return obj;
    // }

    // console.log(mapToObj(map1));
    // let obj = {
    //   a: 1,
    //   b: 4
    // }
    // function objToMap(obj) {
    //   let map = new Map();
    //   // for(key of Object.keys(obj)) {
    //   //   map.set(key, obj[key]);
    //   // }
    //   for([key, value] of Object.entries(obj)) {
    //     map.set(key, value);
    //   }
    //   return map;
    // }

    // console.log(objToMap(obj));



    // WeakMap/WeakSet 成员只能是对象

    // proxy
    // let star = {
    //   name: 'li**',
    //   age: 25,
    //   phone: 'star 1244333333'
    // }

    // let agent = new Proxy(star, {
    //   get: function(target, key){
    //     if(key === 'phone') {
    //       return 'agent 12345678890'
    //     }

    //     if(key === 'price') {
    //       return 12000;
    //     }

    //     return target[key]
    //   },
    //   set: function(target, key, value) {
    //     if(value < 100000) {
    //       throw new Error('low price');
    //     } else {
    //       target[key] = value;
    //       return value;
    //     }
    //   },
    //   has: function(target, key) {
    //     if(key === 'customPrice') {
    //       return target[key]
    //     } else {
    //       return false;
    //     }
    //   }
    // });

    // console.log(star);
    // console.log(agent.price);
    // console.log(agent.phone);
    // console.log(agent.name);
    // console.log(agent.age);
    // agent.customPrice = 1000000;
    // console.log(agent.customPrice);

    class Person {
      constructor(name = 'zhangsan', age = '18') {
        // 实例化的属性配置: 私有属性
        this.name = name;
        this.age = age;
      }
      // 共有属性
      say() {
        console.log(this.name+':'+this.age);
      }

      eat() {
        console.log('I can eat');
      }

      drink() {
        console.log('I can drink');
      }
    }

    // let Person = class {
    //   say() {
    //     console.log(1)
    //   }
    // }

    let p =new Person();
    p.name = '11111';
    console.log(p)

    // 构造函数和类的区别
    // 1. 类内部的方法是不可枚举的, 原型上的方法是可枚举的
    // 2. 类必须通过new 的方式执行, 构造函数可以立即执行
  </script>
</body>

</html>

 

posted on 2019-12-27 11:01  yyy_鸳鸯  阅读(257)  评论(0编辑  收藏  举报