.声明
查看以下代码,并回答输出的内容(以及原因)。
// situation 1 console.log(person); var person='John'; // situation 2 console.log(person); let person='Phill'; // situation 3 console.log(person); const person='Frank'; // situation 4 const person='Vanessa'; console.log(person); person='Mike'; console.log(person); // situation 5 var person='John'; let person='Mike'; console.log(person); // situation 6 var person='John'; if (person) { let person='Mike'; console.log(person); } console.log(person);
说明
Situation 1: 预期结果是在控制台中看到文本 John,但是令人惊讶的是,我们看到记录了undefined。想知道为什么吗?
好吧,这是经典的 JavaScript 在起作用。这种行为被称为提升。在后台,该语言将变量声明和值分配分为两部分。不管变量最初由开发人员在哪里声明,变量都将移动到顶部,声明时将其值设置为 undefined。看起来像这样:
var person; console.log(person); person='John';
Situation 2: 在这里,结果将是引用错误。
Uncaught ReferenceError: Cannot access 'person' before initialization
错误文本说明了一切。因为我们使用了关键字 let,所以我们的变量被提升,但没有初始化,并且抛出该错误,通知我们正在尝试访问未初始化的变量。在 ES6 中引入了关键字 let,使我们能够使用块作用域中的变量,从而帮助我们防止意外行为。
在这里,我们会得到与 Situation 2 中相同的错误。
不同之处在于我们使用了关键字 const,从而防止在初始化后重新分配变量。 ES6 中也引入了此关键字。
Situation 4: 在这种情况下,我们可以看到关键字 const 是如何工作的,以及它如何避免无意中重新分配变量。在我们的示例中,首先会在控制台中看到 Vanessa,然后是一个类型错误。
Uncaught TypeError: Assignment to constant variable
const 变量的使用随着我们的代码库呈指数增长。
Situation 5: 如果已经在某个作用域内使用关键字 var 定义了变量,则在同一作用域中用关键字 let 再次声明该变量将会引发错误。
因此,在我们的示例中,将不会输出任何内容,并且会看到语法错误提示。
Uncaught SyntaxError: Identifier 'person' has already been declared
Situation 6: 我们分别有一个函数作用域的变量,和块作用域的变量。在这种情况下,它们是否有相同的名字或标识符并不重要。
在控制台中,我们应该看到 Mike 和 John 被依次输出。为什么?
因为关键字 let 为我们提供了块作用域内的变量,这意味着它们仅存在于自己创建的作用域内,在这种情况下,位于if...else 语句中。内部变量优先于外部变量,这就是为什么我们可以使用相同标识符的原因。
2.继承
考虑以下类,并尝试回答输出了什么以及为什么。
class Person { constructor() { this.sayHello=()=> { return 'Hello'; } } sayBye() { return 'Bye'; } } class Student extends Person { sayHello() { return 'Hello from Student'; } } const student=new Student(); console.log(student.sayHello());
说明
如果你的答案是 Hello,那是对的!
为什么:每次我们创建一个新的 Student 实例时,都会将 sayHello 属性设置为是一个函数,并返回字符串 Hello。这是在父类(Person)类的构造函数中发生的。
在 JavaScript 中,类是语法糖,在我们的例子中,在原型链上定义了 Student 类中的 sayHello 方法。考虑到每次我们创建 Student 类的实例时,都会将 sayHello 属性设置为该实例,使其成为返回字符串 Hello 的 function,因此我们永远不会使用原型链上定义的函数,也就永远不会看到消息 Hello from Student 。
3.对象可变性
思考以下情况中每个部分的输出:
// situation 1 const user={ name: 'John', surname: 'Doe' } user={ name: 'Mike' } console.log(user); // situation 2 const user={ name: 'John', surname: 'Doe' } user.name='Mike'; console.log(user.name); // situation 3 const user={ name: 'John', surname: 'Doe' } const anotherUser=user; anotherUser.name='Mike'; console.log(user.name); // situation 4 const user={ name: 'John', surname: 'Doe', address: { street: 'My Street' } } Object.freeze(user); user.name='Mike'; user.address.street='My Different Street'; console.log(user.name); console.log(user.address.street);
说明
Situation 1: 正如我们在上一节中所了解的,我们试图重新分配不允许使用的 const 变量,所以将会得到类型错误。
控制台中的结果将显示以下文本:
Uncaught TypeError: Assignment to constant variable
Situation 2: 在这种情况下,即使我们改用关键字 const 声明的变量,也会有不同的行为。不同之处在于我们正在修改对象属性而不是其引用,这在 const 对象变量中是允许的。
控制台中的结果应为单词 Mike。
Situation 3: 通过将 user 分配给 anotherUser 变量,可以在它们之间共享引用或存储位置(如果你愿意)。换句话说,它们两个都会指向内存中的同一个对象,因所以更改一个对象的属性将反映另一个对象的更改。
控制台中的结果应为 Mike。
Situation 4: 在这里,我们使用 Object.freeze 方法来提供先前场景(Situation 3)所缺乏的功能。通过这个方法,我们可以“冻结”对象,从而不允许修改它的属性值。但是有一个问题!它只会进行浅冻结,这意味着它不会保护深层属性的更新。这就是为什么我们能够对 street 属性进行更改,而 name 属性保持不变的原因。
控制台中的输出依次为 John 和 My Different Street 。
4.箭头函数
运行以下代码段后,将会输出什么以及原因:
const student={ school: 'My School', fullName: 'John Doe', printName: ()=> { console.log(this.fullName); }, printSchool: function () { console.log(this.school); } }; student.printName(); student.printSchool();
说明
控制台中的输出将依次为 undefined 和 My School。
你可能会熟悉以下语法:
var me=this; // or var self=this; // ... // ... // somewhere deep... // me.doSomething();
你可以把 me 或 self 变量视为父作用域,该作用域可用于在其中创建的每个嵌套函数。
当使用箭头函数时,这会自动完成,我们不再需要存储 this 引用来访问代码中更深的地方。箭头函数不绑定自己,而是从父作用域继承一个箭头函数,这就是为什么在调用 printName 函数后输出了 undefined 的原因。
5.解构
请查看下面的销毁信息,并回答将要输出的内容。给定的语法是否允许,否则会引发错误?
const rawUser={ name: 'John', surname: 'Doe', email: 'john@doe.com', displayName: 'SuperCoolJohn', joined: '2016-05-05', image: 'path-to-the-image', followers: 45 } let user={}, userDetails={}; ({ name: user.name, surname: user.surname, ...userDetails }=rawUser); console.log(user); console.log(userDetails);
说明
尽管有点开箱即用,但是上面的语法是允许的,并且不会引发错误! 很整洁吧?
上面的语法功能强大,使我们能够轻松地将任何对象分成两个更具体的对象,上面的示例在控制台的输出为:
// {name: "John", surname: "Doe"} // {email: "john@doe.com", displayName: "SuperCoolJohn", joined: "2016-05-05", image: "path-to-the-image", followers: 45}
6.异步/等待
调用以下函数后将输出什么?
(async ()=> { let result='Some Data'; let promise=new Promise((resolve, reject)=> { setTimeout(()=> resolve('Some data retrieved from the server'), 2000); }); result=await promise; console.log(result); })();
说明
如果你认为是两秒钟后输出 Some data retrieved from the server ,那么你是对的!
代码将会暂停,直到 promise 得到解决。两秒钟后,它将继续执行并输出给定的文本。这意味着 JavaScript 引擎实际上会等到异步操作完成。可以说 async/await 是用来获得 promise 结果的语法糖。也有人认为它是比 promise.then 更具可读性的方式。
7. Return 语句
const multiplyByTwo=(x)=> { return { result: x * 2 }; } console.log(multiplyByTwo(2));
说明
如果你的答案是 {result: 4},那你就错了。输出是 undefined。但是不要对自己太苛刻,考虑到我也写 C# 代码,这也曾经困扰着我,这在 C# 那儿不是个问题。
由于自动分号插入的原因,上面的代码将返回 undefined。 return 关键字和表达式之间不允许使用行结束符
解决方案是用以下列方式之一去修复这个函数:
要实现一个面部识别的功能究竟该怎么做?在本文中,我们将以 JavaScript 库 pico.js 为依托,手把手教你如何为一款应用添加面部检测功能。
作者 | Jonathan Freeman
译者 | 弯月,责编 | 屠敏
出品 | CSDN(ID:CSDNnews)
以下为译文:
在本文中,我们将使用pico.js添加简单的面部检测。Pico.js是一个很小的JavaScript库,目前它还是一个近似于概念验证的库,还不能用于生产环境,但在我研究过的人脸检测库中,Pico.js的效果最佳。
本文的目标首先是在地图上通过一个红点显示用户的头部位置:
首先,我们创建一个包含pico.js功能的简单React类,然后用它来获取用户脸部的位置:
<ReactPico onFaceFound={(face)=> {this.setState({face})}} />
接下来,如果检测到面部,我们就使用其位置信息来渲染组件:
{face && <FaceIndicator x={face.totalX} y={face.totalY} />}
我们在使用pico.js时所面临的第一个难题是,它是JavaScript的研究项目的实现,不一定是遵循现代JavaScript标准的面向生产环境的库。除此之外,你还不能直接使用yarn add picojs。虽然pico.js的入门教程是一个很好的入门级别的对象检测,但这个教程更像是一篇研究论文而不像API文档。但是,其中提供的示例足够代码使用。我花了几个小时将该教程提供的样本代码放入了一个相对简单的React类中。
pico.js需要做的第一件事就是加载级联模型,该模型会进行一个AJAX调用,而这个调用会引入预先训练好的模型的二进制文件。(你也可以使用pico.js来检测其他类型的对象,但你需要使用官方的pico实现来自己训练模型。)我们可以在componentDidMount方法中加载模型。为了清楚起见,我进一步将示例代码抽象为另一个名为loadFaceFinder的方法:
componentDidMount {
this.loadFaceFinder;
}
loadFaceFinder {
const cascadeurl='https://raw.githubusercontent.com/nenadmarkus/pico/c2e81f9d23cc11d1a612fd21e4f9de0921a5d0d9/rnt/cascades/facefinder';
fetch(cascadeurl).then((response)=> {
response.arrayBuffer.then((buffer)=> {
var bytes=new Int8Array(buffer);
this.setState({
faceFinder: pico.unpack_cascade(bytes)
});
new camvas(this.canvasRef.current.getContext('2d'), this.processVideo);
});
});
}
除了获取和解析人脸检测模型的二进制文件并设置到state中之外,我们还创建了一个新的camvas,它引用了<canvas>上下文和一个回调处理程序。camvas库从用户的网络摄像头将视频加载到canvas上,并针对渲染的每一帧调用处理程序。loadFaceFinder的代码几乎与pico.js提供的参考项目相同。我们只是更改了存储模型的位置,以便可以利用state访问,我们通过React的Ref(而不是使用浏览器提供的DOM API)来引用我们的canvas上下文。
我们的this.processVideo也几乎与参考项目中提供的代码相同。我们只需要稍微做一些改动。我们希望只在加载模型时执行代码,因此我们在代码的整个主体外又添加一个检查。我还用我们希望用户传入的回调处理程序创建了这个React类,因此只有在定义了该处理程序时,才会运行处理代码:
processVideo=(video, dt)=> {
if(this.state.faceFinder && this.props.onFaceFound) {
/* all the code */
}
}
我只改动了一个地方:在检测到面部时作何处理。pico.js示例在canvas绘制了一些圆圈,但我们希望将数据传递回我们的回调处理程序。让我们稍微修改一下代码, 以方便我们的回调处理程序更容易地处理这些值:
this.props.onFaceFound({
x: 640 - dets[i][1],
y: dets[i][0],
radius: dets[i][2],
xRatio: (640 - dets[i][1]) / 640,
yRatio: dets[i][0] / 480,
totalX: (640 - dets[i][1]) / 640 * window.innerWidth,
totalY: dets[i][0] / 480 * window.innerHeight,
});
这种格式允许我们传回在捕获到的canvas元素中面部的绝对位置和半径,面部相对于canvas元素的相对位置,以及面部相对于canvas元素的位置映射到整个页面后的位置。到这里我们自定义的类就基本完成了。接下来,我还需要对pico.js和pico版本的camvas.js进行一些小改动才能使用现代语法,但这些只是关键字的变化,不涉及逻辑关系。
现在,我们可以将我们的自定义ReactPico类导入到我们的应用程序中,渲染,并在我们检测到面部时有条件地渲染FaceIndicator类。在尝试了其他一些人脸检测库之后,我很惊喜地发现pico.js的准确性和可用性非常高,尽管它还不是一个完全成熟的库。
原文:https://www.infoworld.com/article/3403019/javascript-tutorial-add-face-detection-to-your-web-app.html
本文为 CSDN 翻译,转载请注明来源出处。
【End】
软欲将Edge打造成为全球最佳的网页浏览器,将Edge塑造成为高速、安全、低资源占用和长续航表现的典范。继此前表明Edge在续航方面的卓越表现之后在今天发布的博文中,公司再次表明在即将到来的Windows 10周年更新中将会为Edge和Chakra引擎带来一些JavaScript性能升级,在JavaScript性能上要比Chrome、Firefox等竞争对手快很多。
在这篇博文中最为有趣的的部分就是微软张贴的JavaScript跑分结果中,微软Edge浏览器在Octane和JetStream测试中要优于Google Chrome Canary和Firefox Alpha版本。
在Octane 2.0跑分中Edge浏览器的成绩为31187,Chrome Canary的成绩为25910,Firefox Alpha的成绩为24836(分数越高越好)。在JetStream 1.1版本中,Edge执行成绩作为优秀获得233.7点,随后是Chrome获得168.3点,Firefox获得146.6点(同样越高越好)。
微软表示:“我们非常激动的向你分享我们在内存脚本和启动时间上的性能改进。然而这条通往更优秀性能的道路从未走到尽头,我们将竭尽所能的让JavaScript变得更快。在今年夏季发布的更新中我们将会持续在这个方面进行改善。”
*请认真填写需求信息,我们会在24小时内与您取得联系。