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