函数名.name:函数名获取
函数表达式方式,获取匿名函数名称
var f=function (){console.log(arguments.callee.name); // f 可以拿到匿名函数console.log(f.name); // f}/*es5会打印空“” 因为现在都是es6,所以看不到es5的情况*/console.log(f.name);//ff();
函数表达式方式,获取函数名称
名字被第二个覆盖了,但调用时得调用第一个名字
var f = function fn() {console.log(arguments.callee.name); // fnconsole.log(f.name); // fn}console.log(f.name); // fnf();// fn();//ReferenceError: fn is not defined
new构造函数函数名字anonymous
// console.log(new Function.name);//TypeError: Function.name is not a constructorconsole.log(new Function().name);//anonymousconsole.log((new Function).name);//anonymous
bind与函数名
function foo(){}console.log(foo.name);//fooconsole.log(foo.bind({}).name);//bound foo从 //TypeError: Cannot read properties of undefined (reading 'name')
对象的扩展:对象简写
属性变量名一致时可以简写
const foo="bar";const baz={foo};// const baz={foo:foo};console.log(baz);//{ foo: 'bar' }
const foo="bar";const baz={foo};/*当属性名=变量名的时候可以简写* foo等价于* 属性名foo:变量名foo*/// const baz={foo:foo};console.log(baz);//{ foo: 'bar' }

function foo(a,b){console.log({a,b});//{ a: 1, b: 2 }console.log({a:a*2,b:b*2});//{ a: 2, b: 4 }}foo(1,2);
方法简写
const person={age:'12',say(){console.log(this.age)}}person.say()//12
箭头函数简写
/*function foo(a,b){console.log({a,b});//{ a: 1, b: 2 }console.log({a:a*2,b:b*2});//{ a: 2, b: 4 }}foo(1,2);*/function foo(a=1,b=2){return {a,b}}let foo=(a=1,b=2)=>{a,b};
解构赋值应用:包的导出与引用
导出
root.js
function foo() {console.log(1)}function bar() {console.log(2)}function baz() {console.log(3)}let a = 3;const obj = {a,foo,bar,baz}module.exports.obj=obj;console.log(obj);/*{a: 3,foo: [Function: foo],bar: [Function: bar],baz: [Function: baz]}*/
引用
main.js引用
const obj=require('./root').obj;console.log(obj);/*{a: 3,foo: [Function: foo],bar: [Function: bar],baz: [Function: baz]}{a: 3,foo: [Function: foo],bar: [Function: bar],baz: [Function: baz]}*/
通过解构赋值拿到对象
// const obj=require('./root').obj;/*通过解构赋值从obj拿到属性*/// const {a:a,foo:foo,bar:bar,baz:baz}=require('./root').obj;const {a, foo, bar, baz} = require('./root').obj;console.log(a);//3foo();//1bar();//2baz();//3
属性是字符串
var arr = [1, 23, 23, 45, 5];/*属性会进行包装,把所有传入的值进行一个包装,变成字符串* 定义的属性都是字符串*/console.log(arr[1]);//23console.log(arr["1"]);//23
const obj={/* class(){}*//*在对象中定义class方法,也可以,不冲突,但不推荐这样做* 其实是把class变成字符串*/"class":function (){}}
字符串可以用方法来利用它们
let obj={};obj.foo=true;console.log(obj);//{ foo: true }/*拼接属性,通过表达式让属性拼接,变量相加减都是可以的*/obj['f'+'o'+'o']=false;console.log(obj);//{ foo: false }
通过字符串拼接成属性
属性名都会通过一种方式把它处理成字符串
let a='hello';let b='world';/*三句话都是给obj的helloworld属性赋值*/let obj={[a+b]:true,['hello'+b]:123,['hello'+'world']:undefined}console.log(obj);//{ helloworld: undefined }
[true]、[obj]属性的转换
通过原型上的方法转换成字符串,再从对象中查找属性(字符串)
与类型有关,Number、Boolean、对象Object、数组也是对象但是用Array
var myObject = {};/*直接把true变成字符串*/myObject[true] = 'foo';myObject[3] = 'bar';myObject[myObject] = 'baz';console.log(myObject);//{ '3': 'bar', true: 'foo', '[object Object]': 'baz' }console.log(myObject['true']);//fooconsole.log(myObject['3']);//barconsole.log(myObject[myObject]);//baz/*myObject对象被Object.prototype.toString方法转换成/[object Object]字符串,注意有[],* 不是转换成myObject字符串*/console.log(myObject['myObject']);//undefinedconsole.log(myObject['[object Object]']);//trueconsole.log(Boolean.prototype.toString.call(true));//trueconsole.log(Object.prototype.toString.call(myObject));//[object Object]
步骤类似于以下伪代码,对象[属性x],判断属性x的值进行不同的xxx.prototype.toString.call(x)转换
/*伪代码不能运行*/var obj={};obj[x]=1;if(typeof x==='Number'){obj[Number.prototype.toString.call(x)]=1;}else if(typeof(x)==='Boolean' ){obj[Boolean.prototype.toString.call(x)]=1;}
const a = {a: 1};const b = {b: 2};const obj={[a]:'valueA',[b]:'valueB'}console.log(obj);//{ '[object Object]': 'valueB' }
Array会用Array.prototype.toString转换
var myObject = {};var arr = ['1', 2, 'san'];myObject[arr] = 'arr';console.log(myObject);//{ '1,2,san': 'arr' }console.log(Object.prototype.toString.call(arr));//[object Array]console.log(Array.prototype.toString.call(arr));//1,2,san
getOwnPropertyDescriptor检测属性特征的方法
es5之前js并没有提供一个直接检测属性特征的方法,比如检测一个属性是否是只读属性,是否可以遍历,这些属性在es5之前都没有
es5,属性描述符:可以理解成描述属性的键值对,属性:值,描述属性的对象
对象就是数据,方法也是数据,计算机一切都是数据,数据是,数据可以描述东西的
let obj={a:2};console.log(Object.prototype);

getOwnPropertyDescriptor使用
Object.getOwnPropertyDescriptor(obj需要检测的对象 , ‘a‘对象中需要检测的属性) 查询obj中的a属性的特征
Object.getOwnPropertyDescriptor(obj,’a’)
参数一obj需要检测的对象
参数二’a’对象中需要检测的属性
return返回一个对象,对象里面有一系列数据,关于那个属性特征的数据,返回关于那个属性的描述符对象
用途:查询对象中的属性的描述符,特征
let obj={a:2};// console.log(Object.prototype);console.log(Object.getOwnPropertyDescriptor(obj,'a'));

configurable:(可配置的),通过defineProperty添加一个新的属性,或者修改一个已有属性
enumerable:(可枚举)
writable:(可写)
value:(值)
defineProperty给对象定义属性
是给对象定义属性的,配置修改的是属性,不是对象
Object.defineProperty(obj查询的对象, ‘a‘查询的属性,{描述符})
用途:通过obj、a查到属性,再通过对象(描述符),修改对象属性的特征
let obj = {};Object.defineProperty(obj, 'a',{value :2,enumerable : true,writable : true,configurable : true})console.log(obj);//{a:2}
let obj = {};Object.defineProperty(obj, 'a', {value: 2,enumerable: true,writable: true,configurable: true})console.log(obj);//{a:2}console.log(Object.getOwnPropertyDescriptor(obj, 'a'));
writable:(可写)设置为false,设置的属性不可以更改值
let obj = {};Object.defineProperty(obj, 'a', {value: 2,enumerable: true,/*设置为false,不可以更改*/writable: false,configurable: true})obj.a=3;/*es6在这里采取静默失败的策略,silenty field,属性没有生效,没有报错。* 偷偷不执行这条语句*/console.log(obj.a);//2
严格模式下报错
"use strict";let obj = {};Object.defineProperty(obj, 'a', {value: 2,enumerable: true,/*设置为false,不可以更改*/writable: false,configurable: true})obj.a=3;//Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>'/*es6在这里采取静默失败的策略,silenty field,属性没有生效,没有报错。* 偷偷不执行这条语句* 用严格模式use strict会报错*/console.log(obj.a);
但可以删除,虽然可以修改
// "use strict";let obj = {};Object.defineProperty(obj, 'a', {value: 2,enumerable: true,/*设置为false,不可以更改,但可以删除,严格模式下删除也不报错*/writable: false,configurable: true})console.log(obj);//{a: 2}delete obj.a;console.log(obj.a);//undefinedconsole.log(obj);//{}
configurable:(可配置的)设置为false,设置的属性不可删除
// "use strict";let obj = {};Object.defineProperty(obj, 'a', {value: 2,enumerable: true,writable: true,/*configurable设置为false就不能删除了,configurable:false,不能删除;* 但可以修改,writable设置为true,可以修改,*/configurable: false})obj.a = 3;console.log(obj);//{a: 3}delete obj.a;console.log(obj.a);//3console.log(obj);//{a: 3}
getter,setter
1h19m
get操作,put操作
也是属性描述符,与writeable等一样,虽然打印只显示4个,但有没有显示的内容,比如getter等也是存在的
let obj={a:1};obj.a;//[[Get]]操作/*** 当我们进行obj.a的时候,js引擎其实会通过[[Get]]来获取,*属性的获取,[[Get]]没有特定设置,执行默认操作:查找当前属性如果没有,查找原型,* */obj.a=3;/*** 赋值操作[Put],[Put]默认操作,* 1.getter;setter;* 2.writable:false,不让你改:* 3.赋值:** time 1h27m35s* 1看操作是否是getter、setter 2是否可写 3赋值*/
getter setter
getter、setter改写获取属性的方式、设置属性的方式,
get方式重写了当前的获取属性的默认方式
var obj={log:['example','test'],get latest(){if (this.log.length===0) {return undefined;}return this.log[this.log.length-1];}}console.log(obj.latest);//test/*通过get方式重写了当前的获取属性的默认方式,obj.latest不再是之前原本的obj.a的方式来执行的,* 它访问值的方式是通过get的方式来定义的*/
var obj={log:['example','test'],/*** get latest()不是一个方法,而是一个属性,一个值,所以需要return返回一个值,* 其实latest()本质上是一个方法,因为有get 所以必须有返回值,* obj.latest是得到obj里面latest里面的值,本来会走[[Get]]的默认操作的,但我* 通过get方式重写了获取属性的默认方式,现在获取latest属性值的方式是执行latest这个方法,* 并把方法的返回值作为latest的属性值,而不是找有没有叫latest的属性,并获取它的值* @returns {string|undefined}*/get latest(){if (this.log.length===0) {return undefined;}return this.log[this.log.length-1];},latest1(){if (this.log.length===0) {return undefined;}return this.log[this.log.length-1];}}// console.log(obj.log)console.log(obj.latest);//testconsole.log(obj.latest1());//test/*通过get方式重写了当前的获取属性的默认方式,obj.latest不再是之前原本的obj.a的方式来执行的,* 它访问值的方式是通过get的方式来定义的*/
var obj={log:['example','test'],get latest(){if (this.log.length===0) {return undefined;}return this.log[this.log.length-1];},latest1(){if (this.log.length===0) {return undefined;}return this.log[this.log.length-1];}}console.log(obj.latest);//testconsole.log(obj.latest1());//test/*通过get方式重写了当前的获取属性的默认方式,obj.latest不再是之前原本的obj.a的方式来执行的,* 它访问值的方式是通过get的方式来定义的*/
time 1h38m
var myObject = {get a() {return 2;}}Object.defineProperty(myObject, 'b', {/*get与enumerable等都是可描述属性,只不过赋值需要给它赋值方法function,*/get: function () {// return this.a (2);return this.a * 2;},enumerable: true,/* value:6,writable : true*//*都会报错,因为get已经有值了,已经是赋值语句,就不能在下面再给值了* value、writeable这俩是不让用的,与get方式矛盾,起冲突* configuable、enumerable可以用*/})console.log(myObject.a);//2 执行a()方法,return2,作为a的返回值console.log(myObject.b);//4
time 1h46m
value与get冲突,不能都写
get、set可描述属性与value、writable属性不能同时存在
var myObject = {get a() {return 2;}}Object.defineProperty(myObject, 'b', {get: function () {// return this.a (2);return this.a * 2;},enumerable: true,/* value:6,writable : true*//*都会报错,因为get已经有值了,已经是赋值语句,就不能在下面再给值了* value、writeable这俩是不让用的,与get方式矛盾,起冲突* configuable、enumerable可以用*/})console.log(myObject.a);//2console.log(myObject.b);//4

time 1h51m
set设置,必须给它一个值才能set,所以必须加参数,所有set都必须要有参数
var language = {set current() {},log: []}

time 1h53m
var language = {set current(name) {this.log.push(name);},log: []}language.current = 'EN';console.log(language.log);//['EN']
分析
var language = {set current(name) {this.log.push(name);},log: []}/*** 打印undefined,说明language.current = 'EN';不是给current这个属性赋值了,* 不是默认的set操作了,而是执行current方法,current('EN'),把=的EN作为参数传过去,* 执行方法,=号也不是默认的赋值操作了,而是传参,类似于传参,传了EN作为参数,* 传参需要先指定是哪个方法,language.current找到是哪个方法,找到哪个方法并传参并执行,* 执行了方法,所以log有值了*/language.current = 'EN';console.log(language.current);//undefinedconsole.log(language.log);//['EN']
var language = {set current(name) {this.log.push(name);},log: []}language.current = 'EN';language.current = 'FA';console.log(language.log);//['EN', 'FA']console.log(language.current);//undefinedconsole.log(language.current = 'TE');//TEconsole.log(language.current);//undefinedconsole.log(language.log);//['EN', 'FA', 'TE']
var language = {set current(name) {this.log.push(name);},current1(name) {this.log.push(name);},log: []}language.current = 'EN';language.current = 'FA';console.log(language.log);//['EN', 'FA']console.log(language.current);//undefinedconsole.log(language.current = 'TE');//TE/* language.current = 'EN'不是之前的赋值语句了,而是执行set current函数=“FA”,* 就是current("FA")*/console.log(language.current);//undefinedconsole.log(language.log);//['EN', 'FA', 'TE']
time 1h55m
obj.a=3;进行了赋值操作,我赋值再取值,obj.a还是走get a方法,返回2,值是不会改变的
var obj={get a(){return 2;}}obj.a=3;console.log(obj.a);//2/*并不能等于3,一般有get属性,也得需要set属性,要不只能取值不能赋值,没有意义* 一般get、set都是成对出现的*/
time 1h56m27s
所以我需要get、set方法同时使用
get返回值不能写死,如果get就返回2,就永远取值时走get方法得到2
a属性的get方法、set方法
var obj={get a(){return 2;},set a(val){// return this.a*2;//3return val*2;//3}}console.log(obj.a=3);//3console.log(obj.a);//2
time 2h
var obj={get a(){// return 2;return this._a;},set a(val){// return this.a*2;//3// return val*2;//3this._a=val*2;}}console.log(obj.a=3);//3console.log(obj.a);//6
这个是get、set比较基本的用法,这个之后去练习
var obj={get a(){// return 2;return this._a;},set a(val){// return this.a*2;//3// return val*2;//3this._a=val*2;}}/*** 赋值,走a的set方法,this._a=3*2=6*/console.log(obj.a=3);//3/*** 取值,走a的get方法,return this._a,return 6,结果是6*/console.log(obj.a);//6
time 2h2m
getter、setter操作,覆盖了原本的[[Get]]、[[Put]]操作
