<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>